Thanks to the lazy counter it used in its stat display I never noticed that the serializer was incomplete and that UnlinkFromMap did not call its super method.
After changing the counter to be actively counting on each call, all the other issues became immediately apparent.
The interpolator had been changed long ago to use proper GC tracking, so interpolations only can get collected if they had been fully orphaned.
This comment was the main reason why the design flaw in this code never got fixed until recently.
It seems there can be rare conditions where an interpolation is 'lost' and later garbage collected. If that happens after the owning map is gone, all pointers in the interpolation object will be invalid and Destroy would crash while trying to unlink it. So anything that explicitly deletes an interpolation now has to manually unlink it from the map first so that OnDestroy can be kept clean of map references.
This was always used with 'consoleplayer' which really is the only thing making sense here. But this is a part of the global state which should be avoided in play code.
In particular, this makes no real sense in case of secondary maps where it should always return false.
There is no need to do this deep inside the renderer where it required code duplication and made it problematic to execute on multiple levels.
This is now being done before and after the top level call into the renderer in d_main.cpp.
This also serializes the interpolator itself to avoid problems with the Serialize functions adding the interpolations into the list which can only work with a single global instance.
Since the only thing it gets used for is swapping out PlayerPawns it can safely skip all global variables that never point to a live player, which allowed to remove quite a bit of code here that stood in the way of scriptifying more content
This is to ensure that the Class pointer can be set right on creation. ZDoom had always depended on handling this lazily which poses some problems for the VM.
So now there is a variadic Create<classtype> function taking care of that, but to ensure that it gets used, direct access to the new operator has been blocked.
This also neccessitated making DArgs a regular object because they get created before the type system is up. Since the few uses of DArgs are easily controllable this wasn't a big issue.
- did a bit of optimization on the bots' decision making whether to pick up a health item or not.
This was done to ensure it can be properly overridden in scripts without causing problems when called during engine shutdown for the type and symbol objects the VM needs to work and to have the scripted version always run first.
Since the scripted OnDestroy method never calls the native version - the native one is run after the scripted one - this can be simply skipped over during shutdown.
Needless to say, this is simply too volatile and would require constant active maintenance, not to mention a huge amount of work up front to get going.
It also hid a nasty problem with the Destroy method. Due to the way the garbage collector works, Destroy cannot be exposed to scripts as-is. It may be called from scripts but it may not be overridden from scripts because the garbage collector can call this function after all data needed for calling a scripted override has already been destroyed because if that data is also being collected there is no guarantee that proper order of destruction is observed. So for now Destroy is just a normal native method to scripted classes
- Cleared some GCC and Clang warnings. Mostly static analysis false positives, but one of them generated a pretty massive warning in a release build.
- Use -Wno-unused-result since I doubt we're going to address those unless they actually prove to be a problem (and they only appear in release builds).