minetest-mods / streets

Urban roadbuilding for Minetest! A collaborative mod by webD97, cheapie and Thomas-S
Other
22 stars 17 forks source link

Signs API #100

Open Thomas--S opened 6 years ago

Thomas--S commented 6 years ago

I suggest the following API for signs:

Please notice: additional fields will be added to the definition tables during development as needed.

Updated version (2018-03-06 17:49 UTC)

streets.signs.register_collection()

streets.signs.register_collection({
    name = "minetest",
    description = "Minetest-style Signs",
    info = "This signs are meant to be internationally understandable."
        .. "Blue signs are mandatory signs."
        .. "Yellow signs are danger signs."
        .. "White-red signs are prohibitory signs.",
})

Registered collections are stored in streets.signs.registered_collections. streets.signs.registered_collections is structured as follows:

streets.signs.registered_collections = {
    ["minetest"] = {
        name = "minetest",
        description = "Minetest-style Signs",
        info = "This signs are meant to be internationally understandable."
            .. "Blue signs are mandatory signs."
            .. "Yellow signs are danger signs."
            .. "White-red signs are prohibitory signs.",
    }
}

streets.signs.registered_collections must not be accessed directly. Use streets.signs.get_collection_definition(name) instead, which returns a copy of the definition or nil. name is the unique name of the collection, whose definition you want to get.

streets.signs.register_section()

streets.signs.register_section({
    name = "mandatory",
    description = "Mandatory",
    belongs_to = "minetest",
})

To avoid confusions use <collection name>:<section name> when referring to sections.

Registered sections are stored in streets.signs.registered_sections. streets.signs.registered_sections is structured as follows:

streets.signs.registered_sections = {
    ["minetest:mandatory"] = {
        name = "mandatory",
        description = "Mandatory",
        belongs_to = "minetest",
    }
}

streets.signs.registered_sections must not be accessed directly. Use streets.signs.get_section_definition(name) instead, which returns a copy of the definition or nil. name is the unique name of the section, whose definition you want to get. It must have the format <collection name>:<section name>.

You can get a table of sign definitions with streets.signs.get_section_definitions_by_collection(<collection name>).

streets.signs.register_sign()

streets.signs.register_sign({
    name = "straightonly",
    description = "Straight Only",
    belongs_to = "minetest:mandatory",
    -- all other fields used in minetest.register_node()
})

Registered signs are stored in streets.signs.registered_signs. streets.signs.registered_signs is structured as follows:

streets.signs.registered_signs = {
    ["minetest:mandatory:straightonly"] = {
        name = "straightonly",
        description = "Straight Only",
        belongs_to = "minetest:mandatory",
        -- all other fields used in minetest.register_node()
    }
}

streets.signs.registered_signs must not be accessed directly. Use streets.signs.get_sign_definition(name) instead, which returns a copy of the definition or nil. name is the unique name of the sign, whose definition you want to get. It must have the format <collection name>:<section name>:<sign name>.

You can get a table of sign definitions with streets.signs.get_sign_definitions_by_collection(<collection name>) and streets.signs.get_sign_definitions_by_section(<collection name>:<section name>).

