Skip to content

February 2015 seam - #211

Merged
rc4l merged 54 commits into
mainfrom
port/seam-2015-02
Aug 6, 2026
Merged

February 2015 seam#211
rc4l merged 54 commits into
mainfrom
port/seam-2015-02

Conversation

@rc4l

@rc4l rc4l commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Walked the February 2015 commits in date order, one at a time. 116 of 116 rows resolved, zero pending.

Verdict Count
ported 50
skip 42 (33 merge commits)
adapted 24
deferred 0

Zero deferred — unlike January's 8, this seam has no VM entanglement anywhere.

Real bugs found, none predicted by their titles

  • Null dereference in coop respawnFilterCoopRespawnInventory tested defitem != NULL; inverted, so the else branch read defitem->SavePercent exactly when it was NULL.
  • FDynamicBuffer::SetData assigned the local len parameter instead of m_Len, so a cleared buffer kept reporting stale contents. Inherited from the base.
  • Dehacked replaced only the first occurrence of a patched string.
  • A player number indexing node arrays in the netcode stall detector.
  • A_CStaffCheck dereferenced linetarget after P_LineAttack, which can clear it.
  • HasWeaponPiece only ever set truth, never cleared it, so removed pieces still read as held.

Three under-ports caught by reading follow-ups rather than diff headers

c4b742ebf guarded six P_SpawnMissile* functions and only one had been taken. The OPL waveform fix was four hunks, not the two its header shows. The +NOGRAVITY sweep removed 31 where upstream removed 30 — ArtiBoostMana was deliberately kept, and the walk later reached the commit that removes it.

Clusters taken as settled state

The earthquake rewrite (11 rows) — the intermediate steps undo each other: QuakePower goes to doubles and back, QF_SCALEUP is removed and re-added. Landing them in order would mean writing code to delete days later. Every row is still recorded individually.

The sanity crusade (2 rows, 46 files) — upstream reverted most of it within days, so this takes the state after the reverts: four real defects out of a large hygiene pass.

Netcode

SERVERCOMMANDS_Earthquake sent a single intensity byte and physically could not describe a per-axis quake; it now carries three intensities plus a flag word, with the matching client decode.

Worth knowing: SVC_EARTHQUAKE is hand-written with NetCommand rather than generated from protocolspec, so protocol-snapshot does not cover it and reported "unchanged" throughout. That blind spot applies to every hand-written command.

Save versions

Upstream's quake guards use its SAVEVER 4519/4520, which mean different things here (DamageMultiply, TeleFog types) — porting them verbatim would have made a save written by our 4519 build read quake fields it never wrote. Rewritten to one guard at our own version; SAVEVER 4521 → 4522.

Verification

  • Builds clean; ctest 1316/1316.
  • commit-tracker-check, commit-tracker-overlap, protocol-snapshot --check, wire-enum-snapshot --check all clean.
  • DECORATE parse and in-engine load verified after each lump change.
  • Not run: the multiplayer E2E. Process launches on this machine wedge into uninterruptible state, so the quake wire change and the fly-state move have not had a packet observed crossing.

rc4l added 30 commits August 5, 2026 23:46
Thirty-three merge commits carry no unique content. Four commits touch
nothing we have: three patch FMOD version compatibility, where our sound is
OpenAL, and one edits the software renderer's plane code.
Ports uzdoom@dc6b45804 and adapts uzdoom@8e1b1aa20.

Scrolling up through a run of disabled menu entries jumps several items at
once, which stepped straight past the equality test and scrolled the cursor
out of view. It now clamps instead.

SDL's video subsystem is brought up in I_InitGraphics rather than at startup,
since initialising it that early conflicts with GUI toolkits on some systems,
and joystick init is guarded so the manager is only built if the subsystem
came up. SDL_INIT_TIMER stays where it was: upstream moved it into
I_InitTimer, which for us exists only in the Cocoa backend.
Ports the settled form of uzdoom@de4097cc7, uzdoom@1e0a1466a and
uzdoom@291861bf5. An inventory item carrying its own inventory now hands that
inventory to whoever picks it up.

