This also changes the action special interface to pass a Level parameter to the separate functions and makes a few other minor adjustments to the polyobject code.
This was yet another piece of code that lived or died with the assumption that there can only be one level, stored in global variables.
# Conflicts:
# src/p_saveg.cpp
I have to wonder why it had to use such a complicated implementation that provided no advantages whatsoever.
The new code is just 1/5th of the old one's size and much closer to Hexen's original implementation which also was a simple array but with no means to resize the queue.
This involves passing the level explicitly to many functions. What was done here may seem a bit excessive but at least it covers everything.
Most importantly, the global ActiveThinker pointer has been moved into FLevelLocals and is now getting tracked properly by the level without using dangerous assumptions about how the game organizes its data.
Since the SpawnedThings array is still available when polyobjects are spawned it makes no sense to create an expensive linked list in P_SpawnMapThing.
This can be done far better by scanning through the array again and collect all matching items in a second array.
The new specification is more flexible, and allows assigning additive
colors to individual parts of a sector (walls, sprites, flats) and even
individual parts of a side (top, middle, bottom)
Add AdditiveColors arrays to sector_t and side_t::part
Initialize AdditiveColors arrays to 0
Export AdditiveColors to ZScript
Save AdditiveColors in saved game files
Use colors from AdditiveColors arrays when setting the additive color
for the render state
Add code to parse the new UDMF additive color properties
Remove additive color slot from sector color/part enum
Add SetAdditiveColor to sector_t and side_t
Add GetAdditiveColor to side_t
Export new methods and additive color arrays to ZScript
Rename ColorAdd to AddColor
Add AddColor to FRenderState
Tweak SpecialColors array in ZScript to include the additive color
Add uAddColor to the shader compiler
Add uAddColor to the texel
This did no longer sort sprites in the same position reliably since the feature to render sprites which only partially are inside a sector was added.
With this, sprites in the same position are no longer guaranteed to be added to the render list in sequence.
Fixed by adding an 'order' field to AActor which gets incremented with each spawned actor and reset when a new level is started.
The software renderer will also need a variation of this fix but its data no longer has access to the defining actor when being sorted, so a bit more work is needed here.
* it was never saved in savegames, leaving the state of dead bodies undefined
* it shouldn't be subjected to pointer substitution because all it contains is old dead bodies, not live ones.
* Colors can npw be defined per sidedef, not only per sector.
* Gradients can be selectively disabled or vertically flipped per wall tier.
* Gradients can be clamped to their respective tier, i.e top and bottom of the tier, not the front sector defines where it starts.
The per-wall colors are implemented for hardware and softpoly renderer only, but not for the classic software renderer, because its code is far too scattered to do this efficiently.
- precalculate if a sector's floor and ceiling plane overlap. This avoids rechecking this for each single call of hw_FakeFlat.
- vertices must be marked dirty every time they change after map setup. That means that ChangePlaneTexZ must do this as well, because it cannot rely on interpolation taking care of it.
- Having a 'dirty' argument for SetPlaneTexZ's ZScript version makes no sense. If the value changes from the script side the vertices must always be marked to be recalculated.
- added a few access functions for FActorInfo variables.
With PClassActor now empty the class descriptors can finally be converted back to static data outside the class hierarchy, like they were before the scripting merge, and untangle the game data from VM internals.
src/gl/scene/gl_clipper.h:150:23: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
src/gl/dynlights/gl_aabbtree.cpp:137:24: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_aabbtree.cpp:137:34: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_aabbtree.cpp:137:44: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_aabbtree.cpp:139:6: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_aabbtree.cpp:139:30: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_aabbtree.cpp:139:54: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_aabbtree.cpp:142:6: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_aabbtree.cpp:143:3: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_aabbtree.cpp:144:3: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_aabbtree.cpp:167:6: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
src/gl/dynlights/gl_shadowmap.cpp:163:31: warning: '&&' within '||' [-Wlogical-op-parentheses]
src/p_saveg.cpp:367:16: warning: comparison of integers of different signs: 'unsigned int' and 'int' [-Wsign-compare]
src/p_saveg.cpp:402:60: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
src/p_setup.cpp:1553:39: warning: format specifies type 'ptrdiff_t' (aka 'long') but the argument has type 'int' [-Wformat]
src/scripting/zscript/zcc_compile.cpp:293:74: warning: field 'AST' will be initialized after field 'mVersion' [-Wreorder]
src/swrenderer/drawers/r_thread.cpp:113:21: warning: comparison of integers of different signs: 'int' and 'size_t' (aka 'unsigned long') [-Wsign-compare]
- replaced TStaticArray with regular TArrays.
They had incomplete implementations preventing proper cleanup of the level loading code. It makes more sense to add the missing methods to the regular TArray and use that.
This also makes some changes to how the game nodes are used to avoid creating a copy: If the head node's pointer is stored in a separate variable, no code needs to check which of the two arrays gets used.
This has increasingly become an obstacle with the hardware renderer, so now the values are being stored as plain data in the sector, with the software renderer getting the actual color tables when needed. While this is a bit slower than storing the pregenerated colormap, in realistic situations the added time is mostly negligible in the microseconds range.
Since the true color software renderer also handles them there is no point keeping them on the GL side.
This also optimized how they are stored, because we no longer need to be aware of a base engine which doesn't have them.
gl/data/gl_setup.cpp:430:11: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
gl/data/gl_setup.cpp:527:19: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
gl/data/gl_setup.cpp:542:19: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
nodebuild.cpp:1056:63: warning: format specifies type 'ptrdiff_t' (aka 'long') but the argument has type 'int' [-Wformat]
p_glnodes.cpp:379:50: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
p_saveg.cpp:381:18: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
p_scroll.cpp:532:11: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
p_setup.cpp:2304:43: warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]
p_setup.cpp:2302:12: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
scripting/codegeneration/codegen.cpp:8488:20: warning: comparison of integers of different signs: 'int' and 'size_t' (aka 'unsigned long') [-Wsign-compare]
scripting/codegeneration/codegen.cpp:8606:15: warning: comparison of integers of different signs: 'int' and 'size_t' (aka 'unsigned long') [-Wsign-compare]
- disabled the Build map loader after finding out that it has been completely broken and nonfunctional for a long time. Since this has no real value it will probably removed entirely in an upcoming commit.
- for explicitly defined glows, use the one for the current animation frame, if an animated texture is active. For default glows it will still use the base texture's to avoid inconsistencies.
- This was only visible when using a screen wipe because the initial frame wiped
to would clamp the pitch to whatever undefined pitch range the player
had before the proper range was received.
We have to be extremely careful with the player data, because there's just too much code littered around that has certain expectations about what needs to be present and what not.
Obviously, when travelling in a hub, the player_t should be retained from the previous level. But we still have to set player_t::mo to the PlayerPawn from the savegame so that G_UnsnapshotLevel doesn't prematurely delete it and all associated voodoo dolls, because it checks player_t::mo to decide whether a player is valid or not.
The actual deletion of this redundant PlayerPawn should only be done in G_FinishTravel, after the actual player has been fully set up
* do not skip the player_t init when travelling in a hub. The old player may still be needed in some edge cases. This applies only to singleplayer for now. The multiplayer version still needs reviewing. I left it alone because it may shuffle players around which is not wanted when doing hub travelling.
* do not spawn two temp players in G_FinishTravel. Instead handle the case where no player_t::mo can be found gracefully by adding a few nullptr checks. This temp player served no real purpose except for having a valid pointer. The actual start position was retrieved from somewhere else.
I wish I had realized this the last time it came up - it would have saved me a lot of trouble.
But as it turns out, the more recent travelling code makes all of this completely unnecessary, working perfectly fine with deleting the player pawns along with the rest of the thinkers before loading the stored ones from the savegame (and getting rid of those in G_FinishTravel.)
And with a sane savegame format that does not depend on side effects from how the thinker serializing handled linking into the lists the old code was even harmful, leaving voodoo dolls behind.
I had the exact same effect when I tried to reshuffle some things for reliably restoring portals, but did not make the connection to interference between two mutually incompatible player travelling mechanisms that just worked by sheer happenstance with the original order of things.
- changed S_GetMusic to return a const pointer to the actual music name instead of a copy. The only thing this is used for is the savegame code and it has no use for a copy, it can work far more efficiently with a const pointer.
After testing with a savegame on ZDCMP2 which is probably the largest map in existence, timing both methods resulted in a speed difference of less than 40 ms (70 vs 110 ms for reading all sectory, linedefs, sidedefs and objects).
This compares to an overall restoration time, including reloading the level, precaching all textures and setting everything up, of approx. 1.2 s, meaning an increase of 3% of the entire reloading time.
That's simply not worth all the negative side effects that may happen with a method that highly depends on proper code construction.
On the other hand, using random access means that a savegame version change is only needed now when the semantics of a field change, but not if some get added or deleted.
- do not I_Error out in the serializer unless caused by a programming error.
It is better to let the serializer finish, collect all the errors and I_Error out when the game is known to be in a stable enough state to allow unwinding.
It turned out this may not be done automatically when opening the savegame - it has to be done later, after the pre-spawned map thinkers and all connected objects have been destroyed.
The object deserializer also has to be rather careful about dealing with parse errors, because if something goes wrong a whole batch of uninitialized or partially initialized objects will be left behind to destroy.
This means that no object class may assume that anything but the default constructor has been run on it and needs to check any variable it may reference.
- converted sound and canvas texture serialization.
- refactored file_zip, so that it can be used to load loose zip files and extract their compressed data directly.
- added handling to FSerializer to generate and consume compressed Zip file entries.
If all goes well this will allow saving savegames as Zips when the rework is done, which will make analyzing them a lot easier.
- fixed a few errors in the ACS module serializer.
- reordered a few things to how they were in the old code.
- optimized serialization of the level.Scrolls array to happen within the sector. This is to allow skipping 0-entries which normally constitute the vast majority of them.
- added sanity checks to prevent a savegame from being loaded with an incompatible map
- refactored a few things to simplify serialization.
- started work on main level serializer function.
Note that even with this change it is still not possible to unarchive any thinker pointers before the thinker list has been loaded as it would create broken lists.
Since decals may have thinkers attached this will crash when such a savegame gets loaded, because the thinker lists get reset in P_SerializeThinkers, deleting any thinker that already was processed.
I also added an error message that immediately aborts the save process if such an out-of-sequence thinker is attempted to be written out.
This obviously breaks savegame compatibility again...
- fixed: Visplane checks should only compare the plane flags that are relevant for rendering and mask out the rest.
- floatified FTransform and made the visplane checks a bit less verbose by moving the comparison as an operator into FTransform.
Note that this operator needs forceinline on Visual Studio so that it won't get called as a function.