- link actors into blockmap through linked line portals.

Links through sector portals are not done because nearly all the checks can be performed without doing this so if it works without there's no need to add more processing time.
Will have to see if there's cases left where such a link is needed and if so, whether there's better options to do it.

For line portals such links are necessary to have proper collision detection with actors that are currently transitioning the portal.
This commit is contained in:
Christoph Oelckers 2016-03-08 14:41:37 +01:00
parent 9d877f75e3
commit 899389e6a4
6 changed files with 71 additions and 46 deletions

View file

@ -1167,7 +1167,7 @@ private:
bool FixMapthingPos();
public:
void LinkToWorld (bool spawningmapthing=false, FPortalGroupArray *groups = NULL, sector_t *sector = NULL);
void LinkToWorld (bool spawningmapthing=false, sector_t *sector = NULL);
void UnlinkFromWorld ();
void AdjustFloorClip ();
void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving = false);

View file

@ -5250,7 +5250,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo
double bombdistancefloat = 1.f / (double)(bombdistance - fulldamagedistance);
double bombdamagefloat = (double)bombdamage;
FPortalGroupArray grouplist;
FPortalGroupArray grouplist(FPortalGroupArray::PGA_Full3d);
FMultiBlockThingsIterator it(grouplist, bombspot->X(), bombspot->Y(), bombspot->Z() - bombdistfix, bombspot->height + bombdistfix*2, bombdistfix);
FMultiBlockThingsIterator::CheckResult cres;

View file