Updated version (2018-03-06 13:22 UTC) ## Updated version (2018-03-06 13:22 UTC) ### `streets.signs.register_collection()` ```lua streets.signs.register_collection({ name = "minetest", description = "Minetest-style Signs", info = "This signs are meant to be internationally understandable." .. "Blue signs are mandatory signs." .. "Yellow signs are danger signs." .. "White-red signs are prohibitory signs.", }) ``` * `name` is an unique technical name for the collection. Allowed characters: `[a-zA-Z0-9-]` * `description` is a human-readable description of the collection. If left blank, it will be auto-generated from the `name` field. * `info` is a human-readable info text of the collection. This field is optional. Registered collections are stored in `streets.signs.registered_collections`. `streets.signs.registered_collections` is structured as follows: ```lua streets.signs.registered_collections = { ["minetest"] = { name = "minetest", description = "Minetest-style Signs", info = "This signs are meant to be internationally understandable." .. "Blue signs are mandatory signs." .. "Yellow signs are danger signs." .. "White-red signs are prohibitory signs.", } } ``` `streets.signs.registered_collections` must not be accessed directly. Use `streets.signs.get_collection_definition(name)` instead, which returns a copy of the definition or nil. `name` is the unique name of the collection, whose definition you want to get. ### `streets.signs.register_section()` ```lua streets.signs.register_section({ name = "mandatory", description = "Mandatory", belongs_to = "minetest", }) ``` * `name` is an unique technical name inside the collection for the section. Allowed characters: `[a-zA-Z0-9-]` * `description` is a human-readable description of the section. If left blank, it will be auto-generated from the `name` field. * `belongs_to` is the name of the collection this section belongs to. To avoid confusions use `:
` when referring to sections. Registered sections are stored in `streets.signs.registered_sections`. `streets.signs.registered_sections` is structured as follows: ```lua streets.signs.registered_sections = { ["minetest:mandatory"] = { name = "mandatory", description = "Mandatory", belongs_to = "minetest", } } ``` `streets.signs.registered_sections` must not be accessed directly. Use `streets.signs.get_section_definition(name)` instead, which returns a copy of the definition or nil. `name` is the unique name of the section, whose definition you want to get. It must have the format `:
`. ### `streets.signs.register_sign()` ```lua streets.signs.register_sign({ name = "straightonly", description = "Straight Only", belongs_to = "minetest:mandatory", -- all other fields used in minetest.register_node() }) ``` * `name` is an unique technical name inside the section for the sign. Allowed characters: `[a-zA-Z0-9-]` * `description` is a human-readable description of the sign. If left blank, it will be auto-generated from the `name` field. * `belongs` is the unique name of the section this sign belongs to. Use the form `:
`. Registered signs are stored in `streets.signs.registered_signs`. `streets.signs.registered_signs` is structured as follows: ```lua streets.signs.registered_signs = { ["minetest:mandatory:straightonly"] = { name = "straightonly", description = "Straight Only", belongs_to = "minetest:mandatory", -- all other fields used in minetest.register_node() } } ``` `streets.signs.registered_signs` must not be accessed directly. Use `streets.signs.get_sign_definition(name)` instead, which returns a copy of the definition or nil. `name` is the unique name of the sign, whose definition you want to get. It must have the format `:
:`.
Old version ## Old version ### `streets.signs.register_system()` ```lua streets.signs.register_system({ id = "minetest", name = "Minetest-style Signs", description = "This signs are meant to be internationally understandable." .. "Blue signs are mandatory signs." .. "Yellow signs are danger signs." .. "White-red signs are prohibitory signs.", }) ``` * `id` is an unique technical identifier for the system. Allowed characters: `[a-zA-Z0-9-]` * `name` is a human-readable name of the system. * `description` is a human-readable description of the system. Registered systems are stored in `streets.signs.registered_systems`. `streets.signs.registered_systems` is structured as follows: ```lua streets.signs.registered_systems = { minetest = { id = "minetest", name = "Minetest-style Signs", description = "This signs are meant to be internationally understandable." .. "Blue signs are mandatory signs." .. "Yellow signs are danger signs." .. "White-red signs are prohibitory signs.", } } ``` ### `streets.signs.register_section()` ```lua streets.signs.register_section({ id = "mandatory", name = "Mandatory", system = "minetest", }) ``` * `id` is an unique technical identifier inside the system for the section. Allowed characters: `[a-zA-Z0-9-]` * `name` is a human-readable name of the section. * `system` is the id of the system this section belongs to. To avoid confusions use `:
` when referring to sections. Registered sections are stored in `streets.signs.registered_sections`. `streets.signs.registered_sections` is structured as follows: ```lua streets.signs.registered_sections = { minetest = { mandatory = { id = "mandatory", name = "Mandatory", system = "minetest", } } } ``` ### `streets.signs.register_sign()` ```lua streets.signs.register_sign({ id = "straightonly", name = "Straight Only", system = "minetest", section = "mandatory", -- all other fields used in minetest.register_node() }) ``` * `id` is an unique technical identifier inside the section for the sign. Allowed characters: `[a-zA-Z0-9-]` * `name` is a human-readable name of the sign. * `system` is the id of the system this sign belongs to. * `section` is the id of the section this sign belongs to. Registered signs are stored in `streets.signs.registered_signs`. `streets.signs.registered_signs` is structured as follows: ```lua streets.signs.registered_signs = { minetest = { mandatory = { straightonly = { id = "straightonly", name = "Straight Only", system = "minetest", section = "mandatory", -- all other fields used in minetest.register_node() } } } } ```
webD97 commented 6 years ago

Sounds good so far, but I have a few suggestions for enhancements:

  1. IDs should be autogenerated by the API. It shouldn't be the concern of a developer/content-creator to avoid name-collisions. The ID could be generated out of the description and returned from the function for later use
  2. Avoid duplicated information: If a sign has a section which has a system, the sign shouldn't need to declare the system again
  3. Encapsulate the registration tables to secure them from manipulation after they have been registered. There should be helper functions that can return a copy of an element in such a table if it is required: streets.signs.get_sign_definition(), streets.signs.get_section_definition() etc.
  4. Flatten the registration tables and index the definitions by their id. If there are helper functions, there's no need to have multi-dimensional tables. I believe this could improve the table access performance.
Thomas--S commented 6 years ago

Thanks for your answser!

To 1) I think it would be good if the developer can define the id of the sign by himself. This id the developer also has to use when he refers to the sign in the code. He should be able to choose it freely. Avoiding name-collisions shouldn't be too much of a trouble either: The names must only be unique inside the section.

To 2) It is neccessary to refer to both, system and section. For example, there can be a section "mandatory" inside the "de" system and a section "mandatory" in the "us" system. If you want to shorten the definition, using <system id>:<section id> would be possible, too.

To 3 and 4) This sounds good :+1: I'll change my proposal accordingly soon.

webD97 commented 6 years ago

To 1: What I wanted to achieve is a simplification of the API. In my opinion, there shouldn't be a need to specify two strings, name and ID, which are quite similar. It's just another step to understand for content creators. I don't think it's their concern to create IDs following our conventions. Autogenerated IDs would also enforce these conventions. He/she (I'll abbreviate this to 'he') will most likely not care about whatever is inside the ID. If he needs to use the ID later on, he can use the ID the function would return. Another effect of this is that we will always have the control over these IDs. If we ever need to change their semantics in a later release, it's just a change in our own code, but not in the code the content creators.

To 2: My proposal makes more sense if the IDs are autogenerated because the autogenerated ID for a section could include the system ID, e.g. in the format you mentioned.

Edit: One more thing. I'm not quite happy with the term "system". I think it's not very "speaking". Maybe something like "collection" would be better?

Thomas--S commented 6 years ago

To 1) I still think we should separate ID and name in the API. Maybe I've chosen bad names, so that I have caused a misunderstanding: The ID is like the itemstring (e.g. default:dirt) in minetest and the name is like the description in the node definition. Maybe I should change the names accordingly.

I'll think about this problem in the next few days. I'll update my proposal accordingly then.

Changing the term "system" to "collection" is a good idea. I'll do this.

Thomas--S commented 6 years ago

I've addressed most of your comments in dc075087e7ca298c0be8e0c8456cf4f8915c5150.

It would be good, if you could review the updated proposal in the first post or in api.md (it's the same)

Here's a (possibly incomplete) list of the changes I did:

I'm looking forward to your comments!

Thomas--S commented 5 years ago

I suggest to use the following properties for all signs:

webD97 commented 5 years ago

Sounds reasonable

Thomas--S commented 5 years ago

A GIMP script for generating these images can be found at https://github.com/minetest-streets/streets/blob/02690a9814b68f05e91e565884ccceffe4b8f27c/streets_api/helpers/script-fu-streets-signs.scm#L1-L162

The suggested usage is as follows:

1) Find the image of the wanted sign. 2) Scale it with 250px equals 1m. 3) ln -s ~/.minetest/mods/streets/streets_api/helpers/script-fu-streets-signs.scm ~/.gimp-2.8/scripts/ 4) bash ~/.minetest/mods/streets/streets_api/helpers/streets-signs.sh <path to png> "<fixed colors>"

Example: bash ~/.minetest/mods/streets/streets_api/helpers/streets-signs.sh streets_signs_de__warning__work.png "#000000,#ffffff,#c1121c"

Please note: This script does not handle wrong user inputs! Use it with care!