Upstream landed this three times: first in AddInventory with debug output
left in, then moved to CallTryPickup still with the debug output, then
stripped. Only the end state is here.

The flag moves from upstream's 1<<24 to 1<<25, since 1<<24 is Zandronum's
IF_FORCERESPAWNINSURVIVAL. ItemFlags is never serialised, so no existing
value shifts.
Ports uzdoom@5164b78c3. APathFollower computed hold times from gametic, which
counts from engine start and never resets, so a path holding across a level
change compared against a number that had run away. HoldTime is serialised,
which is how the stale value survived into the next level.
Ports uzdoom@60b735dc6 and uzdoom@c4f932022.

A perpetual swing polyobj can never reach the completion check below it, so
its early return guarded nothing.

listsoundchannels prints every non-evicted channel with its computed position
and a total, which is useful when tracking down sounds that will not stop.

Also records uzdoom@ec5817869 as already present: both the NUL-to-space sweep
over Dehacked patches and the (int)len cast in C_DoCommand are here.
Adapts uzdoom@322742d4b. The commit is a 28-file hygiene pass, and upstream
reverted most of it within days -- 7789975b6 undid the info, tarray, decallib
and d_net changes, fd7ed2bc2 undid am_map, c_cvars, configfile and more. Both
the am_map out-of-bounds guard and the FName const& signatures are gone by
the end of the cluster, so porting it whole would have meant landing work
upstream had already deleted.

Four of the surviving hunks are real defects rather than tidying:

SkipChunk advanced its local pointer variable instead of the caller's stream,
so skipping a chunk left the read position where it started.

FileReader's default constructor never initialised FilePos.

SetCompatibilityParams indexed CompatParams before testing the bound, reading
one past the end on the last iteration.

G_ProcessIFFDemo accepted a demo with no header at all.

The unused-variable removals in the same surviving set are cosmetic and left
alone.
Adapts uzdoom@b37a98689. A spawned actor can now inherit the caller's sprite
and frame.

Upstream also respelled the whole SIXF_ enum from 1<<n to hex in the same
commit; not taken, since the values are identical and rewriting 24 lines to
change nothing only invites a transcription error. The FAF_NODISTFACTOR
parenthesis fix it carries is moot here, because the commits that delete that
branch entirely were pulled forward during the January seam.

The transferred sprite and frame do not reach clients. SpawnThing carries
only position, class and net ID, and the post-spawn broadcasts we already do
have no sprite/frame equivalent -- SetThingFrame sends a state, not a raw
sprite/frame pair. A client draws the spawned actor with its own default
sprite. Closing that needs a new command and is its own job; the tracker row
records it.

Also records uzdoom@7789975b6 as already matching: it reverts sanity-crusade
changes we never took, and each hunk was checked rather than assumed.
Adapts uzdoom@2c06987f6. FDynamicBuffer::SetData assigned the local len
parameter instead of m_Len when handed a NULL data pointer, so the buffer
kept reporting its old length and still looked like it held its old contents.
The bug came from the base -- upstream had it too.

The same commit also added M_Free(m_Data) in that branch, which is not taken.
It leaves m_Data dangling while m_BufferLen keeps its old value, so the next
call with a small length skips the realloc and memcpys into freed memory.
Upstream HEAD has only the m_Len reset, having removed the free again.
Adapts uzdoom@c4b742ebf. As with part one of the sanity crusade, most of it
was reverted by upstream days later, so this takes the state after the revert
rather than the commit as written.

P_SpawnMissile dereferenced source unconditionally, and a DECORATE caller can
reach it with none. The revert keeps the guard and tidies it to source ==
NULL, which is the form used here.

