Skip to content

Commit

Permalink
Fixed|World|Sector|Client: Crashes in various Hexen maps when mapping…
Browse files Browse the repository at this point in the history
… sector planes

The Hexen IWAD is littered with maps containing severely broken map
geometry, such as one-sided line constructs facing outward into the
void. If such a construct partly forms a convex subspace this will
produce a non-degenerate BSP leaf and which may be "attached" to the
back of otherwise valid geometry.

Unfortunately we can't simply remove such geometries from the map at
load time because the playsim may depend on their presence to ensure
that line specials (for example) work correctly. Consequently these
must be tolerated and carefully working around them.

If such a construct is encountered when classifying sector clusters
for visual plane mapping, the cluster should be marked such that all
mapping is canceled. The assumption being that if the map author did
intend to use a map hack here then they would fixed the geometry in
any case.
  • Loading branch information
danij-deng committed Sep 21, 2013
1 parent 7a935b3 commit fa7d1fd
Showing 1 changed file with 52 additions and 49 deletions.
101 changes: 52 additions & 49 deletions doomsday/client/src/world/sectorcluster.cpp
Expand Up @@ -252,62 +252,65 @@ DENG2_OBSERVES(Plane, HeightChange)
continue;

// This edge defines a section of a map line.
if(hedge->twin().hasFace())

// If a back geometry is missing then never map planes.
if(!hedge->twin().hasFace())
{
BspLeaf const &backLeaf = hedge->twin().face().mapElement()->as<BspLeaf>();
Cluster const *backCluster = backLeaf.hasCluster()? &backLeaf.cluster() : 0;

if(backCluster != thisPublic)
{
LineSideSegment const &seg = hedge->mapElement()->as<LineSideSegment>();
if(!seg.line().isSelfReferencing())
{
flags &= ~AllSelfRef;

LineSide const &frontSide = seg.lineSide();
if(frontSide.bottom().hasMaterial() &&
!frontSide.bottom().hasFixMaterial())
{
flags &= ~AllMissingBottom;
}

if(frontSide.top().hasMaterial() &&
!frontSide.top().hasFixMaterial())
{
flags &= ~AllMissingTop;
}

if(hedge->twin().mapElement())
{
LineSide const &backSide = hedge->twin().mapElement()->as<LineSideSegment>().lineSide();
if(backCluster->floor().height() < self.sector().floor().height() &&
backSide.bottom().hasMaterial() && !backSide.bottom().hasFixMaterial())
{
flags &= ~AllMissingBottom;
}

if(backCluster->ceiling().height() > self.sector().ceiling().height() &&
backSide.top().hasMaterial() && !backSide.top().hasFixMaterial())
{
flags &= ~AllMissingTop;
}
}
}
else
{
flags |= PartSelfRef;
}
}
flags |= NeverMapped;
flags &= ~(PartSelfRef|AllSelfRef|AllMissingBottom|AllMissingTop);
return flags;
}
else

BspLeaf const &backLeaf = hedge->twin().face().mapElement()->as<BspLeaf>();
Cluster const *backCluster = backLeaf.hasCluster()? &backLeaf.cluster() : 0;

// Cluster internal edges are not considered.
if(backCluster == thisPublic)
continue;

LineSide const &frontSide = hedge->mapElement()->as<LineSideSegment>().lineSide();
LineSide const &backSide = hedge->twin().mapElement()->as<LineSideSegment>().lineSide();

// Similarly if no sections are defined for either side then
// never map planes. This can happen due to mapping errors
// where a group of one-sided lines facing outward in the
// void partly form a convex subspace.
if(!frontSide.hasSections() || !backSide.hasSections())
{
// If a back geometry is missing then never map planes.
flags |= NeverMapped;
flags &= ~(PartSelfRef|AllSelfRef|AllMissingBottom|AllMissingTop);

// We're done.
return flags;
}

if(frontSide.line().isSelfReferencing())
{
flags |= PartSelfRef;
continue;
}

flags &= ~AllSelfRef;

if(frontSide.bottom().hasMaterial() && !frontSide.bottom().hasFixMaterial())
{
flags &= ~AllMissingBottom;
}

if(frontSide.top().hasMaterial() && !frontSide.top().hasFixMaterial())
{
flags &= ~AllMissingTop;
}

if(backCluster->floor().height() < self.sector().floor().height() &&
backSide.bottom().hasMaterial() && !backSide.bottom().hasFixMaterial())
{
flags &= ~AllMissingBottom;
}

if(backCluster->ceiling().height() > self.sector().ceiling().height() &&
backSide.top().hasMaterial() && !backSide.top().hasFixMaterial())
{
flags &= ~AllMissingTop;
}
} while((hedge = &hedge->next()) != base);
}
}
Expand Down

0 comments on commit fa7d1fd

Please sign in to comment.