Happy new year!
Okay, so I've installed the current edition of Visual Studio and CMake and got it running and reproduced the bug with the debugger enabled!
I present: My more detailed bug report :D
This is for version 3.2.4.
Proposed fix: See at the end of the post.
From top to bottom, this is where the crash comes from:
g_levellocals.h:
Code: Select all
inline int sector_t::GetOppositePortalGroup(int plane)
return level.sectorPortals[Portals[plane]].mDestination->PortalGroup;
Unhandled exception thrown: read access violation.
TArray<FSectorPortal,FSectorPortal>::operator[](...).mDestination was nullptr.
level.sectorPortals[Portals[plane]].mDestination is nullptr, so ->PortalGroup crashes it.
The .sectorPortals seem to indicate those actual portals from the feature that you can see and move through portals (struct FSectorPortal in portal.h).
Code: Select all
unsigned Portals[2]; per sector_t are indexes into that array, reading "// [RH] The portal or skybox to render for this sector."
Portals[0] and Portals[1] are both 0 here.
Coming from:
p_map.cpp
Code: Select all
// P_TryMove
// Attempt to move to a new position,
// crossing special lines unless MF_TELEPORT is set.
bool P_TryMove(AActor *thing, ...
Code: Select all
// If the actor stepped through a ceiling portal we need to reacquire the actual position info after the transition
if (tm.portalstep)
{
FLinkContext ctx;
DVector3 oldpos = thing->Pos();
thing->UnlinkFromWorld(&ctx);
thing->SetXYZ(thing->PosRelative(thing->Sector->GetOppositePortalGroup(sector_t::ceiling)));
^ setXYZ
Call from p_mobj.cpp/double P_XYMovement (AActor *mo, DVector2 scroll)
I dunno what kind of actor this is. Maybe a puff of smoke or a spark so. At first glance it looks like it crashes the moment this thing rises through the portal upward.
Does the sector have wrong information, or is thing->Sector wrong in that moment?
Map layout:
Code: Select all
bottom inner tag 1, sector id 2
bottom outer tag 0, sector id 3
top inner tag 3, sector id 0
top outer tag 0, sector id 1
The ceiling of bottom inner is the floor of top inner.
Inspecting level.sectors:
Code: Select all
0 (top inner): Portals = {3, 0}
1 (top outer): Portals = {0, 0}
2 (bottom inner): Portals = {0, 2}
3 (bottom outer): Portals = {0, 0}
thing->Sector in setXYZ points at sector 3 in my crash moment, the bottom outer, while I think it should point at 2, the bottom inner then.
Hm... so maybe the thing moved parallel to the world floor, but also vertically - Maybe at the ledge, it moves diagonally?
Could "if (tm.portalstep)" in p_map.cpp yield true while at the same time the thing moves out of the sector?
In P_TryMove, there's *oldsector and also *oldsec, and both point at sector 2 in that moment, which would be correct.
============================
My theory:
in p_map.cpp, replacing thing->Sector with oldsector in
Code: Select all
thing->SetXYZ(thing->PosRelative(thing->Sector->GetOppositePortalGroup(sector_t::ceiling)));
should do the trick, at least with my limited understanding of what I see there (could also be that the other "old" variable is supposed to be used).
After all, there is also a reference to "oldpos" in the next line of code.
Making that little change and compiling it, the game stopped crashing for me in my test case. :D
Could someone please check that out? Hoping that the next release doesn't have this crash bug anymore then. :)
This was a fun little endeavor!