secplane_t floorplane no longer copies from floorsector when 3D floors are
compiled in, since P_FindFloorPlane overwrote it on the next line.

The AIMREFLECT collapse in the same commit is already present as a ternary
from the reflection cluster, and the remaining hunks are unused-variable
removals.
Ports uzdoom@003817f41. The alt HUD listed every ammo type any slotted weapon
could ever use, which is a long list on a mod with many weapons.
hud_showammo now selects between the ready weapon's ammo only, ammo for
weapons actually held, or the previous behaviour, which stays the default.
Ports uzdoom@bd93ce63a, adding the AltHUDAmmo option values and the menu
entry for the CVAR added a commit earlier.

Also records three commits in the FDynamicBuffer::SetData churn as already
settled here. Upstream added M_Free, then patched the dangling pointer it
created, then removed the free altogether; we declined the free when it first
appeared, so we have been at the end state throughout. The
SXF_TRANSFERSPRITEFRAME typo fix likewise never applied, since the constant
was written with the correct prefix when it was ported.
uzdoom@2d7592c2c puts back the locals the sanity crusade removed from the
nodebuilder. We never took those removals, so the tree already matches.
Checked each variable rather than the commit title: SplitSeg's dx and dy,
ptect around the mprotect call, and bestj in CloseSubsector, which lives in
nodebuild_extract.cpp here rather than nodebuild_gl.cpp.
Ports uzdoom@711ac7791, uzdoom@c3227729e and uzdoom@79791629e.

FilterCoopRespawnInventory tested defitem != NULL when deciding whether to
destroy armour, which is backwards: the else branch then read
defitem->SavePercent precisely when defitem was NULL, so respawning in coop
as a class with no default armour dereferenced null.

FxGlobalVariable::Resolve was missing a break, so the float, fixed and angle
cases fell through into the object and class cases and overwrote ValueType.

DoGiveInv had an if/else whose branches were identical.
Ports uzdoom@fd7ed2bc2, the large revert of the sanity crusade.

Every hunk of the revert already matched here, since we took only the
crusade's surviving fixes rather than the commit as written. But reading it
caught an under-port of my own: uzdoom@c4b742ebf added null source guards to
six P_SpawnMissile functions and only one had been taken. The other five now
have them, in the settled form the revert normalises to.

That is the second time this cluster has repaid reading the follow-up rather
than trusting the original commit.
Ports uzdoom@6423b2fec, uzdoom@867bfd275 and adapts uzdoom@3d7934f1a.

A Dehacked text replacement only altered the first occurrence of the source
string. The search now repeats until no match remains, poisoning each matched
entry so neither the next pass nor a later replacement finds it again, and it
no longer sits behind !good since a string can appear in both the tables
searched earlier and the general text list.

Net_CheckLastRecieved indexed nettics and remoteresend -- both node arrays --
with Net_Arbitrator, which is a player number, and made the mirror-image
mistake when looking up the player. Both now go through nodeforplayer.

The rename to Net_CheckLastReceived in the same commit is not taken; the
misspelling is Zandronum's too, and renaming a function our netcode calls is
churn against the fork for no gain.
Ports uzdoom@c6cb8493e and adapts uzdoom@962fc64d2. Both CVARs already
existed here with no way to reach them from the menu. The earthquake
intensity slider from the same commit was already present.
rc4l added 24 commits August 6, 2026 00:28
Ports uzdoom@a3bdbff05, uzdoom@5fc6ff130 and uzdoom@c0eb39ec7.

The 3D midtex opening was computed from the texture's own scale alone, so a
sidedef carrying its own Y scale got both the height and the offset divisor
wrong. This comes with the GetScaledHeight overload the fix needs.

A 3D floor with neither ALLSIDES nor BOTHPLANES draws nothing, but was
counted as solid when building the sorted lists, clipping the top plane of
anything that overlapped it.