@ -435,7 +435,7 @@ bool AActor::FixMapthingPos()
//
//==========================================================================
void AActor::LinkToWorld (bool spawningmapthing, FPortalGroupArray *groups, sector_t *sector)
void AActor::LinkToWorld(bool spawningmapthing, sector_t *sector)
{
if (spawningmapthing && (flags4 & MF4_FIXMAPTHINGPOS) && sector == NULL)
{
@ -457,7 +457,7 @@ void AActor::LinkToWorld (bool spawningmapthing, FPortalGroupArray *groups, sect
Sector = sector;
subsector = R_PointInSubsector(X(), Y()); // this is from the rendering nodes, not the gameplay nodes!
if ( !(flags & MF_NOSECTOR) )
if (!(flags & MF_NOSECTOR))
{
// invisible things don't go into the sector links
// killough 8/11/98: simpler scheme using pointer-to-pointer prev
@ -482,51 +482,60 @@ void AActor::LinkToWorld (bool spawningmapthing, FPortalGroupArray *groups, sect
// When a node is deleted, its sector links (the links starting
// at sector_t->touching_thinglist) are broken. When a node is
// added, new sector links are created.
P_CreateSecNodeList (this, X(), Y());
P_CreateSecNodeList(this, X(), Y());
touching_sectorlist = sector_list; // Attach to thing
sector_list = NULL; // clear for next time
}
}
// link into blockmap (inert things don't need to be in the blockmap)
if ( !(flags & MF_NOBLOCKMAP) )
if (!(flags & MF_NOBLOCKMAP))
{
int x1 = GetSafeBlockX(X() - radius - bmaporgx);
int x2 = GetSafeBlockX(X() + radius - bmaporgx);
int y1 = GetSafeBlockY(Y() - radius - bmaporgy);
int y2 = GetSafeBlockY(Y() + radius - bmaporgy);
FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals);
if (x1 >= bmapwidth || x2 < 0 || y1 >= bmapheight || y2 < 0)
{ // thing is off the map
BlockNode = NULL;
}
else
{ // [RH] Link into every block this actor touches, not just the center one
FBlockNode **alink = &this->BlockNode;
x1 = MAX (0, x1);
y1 = MAX (0, y1);
x2 = MIN (bmapwidth - 1, x2);
y2 = MIN (bmapheight - 1, y2);
for (int y = y1; y <= y2; ++y)
{
for (int x = x1; x <= x2; ++x)
P_CollectConnectedGroups(Sector->PortalGroup, Pos(), Top(), radius, check);
for (int i = -1; i < (int)check.Size(); i++)
{
fixedvec3 pos = i==-1? Pos() : PosRelative(check[i]);
int x1 = GetSafeBlockX(pos.x - radius - bmaporgx);
int x2 = GetSafeBlockX(pos.x + radius - bmaporgx);
int y1 = GetSafeBlockY(pos.y - radius - bmaporgy);
int y2 = GetSafeBlockY(pos.y + radius - bmaporgy);
if (x1 >= bmapwidth || x2 < 0 || y1 >= bmapheight || y2 < 0)
{ // thing is off the map
BlockNode = NULL;
}
else
{ // [RH] Link into every block this actor touches, not just the center one
FBlockNode **alink = &this->BlockNode;
x1 = MAX(0, x1);
y1 = MAX(0, y1);
x2 = MIN(bmapwidth - 1, x2);
y2 = MIN(bmapheight - 1, y2);
for (int y = y1; y <= y2; ++y)
{
FBlockNode **link = &blocklinks[y*bmapwidth + x];
FBlockNode *node = FBlockNode::Create (this, x, y, this->Sector->PortalGroup);
// Link in to block
if ((node->NextActor = *link) != NULL)
for (int x = x1; x <= x2; ++x)
{
(*link)->PrevActor = &node->NextActor;
}
node->PrevActor = link;
*link = node;
FBlockNode **link = &blocklinks[y*bmapwidth + x];
FBlockNode *node = FBlockNode::Create(this, x, y, this->Sector->PortalGroup);
// Link in to actor
node->PrevBlock = alink;
node->NextBlock = NULL;
(*alink) = node;
alink = &node->NextBlock;
// Link in to block
if ((node->NextActor = *link) != NULL)
{
(*link)->PrevActor = &node->NextActor;
}
node->PrevActor = link;
*link = node;
// Link in to actor
node->PrevBlock = alink;
node->NextBlock = NULL;
(*alink) = node;
alink = &node->NextBlock;
}
}
}
}

View file

@ -456,7 +456,7 @@ void AActor::Serialize (FArchive &arc)
if (arc.IsLoading ())
{
touching_sectorlist = NULL;
LinkToWorld (false, NULL, Sector);
LinkToWorld (false, Sector);
AddToHash ();
SetShade (fillcolor);
if (player)

View file

@ -1107,7 +1107,25 @@ void P_CreateLinkedPortals()
}
}
}
//BuildBlockmap();
if (linkedPortals.Size() > 0)
{
// We need to relink all actors that may touch a linked line portal
TThinkerIterator<AActor> it;
AActor *actor;
while ((actor = it.Next()))
{
if (!(actor->flags & MF_NOBLOCKMAP))
{
FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals);
P_CollectConnectedGroups(actor->Sector->PortalGroup, actor->Pos(), actor->Top(), actor->radius, check);
if (check.Size() > 0)
{
actor->UnlinkFromWorld();
actor->LinkToWorld();
}
}
}
}
}
@ -1208,7 +1226,7 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat
retval = true;
}
if (out.method == FPortalGroupArray::PGA_Full3d)
if (out.method == FPortalGroupArray::PGA_Full3d && PortalBlockmap.hasLinkedSectorPortals)
{
groupsToCheck.Clear();
groupsToCheck.Push(startgroup);

View file

@ -5024,9 +5024,7 @@ void A_Weave(AActor *self, int xyspeed, int zspeed, fixed_t xydist, fixed_t zdis
{
self->UnlinkFromWorld ();
self->flags |= MF_NOBLOCKMAP;
// the following 4 lines are for future-proofing this for both interpolation overhaul and line portals.
// For portals we need to calculate the destination including the portal offset
// and for interpolation we need to set the performed movement explicitly, because SetXY cannot do that.
// We need to do portal offsetting here explicitly, because SetXY cannot do that.
newX -= self->X();
newY -= self->Y();
self->SetXY(self->Vec2Offset(newX, newY));