Yeah, you named quite a few possible contradictions there.
If one DLL sets a return address, the breakpoint won't be called anymore, I think I've stated that sometime already, in my last post I forgot that.
The question is when does somebody actually need to set a return address?
Anyway, many things you're talking about I'm actually aware of, the return address, same action or other values, critical property changes. Of course not every DLL will be compatible to every other DLL,
like mods aren't always compatible to each other (UT2004 has exactly the same problems!).
Therefore it's pretty important for people to know what a DLL changes, if
it is designed to be compatible to others, which mines for example are to be.
To the first points:
DCoder Wrote:What if a DLL needs per-object variables like cBuilding::timesThisHasBeenCaptured ?
If one DLL accesses that very variable, it's stored in the game, not in that one DLL.
Once you changed it, it's changed for the other DLLs as well, unless it's declared in that DLL.
A problem is of course that one DLL can not access another DLL, unless that other DLL has export functions designed to communicate with others (I plan on doing this with mine).
DCoder Wrote:What if I want a crate that makes every single unit on the map cloaked for two minutes, and, naturally, not lose the actually cloakable units' cloak when uncloaking everything else afterwards? I imagine the callback on MyTimerExpired will need to iterate the units and reload their Cloakable status from the INI, meaning certain INI changes will work mid-game and potentially desync.
Every Techno (Vehicles, Infantry, Aircraft, Buildings) is linked to a TechnoType, which holds the "Cloakable" tag, thus is doesn't have to be reloaded. Also the veteran/elite abilities are accessible via TechnoTypes.
Most ingame classes have a corresponding type class.
Infantry (ingame) - InfantryType (INI)
Anim - AnimType
Terrain - TerrainType
The list goes on long.
The type classes can be referred to as templates for the ingame classes.
DCoder Wrote:What if I want a new AI Script Action/Trigger Event/Action ? [And two developers reuse the same Action number?]
In this case, I'll probably define callback function which return a boolean value, as in "handled" or "not handled".
If handled, it will set the return address(*), if not, it won't, and it's a possible next DLL's turn.
(*) Yes, this means that if two DLLs use the same value, only the first one loaded (at the moment this goes alphabetically) will receive it.
This is why I will most definitely release lists about such values I use.
DCoder Wrote:What if I want to lift the built-in array length limits like ScriptType/TaskForce length?
You might have realized already that not everything will be doable using just the callbacks.
For instance, I'm not planning to add callbacks for every single use of a property (like the scripttype array), which means you'd have to create your own in such a case.
Coding-wise, you'd do this by
a) actually adding it to the ScriptTypeClass, which would require you to increase the amount of memory allocated for the ScriptTypeClasses before being constructed, or
b) keep a map (or similar) which assigns each ScriptTypeClass pointer to a custom structure which holds the additional information, while the assignment should be a reaction on the construction event (likewise when the object gets destructed, you drop the assignment).
I used to stick to method (a) in the RP times, but for the DLLs I'm most likely going to use method (b).
In both cases you'll have to modify every single usage of the modified properties and make it point to your newly allocated structure.
This is the type of case that will require you to set a return address, ie your DLL will be in danger to be compatible to others (concerning ScriptTypes).
DLLs truly make adding easier than modifying existing stuff, quite the opposite of exe hacking. Whether that's good or bad, we'll see.