A_TimeBomb raises the actor 32 units to position the explosion, and without
resetting PrevZ the renderer interpolated that jump, smearing the explosion
frames upward from where the bomb had been.
Adapts uzdoom@337682934. CF_FLY lived on player_t while MF2_FLY lived on the
actor, so travel carried one and not the other -- which is what the sync hack
this commit deletes was papering over. The state is now MF7_FLYCHEAT on the
actor and the two stay together for free.

Upstream numbered the flag 0x00020000, which is MF7_NODECAL here, so it takes
the free 0x00080000. flags7 is wire-synced, but only an added bit is
involved, so nothing existing shifts.

The commit as written tested (flags7 ^= MF7_FLYCHEAT) != 0 in the fly cheat,
which is true whenever any other flags7 bit is set; this takes the form
upstream settled on.

Three call sites we have and upstream does not still set CF_FLY, which
nothing reads any more: spectators, savegame restore and demo playback would
all have silently lost flight. All three set the actor flag now, as does the
extra all-players branch our LS_SetPlayerProperty carries.

This is a netcode improvement rather than a risk: CF_FLY was never broadcast,
and flags7 is.
Adapts uzdoom@7db035abb, uzdoom@c2e155bb9 and uzdoom@93c12cf25 as one settled
change.

Floatbobbing items carried +NOGRAVITY purely to reproduce Hexen's placement,
which also needed per-map setthingz hacks in compatibility.txt. The flag is
gone from 30 actors, the Hexen MAP04 block is gone, and the behaviour is
restored properly instead: BCOMPATF_FLOATBOB, set automatically for maps with
an original Hexen MAPINFO, holds a map-placed floatbob item at its authored
height through special1 rather than letting it settle to the floor.

ArtiBoostMana keeps its +NOGRAVITY, as upstream left it -- a blanket removal
would have taken 31 rather than 30.

special1 is a plain int while mthing->z is our strong fixed_t, so the store
and read go through Raw and FromRaw where upstream converted implicitly.
Upstream ships the lump as menudef.z; ours is menudef.txt, so the provenance
cross-check has no shared basename to match on.
Both were declined earlier on my own judgement rather than upstream's. The
SIXF_ flags now use upstream's hex spelling, values unchanged, and
Net_CheckLastRecieved is renamed to Net_CheckLastReceived across d_net.cpp
and d_net.h. Neither is netcode behaviour, so upstream is the reference.
Adapts the eleven-commit quake cluster to its settled state at
uzdoom@2827c13d0. Porting the intermediate steps would have been wasted work:
QuakePower goes to doubles and back to fixed_t, and QF_SCALEUP is removed and
re-added, within the same week.

Quakes now have separate X, Y and Z intensities plus QF_RELATIVE, SCALEDOWN,
SCALEUP, MAX and FULLINTENSITY, exposed to DECORATE as A_QuakeEx.

SERVERCOMMANDS_Earthquake carried a single intensity byte, which cannot
describe a per-axis quake, so it sends three intensity bytes and a flag word
now, with the matching client decode. Worth knowing: SVC_EARTHQUAKE is
hand-written rather than generated from protocolspec, so protocol-snapshot
does not cover this and reported clean.

The [AK] spectator guard in R_SetupFrame and the [BC] broadcast in the
DEarthquake constructor are preserved. QuakePower indexes the RNG with the
raw 16.16 span and rebuilds the draw through FromRaw, where upstream's plain
int did both implicitly.

Also ports uzdoom@0f4bca860, SXF_TRANSFERROLL, which is observable here now
that roll renders and syncs.
Both bit rehomings in this seam happened for the same reason: upstream takes
the next free bit when it adds a flag, and so did Zandronum, so they keep
landing on the same one. A dedicated fua_flags field would end that
permanently and costs close to nothing -- flagsets are sent one at a time and
only when they differ from the default, so an unused field is free on the
wire even in a 30k-monster map.

