Fix 3dveins crashing because of trees and malformed biome data.

The sky in the latest versions has uninitialized biome data, which
made the plugin crash on invalid vector index access. Also, trees
on ground may still have wrong geolayer inside them like obsidian.
develop
Alexander Gavrilov 2014-09-05 15:11:13 +04:00
parent cf06dc3503
commit a45438d172
1 changed files with 57 additions and 4 deletions

@ -661,6 +661,55 @@ GeoLayer *VeinGenerator::mapLayer(Block *pb, df::coord2d tile)
return biome->layers[lidx];
}
static bool isTransientMaterial(df::tiletype tile)
{
using namespace df::enums::tiletype_material;
switch (tileMaterial(tile))
{
case AIR:
case LAVA_STONE:
case PLANT:
case ROOT:
case TREE:
case MUSHROOM:
return true;
default:
return false;
}
}
static bool isSkyBlock(Block *b)
{
for (int x = 0; x < 16; x++)
{
for (int y = 0; y < 16; y++)
{
df::coord2d tile(x,y);
auto dsgn = b->DesignationAt(tile);
auto ttype = b->baseTiletypeAt(tile);
if (dsgn.bits.subterranean || !dsgn.bits.light || !isTransientMaterial(ttype))
return false;
}
}
return true;
}
static int findTopBlock(MapCache &map, int x, int y)
{
for (int z = map.maxZ(); z >= 0; z--)
{
Block *b = map.BlockAt(df::coord(x,y,z));
if (b && b->is_valid() && !isSkyBlock(b))
return z;
}
return -1;
}
bool VeinGenerator::scan_tiles()
{
for (int x = 0; x < size.x; x++)
@ -669,8 +718,10 @@ bool VeinGenerator::scan_tiles()
{
df::coord2d column(x,y);
int top = findTopBlock(map, x, y);
// First find where layers start and end
for (int z = map.maxZ(); z >= 0; z--)
for (int z = top; z >= 0; z--)
{
Block *b = map.BlockAt(df::coord(x,y,z));
if (!b || !b->is_valid())
@ -684,7 +735,7 @@ bool VeinGenerator::scan_tiles()
return false;
// Collect tile data
for (int z = map.maxZ(); z >= 0; z--)
for (int z = top; z >= 0; z--)
{
Block *b = map.BlockAt(df::coord(x,y,z));
if (!b || !b->is_valid())
@ -725,7 +776,7 @@ bool VeinGenerator::scan_layer_depth(Block *b, df::coord2d column, int z)
auto &bottom = col_info.bottom_layer[x][y];
auto ttype = b->baseTiletypeAt(tile);
bool obsidian = (tileMaterial(ttype) == tiletype_material::LAVA_STONE);
bool obsidian = isTransientMaterial(ttype);
if (top_solid < 0 && !obsidian && isWallTerrain(ttype))
top_solid = z;
@ -974,7 +1025,9 @@ void VeinGenerator::write_tiles()
{
df::coord2d column(x,y);
for (int z = map.maxZ(); z >= 0; z--)
int top = findTopBlock(map, x, y);
for (int z = top; z >= 0; z--)
{
Block *b = map.BlockAt(df::coord(x,y,z));
if (!b || !b->is_valid())