It looks like you're new here. If you want to get involved, click one of these buttons!
Hi, everyone! I've been playing with ORX for some time and I'm quite fond of the data-driven design and how the low-level code is arranged. The config system has many merits. It's very powerful and flexible. However, I found that robustness and scalability is less desirable. Actually I've stumbled on quite a few problems when trying to run the outdated examples on github. In these cases, The deprecated C API can be easily noticed when typing "make", but the config part is quite the opposite. For example, in some examples the "Position" entry is set to "top right" or something alike which is no longer supported, but the engine don't complain. Same problem can be experienced when an entry is mistyped or no longer supported. Let along the lack of transparence for the parsing process.
These are just a few aspects of the problem. ORX's config system is too free for non-trivial games where there could be thousands of sections weaving upon each other. If one mistyped just one word in a complicating config system, it would be a pain in the ass to find it out. More so if commands are abusively used in the config system, but I guess that would be another topic. I wonder if anyone feels the same about this, because I feel that even a tiny improvement can do me a lot of good given the current situation.
The engine and the config system are simple and effective and I think we would all like to keep it that way. So the task would be how to improve the robustness and scalability without introducing too much complicity. In my opinion, given that ORX is a data-driven engine, the responsibility of the config system is to correctly organize the data so that the engine can parse them as the user expected or throw errors if otherwise (while runtime variables and game logics should be kept in the code). To achieve this, we would need to set some rules for the data format.
For now, I've got some simple ideas but they might not be very complete at this moment.
First of all, enhancement of explicity.
1) Typed sections
ORX uses config section of free forms to create objects and structures. The engine does not know what a section represents until it is used to create structures. I think that maybe we can give a hint to the engine so that it can know what a section really is and perform checks. For example, we can write the title of a section like this:
So that the engine would know that this section is a definition of an object. This way, the engine can throw a warning when a section name of incorrect type appears in where it shouldn't be. This done, the check of entries become possible. For when the type of a section is determined, the engine can query its type to get a list of internal entry names and restrictions on the values (these infomation should be registered on the init of the config module). This way the engine can throw a warning or an error when a neccessary entry is missing or a value is invalid.
2) Distinguish internal entries from external entries
Let's call the hardcoded entries as "internal entry" and the ones defined in the config files as "external entry". To make the data format even stricter, we can provide a way to explicitly specify an internal entry name for use in both assignment and reference. We might want this because sometimes missing an internal entry is not noticeable. To implement this, we can allow the user to choose to prefix an internal entry name with '~' when an internal entry is wanted, or to set a rule that the first letter must be uppercase for internal entry and lowercase for external entry. Actually I personally prefer the latter one for it doesn't need to define more symbols and can completely divide entries into two types. So it would be like this:
; Explicitly declaring HeroGraphic as a Graphic section
; Assigning an internal entry (start with uppercase letter)
Texture = hero.png
; Inheriting a section makes it has both its original type and the type of the inherited section
; In this case maybe we can allow omitting the type of HeroGraphic1 and default it to parent section's type.
TextureSize = (64, 64)
TextureOrigin = (64, 0)
Graphic = HeroGraphic1
; Defining & assigning an external entry (start with lowercase letter)
health = 100
This way, any typo or invalid assignment can be discovered at parsing phase (of course this does not apply when a value is a command string).
3) Redefinition of a section throws a warning
Currently, redefining a section defaults to extending the original one. I think it would be more helpful to have it the other way round. That is to say, the engine should throw a warning and wipe the old entries if a section is defined twice without a '+' prefix.
4) Handle collision flags and groups more safely
Typos in collision flags are hard to find out because collision flags are defined on a object section's instancing. Maybe we can have a special section to register all collision flags before using them. The same applies to group names as well. For now, one can mitigate these problems by using data inheritance. For collision flags there is one more thing to be addressed. Collision event might not be emitted if collision flags are not used in pairs. Collision pairs should also be pre-registered to ensure there's no broken pairs. It will look like this
Flags = hero # monster # wall # bullet
; Define collision pairs. All flags must be pre-defined in 'Flags' entry
; (hero <-> monster) and (hero <-> wall)
hero = monster # wall
; (bullet <-> monster) and (monster <-> wall)
monster = bullet # wall
; If there are flags not included in pairs, throw a warning
5) Settings sections are special
Forbid the definition of new (external) entries for settings sections. Forbid type hinting too. So this
ScrollSize = 1000
abc = 1
should result in errors. This way it doesn't change anything for using it but ensures nothing unexpected would happen when a special settings section is misused as a normal one.
Secondly, enhancement of section prototype design.
1) Section entries should be carefully designed so that coupling between the effects of different entries is diminished to an extreme extent. I propose this because I once encoutered confliction between different entries (although I can't recall exactly which section type and which entries).
2) If confliction can't be avoided, then the engine should check the potentially conflicting entries and their values and throw a warning if neccessary.
Thirdly, data scope.
Currently all sections are referenced by one linked list which allows no means to separate them. Maybe it would nice to have scopes in config systems just as in common programming languages. I'm not quite sure yet.
So, this is it. I would love to hear from the developers and other users. I haven't touch the code yet but would be happy to if this proposal sounds acceptable.