Not doing it now because it needs an accurate list of which flags are
genuinely ours, and comparing against upstream HEAD is too noisy to trust:
upstream has renamed and restructured whole flag families since our base.
Ports uzdoom@fa2e2a852 and uzdoom@2939194ae, adapts uzdoom@3bf24204d.

The nuked OPL emulator tested extra low phase bits and decremented phase
before flipping the waveform sign, where the flip depends only on which half
of the wave the phase falls in. Four call sites, not the one the diff header
suggests.

The quake savegame guards needed rewriting rather than porting. Upstream
guards its new fields at SAVEVER 4519 and 4520, but ours mean different
things -- 4519 was DamageMultiply and 4520 TeleFog types -- so upstream's
numbers would make a save written by our 4519 build read quake fields it
never wrote. Both sets arrive together here behind one guard, and SAVEVER
goes to 4522.
Ports uzdoom@173dbd6bc and uzdoom@8e0151b4c. FxFloatCast is the float
counterpart to FxIntCast, and frandompick is randompick over float choices.

The scanner rule goes in sc_man_scanner.re, not just the token list --
sc_man_scanner.h is generated from it at build time, which is the same trap
randompick hit.

Also records three quake commits as superseded: they introduced a quakeInfo
struct that the rewrite a few hours later discarded, and the compat menu
regrouping as a skip, since our CompatibilityOptions carries 61 options to
upstream's 36 and its wholesale replacement would delete the 25 that are
Zandronum's.
Ports uzdoom@19ab774dc, uzdoom@a64ebc720 and uzdoom@e92f2826e.

P_LineAttack can clear linetarget, and A_CStaffCheck dereferenced it
immediately afterwards. Both attack blocks are guarded, not just the one the
diff header points at; the [CW] client guard and health broadcast inside are
preserved.

The assert added with frandompick compared against ValueType, which is an
FExpressionType object rather than the raw enum.

ArtiBoostMana loses its +NOGRAVITY here, which is the actor the earlier
floatbob sweep deliberately left alone -- restoring it then and removing it
now is the sequential walk working as intended.
Ports uzdoom@5aba252b8, a41af2de7, e4a041cb4 and adapts uzdoom@84f8c299c.

Cached GL nodes truncated node coordinates to words, losing precision on
large maps; they store the full fixed-point values now and the cache magic
goes to ZGL3 so stale caches are rejected rather than misread. WriteLong
takes an int, so the coordinates go through Raw where upstream passed the
plain fixed_t.

SBARINFO's HasWeaponPiece only ever set truth and never cleared it, so a
removed piece still read as held.

NoDelay calls the spawn state's function directly instead of re-entering
SetState and adjusting tics afterwards, and the level banner lower-cases the
map name.
Ports uzdoom@c7842a8de, uzdoom@719dfbe5a and adapts uzdoom@5d65b10ae.

The saveable-game guards lived in the save CCMD, so anything else reaching
G_SaveGame skipped them; they move into G_SaveGame itself, and G_DoSaveGame
additionally refuses when not in a level. Upstream tests a multiplayer global
Zandronum does not have, so the check here is NETSTATE_SINGLE.

The map-name banner ported a commit ago passed an FString where a const char*
was wanted, which only breaks off Windows.

A missing xinput.h warns rather than failing configuration, since XInput is
optional and disables cleanly.
Their content never landed as its own change, only as part of the settled
state, so the cited commit shares no file with them.
The move off player_t is a correctness fix -- a cheats bit cannot survive
travel -- not a networking gain. Broadcasting flags7 has no spectator
exclusion, so a spectator now emits a flag update for a pawn nobody renders.
Small and bounded, but a cost rather than an improvement.
@rc4l
rc4l marked this pull request as ready for review August 6, 2026 18:06
@rc4l
rc4l enabled auto-merge August 6, 2026 18:06
@rc4l
rc4l merged commit 54def93 into main Aug 6, 2026
8 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant