ChromeAngel / ModMaker

Utility to help with mod development using the Source game engine
Other
7 stars 0 forks source link

FGD files: "correctly" handling base() class shadowing. #1

Open TeamSpen210 opened 6 years ago

TeamSpen210 commented 6 years ago

Valve's parser for FGD files is implemented in a rather simplistic way, which means it'll produce different results than yours when run with certain base() classes. I ran into this issue when writing my own FGD library (Python, here). The problem is that when reading in base entries, the names are immediately up at that point and all data is copied into the current entity. There's also no check for overwriting a name later. This means, that the following code will put the first info_base class into the entity, but display the second in the class list:

@PointClass base(Targetname) = info_base : "This gets included"
[
]

@PointClass base(info_base) = info_child : "Includes above, not below"
[
]

@PointClass = info_base : "Hides above definition, but isn't used by info_child"
[
]

This works even if you have an entity overriding itself (@XClass base(name) = name). My solution was to lookup and save a reference to the bases when parsing through the base() line of code, so I keep a reference to it even if it's overwritten later.

You'll also need to deal with this when writing back to the FGD file. There it's a bit more difficult - you'll want to deduplicate names when they overwrite others, and do a topological sort so you can ensure the base classes appear before parents. Either that, or record the original order and always output in that order exactly.

ChromeAngel commented 6 years ago

Thanks for the insight @TeamSpen210 , I will have look into it. It never occurred to me that anyone would redefine an entity with the same name as an existing entity. Do you think this is an intentional design decision?

TeamSpen210 commented 6 years ago

I doubt it, moreso something that just makes the code simpler. You can just rearrange the FGD file to fix any issues, and it doesn't really need to be that robust. Additionally, writing it in raw C/C++ means there's a lot of low-level detail involved in doing operations.