diff --git a/src/p_local.h b/src/p_local.h index 93875df2f..6bb65ad97 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -38,9 +38,11 @@ class APlayerPawn; struct line_t; struct sector_t; struct msecnode_t; +struct portnode_t; struct secplane_t; struct FCheckPosition; struct FTranslatedLineTarget; +struct FLinePortal; #include @@ -389,8 +391,14 @@ int P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, FName damageType, int flags, int fulldamagedistance=0); void P_DelSeclist(msecnode_t *, msecnode_t *sector_t::*seclisthead); -msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecnode_t *&sec_thinglist); -msecnode_t* P_DelSecnode(msecnode_t *, msecnode_t *sector_t::*head); +void P_DelSeclist(portnode_t *, portnode_t *FLinePortal::*seclisthead); + +template +nodetype *P_AddSecnode(linktype *s, AActor *thing, nodetype *nextnode, nodetype *&sec_thinglist); + +template +nodetype* P_DelSecnode(nodetype *, nodetype *linktype::*head); + msecnode_t *P_CreateSecNodeList(AActor *thing, double radius, msecnode_t *sector_list, msecnode_t *sector_t::*seclisthead); double P_GetMoveFactor(const AActor *mo, double *frictionp); // phares 3/6/98 double P_GetFriction(const AActor *mo, double *frictionfactor); diff --git a/src/p_secnodes.cpp b/src/p_secnodes.cpp index 38a9a5bab..8edfc0c70 100644 --- a/src/p_secnodes.cpp +++ b/src/p_secnodes.cpp @@ -32,7 +32,7 @@ // Maintain a freelist of msecnode_t's to reduce memory allocs and frees. //============================================================================= -msecnode_t *headsecnode = NULL; +msecnode_t *headsecnode = nullptr; FMemArena secnodearena; //============================================================================= @@ -55,7 +55,6 @@ msecnode_t *P_GetSecnode() } else { - node = node = (msecnode_t *)secnodearena.Alloc(sizeof(*node)); } return node; @@ -87,9 +86,10 @@ void P_PutSecnode(msecnode_t *node) // //============================================================================= -msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecnode_t *&sec_thinglist) +template +nodetype *P_AddSecnode(linktype *s, AActor *thing, nodetype *nextnode, nodetype *&sec_thinglist) { - msecnode_t *node; + nodetype *node; if (s == 0) { @@ -110,21 +110,21 @@ msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecn // Couldn't find an existing node for this sector. Add one at the head // of the list. - node = P_GetSecnode(); + node = (nodetype*)P_GetSecnode(); // killough 4/4/98, 4/7/98: mark new nodes unvisited. node->visited = 0; node->m_sector = s; // sector node->m_thing = thing; // mobj - node->m_tprev = NULL; // prev node on Thing thread + node->m_tprev = nullptr; // prev node on Thing thread node->m_tnext = nextnode; // next node on Thing thread if (nextnode) nextnode->m_tprev = node; // set back link on Thing // Add new node at head of sector thread starting at s->touching_thinglist - node->m_sprev = NULL; // prev node on sector thread + node->m_sprev = nullptr; // prev node on sector thread node->m_snext = sec_thinglist; // next node on sector thread if (sec_thinglist) node->m_snext->m_sprev = node; @@ -132,22 +132,26 @@ msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecn return node; } +template msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecnode_t *&sec_thinglist); +template portnode_t *P_AddSecnode(FLinePortal *s, AActor *thing, portnode_t *nextnode, portnode_t *&sec_thinglist); + //============================================================================= // // P_DelSecnode // // Deletes a sector node from the list of // sectors this object appears in. Returns a pointer to the next node -// on the linked list, or NULL. +// on the linked list, or nullptr. // //============================================================================= -msecnode_t *P_DelSecnode(msecnode_t *node, msecnode_t *sector_t::*listhead) +template +nodetype *P_DelSecnode(nodetype *node, nodetype *linktype::*listhead) { - msecnode_t* tp; // prev node on thing thread - msecnode_t* tn; // next node on thing thread - msecnode_t* sp; // prev node on sector thread - msecnode_t* sn; // next node on sector thread + nodetype* tp; // prev node on thing thread + nodetype* tn; // next node on thing thread + nodetype* sp; // prev node on sector thread + nodetype* sn; // next node on sector thread if (node) { @@ -175,12 +179,15 @@ msecnode_t *P_DelSecnode(msecnode_t *node, msecnode_t *sector_t::*listhead) // Return this node to the freelist - P_PutSecnode(node); + P_PutSecnode((msecnode_t*)node); return tn; } - return NULL; + return nullptr; } // phares 3/13/98 +template msecnode_t *P_DelSecnode(msecnode_t *node, msecnode_t *sector_t::*listhead); +template portnode_t *P_DelSecnode(portnode_t *node, portnode_t *FLinePortal::*listhead); + //============================================================================= // // P_DelSeclist @@ -195,6 +202,13 @@ void P_DelSeclist(msecnode_t *node, msecnode_t *sector_t::*sechead) node = P_DelSecnode(node, sechead); } +void P_DelSeclist(portnode_t *node, portnode_t *FLinePortal::*sechead) +{ + while (node) + node = P_DelSecnode(node, sechead); +} + + //============================================================================= // phares 3/14/98 // @@ -210,13 +224,13 @@ msecnode_t *P_CreateSecNodeList(AActor *thing, double radius, msecnode_t *sector // First, clear out the existing m_thing fields. As each node is // added or verified as needed, m_thing will be set properly. When - // finished, delete all nodes where m_thing is still NULL. These + // finished, delete all nodes where m_thing is still nullptr. These // represent the sectors the Thing has vacated. node = sector_list; while (node) { - node->m_thing = NULL; + node->m_thing = nullptr; node = node->m_tnext; } @@ -254,12 +268,12 @@ msecnode_t *P_CreateSecNodeList(AActor *thing, double radius, msecnode_t *sector sector_list = P_AddSecnode(thing->Sector, thing, sector_list, thing->Sector->*seclisthead); // Now delete any nodes that won't be used. These are the ones where - // m_thing is still NULL. + // m_thing is still nullptr. node = sector_list; while (node) { - if (node->m_thing == NULL) + if (node->m_thing == nullptr) { if (node == sector_list) sector_list = node->m_tnext; @@ -308,7 +322,7 @@ portnode_t *P_DelPortalnode(portnode_t *node) if (sp) sp->m_snext = sn; else - node->m_portal->lineportal_thinglist = sn; + node->m_sector->lineportal_thinglist = sn; if (sn) sn->m_sprev = sp; @@ -316,7 +330,7 @@ portnode_t *P_DelPortalnode(portnode_t *node) P_PutSecnode(reinterpret_cast(node)); return tn; } - return NULL; + return nullptr; } @@ -340,16 +354,16 @@ portnode_t *P_AddPortalnode(FLinePortal *s, AActor *thing, portnode_t *nextnode) // killough 4/4/98, 4/7/98: mark new nodes unvisited. node->visited = 0; - node->m_portal = s; // portal + node->m_sector = s; // portal node->m_thing = thing; // mobj - node->m_tprev = NULL; // prev node on Thing thread + node->m_tprev = nullptr; // prev node on Thing thread node->m_tnext = nextnode; // next node on Thing thread if (nextnode) nextnode->m_tprev = node; // set back link on Thing // Add new node at head of portal thread starting at s->touching_thinglist - node->m_sprev = NULL; // prev node on portal thread + node->m_sprev = nullptr; // prev node on portal thread node->m_snext = s->lineportal_thinglist; // next node on portal thread if (s->lineportal_thinglist) node->m_snext->m_sprev = node; @@ -357,7 +371,6 @@ portnode_t *P_AddPortalnode(FLinePortal *s, AActor *thing, portnode_t *nextnode) return node; } - //========================================================================== // // Handle the lists used to render actors from other portal areas @@ -420,18 +433,12 @@ void AActor::UpdateRenderSectorList() void AActor::ClearRenderSectorList() { - msecnode_t *node = touching_sectorportallist; - while (node) - node = P_DelSecnode(node, §or_t::sectorportal_thinglist); - touching_sectorportallist = NULL; + P_DelSeclist(touching_sectorportallist, §or_t::sectorportal_thinglist); + touching_sectorportallist = nullptr; } void AActor::ClearRenderLineList() { - portnode_t *node = touching_lineportallist; - while (node) - node = P_DelPortalnode(node); - touching_lineportallist = NULL; + P_DelSeclist(touching_lineportallist, &FLinePortal::lineportal_thinglist); + touching_lineportallist = nullptr; } - - diff --git a/src/p_user.cpp b/src/p_user.cpp index 6db4a57f5..3ea9f451f 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -95,9 +95,19 @@ static int PredictionLerptics; static player_t PredictionPlayerBackup; static BYTE PredictionActorBackup[sizeof(APlayerPawn)]; -static TArray PredictionTouchingSectorsBackup; static TArray PredictionSectorListBackup; -static TArray PredictionSector_sprev_Backup; + +static TArray PredictionTouchingSectorsBackup; +static TArray PredictionTouchingSectors_sprev_Backup; + +static TArray PredictionRenderSectorsBackup; +static TArray PredictionRenderSectors_sprev_Backup; + +static TArray PredictionPortalSectorsBackup; +static TArray PredictionPortalSectors_sprev_Backup; + +static TArray PredictionPortalLinesBackup; +static TArray PredictionPortalLines_sprev_Backup; // [GRB] Custom player classes TArray PlayerClasses; @@ -2775,6 +2785,100 @@ bool P_LerpCalculate(AActor *pmo, PredictPos from, PredictPos to, PredictPos &re return (delta.LengthSquared() > cl_predict_lerpthreshold && scale <= 1.00f); } +template +void BackupNodeList(AActor *act, nodetype *head, nodetype *linktype::*otherlist, TArray &prevbackup, TArray &otherbackup) +{ + // The ordering of the touching_sectorlist needs to remain unchanged + // Also store a copy of all previous sector_thinglist nodes + prevbackup.Clear(); + otherbackup.Clear(); + + for (auto mnode = head; mnode != nullptr; mnode = mnode->m_tnext) + { + otherbackup.Push(mnode->m_sector); + + for (auto snode = mnode->m_sector->*otherlist; snode; snode = snode->m_snext) + { + if (snode->m_thing == act) + { + prevbackup.Push(snode->m_sprev); + break; + } + } + } +} + +template +nodetype *RestoreNodeList(AActor *act, nodetype *head, nodetype *linktype::*otherlist, TArray &prevbackup, TArray &otherbackup) +{ + // Destroy old refrences + nodetype *node = head; + while (node) + { + node->m_thing = NULL; + node = node->m_tnext; + } + + // Make the sector_list match the player's touching_sectorlist before it got predicted. + P_DelSeclist(head, otherlist); + head = NULL; + for (auto i = otherbackup.Size(); i-- > 0;) + { + head = P_AddSecnode(otherbackup[i], act, head, otherbackup[i]->*otherlist); + } + //act->touching_sectorlist = ctx.sector_list; // Attach to thing + //ctx.sector_list = NULL; // clear for next time + + // In the old code this block never executed because of the commented-out NULL assignment above. Needs to be checked + node = head; + while (node) + { + if (node->m_thing == NULL) + { + if (node == head) + head = node->m_tnext; + node = P_DelSecnode(node, otherlist); + } + else + { + node = node->m_tnext; + } + } + + nodetype *snode; + + // Restore sector thinglist order + for (auto i = otherbackup.Size(); i-- > 0;) + { + // If we were already the head node, then nothing needs to change + if (prevbackup[i] == NULL) + continue; + + for (snode = otherbackup[i]->*otherlist; snode; snode = snode->m_snext) + { + if (snode->m_thing == act) + { + if (snode->m_sprev) + snode->m_sprev->m_snext = snode->m_snext; + else + snode->m_sector->*otherlist = snode->m_snext; + if (snode->m_snext) + snode->m_snext->m_sprev = snode->m_sprev; + + snode->m_sprev = prevbackup[i]; + + // At the moment, we don't exist in the list anymore, but we do know what our previous node is, so we set its current m_snext->m_sprev to us. + if (snode->m_sprev->m_snext) + snode->m_sprev->m_snext->m_sprev = snode; + snode->m_snext = snode->m_sprev->m_snext; + snode->m_sprev->m_snext = snode; + break; + } + } + } + return head; +} + void P_PredictPlayer (player_t *player) { int maxtic; @@ -2809,28 +2913,10 @@ void P_PredictPlayer (player_t *player) act->flags2 &= ~MF2_PUSHWALL; player->cheats |= CF_PREDICTING; - // The ordering of the touching_sectorlist needs to remain unchanged - // Also store a copy of all previous sector_thinglist nodes - msecnode_t *mnode = act->touching_sectorlist; - msecnode_t *snode; - PredictionSector_sprev_Backup.Clear(); - PredictionTouchingSectorsBackup.Clear (); - - while (mnode != NULL) - { - PredictionTouchingSectorsBackup.Push (mnode->m_sector); - - for (snode = mnode->m_sector->touching_thinglist; snode; snode = snode->m_snext) - { - if (snode->m_thing == act) - { - PredictionSector_sprev_Backup.Push(snode->m_sprev); - break; - } - } - - mnode = mnode->m_tnext; - } + BackupNodeList(act, act->touching_sectorlist, §or_t::touching_thinglist, PredictionTouchingSectors_sprev_Backup, PredictionTouchingSectorsBackup); + BackupNodeList(act, act->touching_rendersectors, §or_t::touching_renderthings, PredictionRenderSectors_sprev_Backup, PredictionRenderSectorsBackup); + BackupNodeList(act, act->touching_sectorportallist, §or_t::sectorportal_thinglist, PredictionPortalSectors_sprev_Backup, PredictionPortalSectorsBackup); + BackupNodeList(act, act->touching_lineportallist, &FLinePortal::lineportal_thinglist, PredictionPortalLines_sprev_Backup, PredictionPortalLinesBackup); // Keep an ordered list off all actors in the linked sector. PredictionSectorListBackup.Clear(); @@ -2940,6 +3026,12 @@ void P_UnPredictPlayer () player->camera = savedcamera; FLinkContext ctx; + // Unlink from all list, includeing those which are not being handled by UnlinkFromWorld. + auto sectorportal_list = act->touching_sectorportallist; + auto lineportal_list = act->touching_lineportallist; + act->touching_sectorportallist = nullptr; + act->touching_lineportallist = nullptr; + act->UnlinkFromWorld(&ctx); memcpy(&act->snext, PredictionActorBackup, sizeof(APlayerPawn) - ((BYTE *)&act->snext - (BYTE *)act)); @@ -2968,71 +3060,10 @@ void P_UnPredictPlayer () *link = me; } - // Destroy old refrences - msecnode_t *node = ctx.sector_list; - while (node) - { - node->m_thing = NULL; - node = node->m_tnext; - } - - // Make the sector_list match the player's touching_sectorlist before it got predicted. - P_DelSeclist(ctx.sector_list, §or_t::touching_thinglist); - ctx.sector_list = NULL; - for (i = PredictionTouchingSectorsBackup.Size(); i-- > 0;) - { - ctx.sector_list = P_AddSecnode(PredictionTouchingSectorsBackup[i], act, ctx.sector_list, PredictionTouchingSectorsBackup[i]->touching_thinglist); - } - act->touching_sectorlist = ctx.sector_list; // Attach to thing - ctx.sector_list = NULL; // clear for next time - - // Huh??? - node = ctx.sector_list; - while (node) - { - if (node->m_thing == NULL) - { - if (node == ctx.sector_list) - ctx.sector_list = node->m_tnext; - node = P_DelSecnode(node, §or_t::touching_thinglist); - } - else - { - node = node->m_tnext; - } - } - - msecnode_t *snode; - - // Restore sector thinglist order - for (i = PredictionTouchingSectorsBackup.Size(); i-- > 0;) - { - // If we were already the head node, then nothing needs to change - if (PredictionSector_sprev_Backup[i] == NULL) - continue; - - for (snode = PredictionTouchingSectorsBackup[i]->touching_thinglist; snode; snode = snode->m_snext) - { - if (snode->m_thing == act) - { - if (snode->m_sprev) - snode->m_sprev->m_snext = snode->m_snext; - else - snode->m_sector->touching_thinglist = snode->m_snext; - if (snode->m_snext) - snode->m_snext->m_sprev = snode->m_sprev; - - snode->m_sprev = PredictionSector_sprev_Backup[i]; - - // At the moment, we don't exist in the list anymore, but we do know what our previous node is, so we set its current m_snext->m_sprev to us. - if (snode->m_sprev->m_snext) - snode->m_sprev->m_snext->m_sprev = snode; - snode->m_snext = snode->m_sprev->m_snext; - snode->m_sprev->m_snext = snode; - break; - } - } - } + act->touching_sectorlist = RestoreNodeList(act, ctx.sector_list, §or_t::touching_thinglist, PredictionTouchingSectors_sprev_Backup, PredictionTouchingSectorsBackup); + act->touching_rendersectors = RestoreNodeList(act, ctx.render_list, §or_t::touching_renderthings, PredictionRenderSectors_sprev_Backup, PredictionRenderSectorsBackup); + act->touching_sectorportallist = RestoreNodeList(act, sectorportal_list, §or_t::sectorportal_thinglist, PredictionPortalSectors_sprev_Backup, PredictionPortalSectorsBackup); + act->touching_lineportallist = RestoreNodeList(act, lineportal_list, &FLinePortal::lineportal_thinglist, PredictionPortalLines_sprev_Backup, PredictionPortalLinesBackup); } // Now fix the pointers in the blocknode chain diff --git a/src/r_defs.h b/src/r_defs.h index 44f042820..4b820a3a0 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1372,7 +1372,7 @@ struct msecnode_t // use the same memory layout as msecnode_t so both can be used from the same freelist. struct portnode_t { - FLinePortal *m_portal; // a portal containing this object + FLinePortal *m_sector; // a portal containing this object (no, this isn't a sector, but if we want to use templates it needs the same variable names as msecnode_t.) AActor *m_thing; // this object struct portnode_t *m_tprev; // prev msecnode_t for this thing struct portnode_t *m_tnext; // next msecnode_t for this thing