func-godot / func_godot_plugin

Quake .map support for Godot 4.2
MIT License
266 stars 17 forks source link

allow set name prefixes for entities, tb layers and tb groups #34

Open azur-wolf opened 1 week ago

azur-wolf commented 1 week ago

Allow to set the prefixes for entities, tb layers and tb groups expose them on the FuncGodotMapSettings

by default the ones that are currently used

when having groups inside groups a lot of workarounds needed to set their names with a custom convention

can't access names of tb layers and groups like fgd properties i guess

to set them to the exact name set on TB just should leave it empty

RhapsodyInGeek commented 1 week ago

Not sure why you have to find workarounds to getting the entity, group, and layer names. There's a specific set of simple rules they follow, though it's not a simple prefix addition.

This is the code in resolve_trenchbroom_group_hierarchy() that handles Group and Layer naming:

# identify parents
        if '_tb_id' in properties:
            node.set_meta("_tb_type", properties['_tb_type'])
            if properties['_tb_type'] == "_tb_group":
                node.name = "group_" + str(properties['_tb_id'])
            elif properties['_tb_type'] == "_tb_layer":
                node.name = "layer_" + str(properties['_tb_layer_sort_index'])
            if properties['_tb_name'] != "Unnamed":
                node.name = node.name + "_" + properties['_tb_name']
            parent_entities[node_idx] = node

It's easy enough to rename entities, as there are multiple ways to do it, both in script and through properties (see entity_name_property in the Map Settings resource). And since groups and layers follow set naming patterns, it isn't really difficult to find them in the scene tree, either.

One complication with trying to set group and layer names is that they're not actually defined in an FGD, so the only information we get are the meta properties that TrenchBroom adds. Beyond that, they're just simple Node3Ds for positioning and parenting purposes with some meta data attached.

Another complication is entity name duplication. The current setup was decided because it made sure that every layer name and group name would have the highest odds of remaining unique, aside from some edge cases.

Something worth mentioning: entities in groups do receive extra meta data properties, which do get sent to the entity on build through both func_godot_properties and _func_godot_apply_properties().

// entity 15
{
"classname" "func_group"
"_tb_type" "_tb_group"
"_tb_name" "startcave"
"_tb_id" "2"
"_tb_linked_group_id" "{b8c9a0a4-d80b-4ed4-b3f5-45ede6bba290}"
"_tb_transformation" "1 0 0 -32 0 1 0 -336 0 0 1 0 0 0 0 1"
}
// entity 16
{
"classname" "func_detail"
"_tb_group" "2"
// brush 0
{

You can also get layer information this way, too. These meta properties are what we use to sort entities into groups into layers. You can use them to also identify groups and layers in script.

I don't consider using entity properties along with anticipating the group and layer naming conventions to be workarounds personally. Maybe you do. But all you need to find entities, groups, and layers is already there.

azur-wolf commented 1 week ago

would want be able to turn TB layers and groups into fgd entity nodes

RhapsodyInGeek commented 1 week ago

There's no point. TB Groups and TB layers can't have their properties modified in TrenchBroom, other than their name. Even their _tb_id is hidden, automatically assigned by the editor. We also very intentionally chose not to incorporate func_group, which isn't the same as a TB Group, despite TB Groups and TB Layers being listed in map files as func_groups. We won't be changing the design to view TB layers and TB groups as full fledged entities. Users can try to extend that functionality on their own if they'd like, but it won't come as part of the FuncGodot download.

They are already full fledged nodes once built though, as they all are represented as Node3Ds.

azur-wolf commented 1 week ago

because my level design approach uses hierarchies that aren't possible in TB, because can't have a func be inside another func . also cant have subrgroups on different layers than its parent group

and TB doesnt allow to apply properties to layers, so its even harder to have such hierarchies

something like that:

the entities are just entities independent on hierarchies but the first 3 are types that arrange the scenario structure cant be entities on tb because can't follow such structure for good mapping workflow those should be arranged within the level editor so that forces to either have a messy logic on map build to parent all those entities to the correct hierachical structure or let those that arrange the overall structure be groups/layers (without properties) and use whatever workaround to set those on map build

maybe with those meta properties and tb_<whatever> can do some of that

i only see a tb_group on the properties, no tb_name, tb_id, etc

but as you said then that must be done with custom logic

RhapsodyInGeek commented 1 week ago

The way that TrenchBroom defines a TB Layer in a map file is by making it a func_group with a _tb_type property set to layer. Their _tb_id is assigned based upon the Layer Order in the editor. If a Layer is deleted the IDs for other layers are changed to reflect the new order.

TB Groups are defined as func_group with a _tb_type property set to group. Their _tb_id is assigned upon creation as the next available ID number starting from 1. When a group with an ID is a deleted, the IDs of other groups are not affected.

Entities that are placed in a non Default Layer get a hidden _tb_layer property added to them not visible in the editor but visible in the map file if you view it through a text editor. The _tb_layer entity property corresponds with a Layer's _tb_id.

Entities that are added to a TB Group get a hidden _tb_group property added to them, also not visible in the editor. The _tb_group entity property corresponds to a Groups' _tb_id.

In any case, what you're trying to do would just end up being:

The only real "wildcards" here are the group numbers, because those are determined by the order they're created, but we chose not to use just the name because you can easily and likely will have multiple groups with the same name, so they'd get numbered anyway. But, if you need to access a group in GDScript by name, you can easily just do a String.find() within the children of the layer of the map node of each child's name.

for layer in FuncGodotMap.get_children():
    if layer is Node3D:
        for group in layer.get_children():
            if group.name.find("section_a1", 8) > -1: #we can start our search at 8 because 8 characters are the minimum used for the prefix
                do_something()

It's really easy, and you can expand that simple logic to look for groups that are marked with specific prefixes. You can do it with layers as well, although as said before, layer naming conventions are extremely predictable.