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]; 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() bool VeinGenerator::scan_tiles()
{ {
for (int x = 0; x < size.x; x++) for (int x = 0; x < size.x; x++)
@ -669,8 +718,10 @@ bool VeinGenerator::scan_tiles()
{ {
df::coord2d column(x,y); df::coord2d column(x,y);
int top = findTopBlock(map, x, y);
// First find where layers start and end // 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)); Block *b = map.BlockAt(df::coord(x,y,z));
if (!b || !b->is_valid()) if (!b || !b->is_valid())
@ -684,7 +735,7 @@ bool VeinGenerator::scan_tiles()
return false; return false;
// Collect tile data // 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)); Block *b = map.BlockAt(df::coord(x,y,z));
if (!b || !b->is_valid()) 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 &bottom = col_info.bottom_layer[x][y];
auto ttype = b->baseTiletypeAt(tile); auto ttype = b->baseTiletypeAt(tile);
bool obsidian = (tileMaterial(ttype) == tiletype_material::LAVA_STONE); bool obsidian = isTransientMaterial(ttype);
if (top_solid < 0 && !obsidian && isWallTerrain(ttype)) if (top_solid < 0 && !obsidian && isWallTerrain(ttype))
top_solid = z; top_solid = z;
@ -974,7 +1025,9 @@ void VeinGenerator::write_tiles()
{ {
df::coord2d column(x,y); 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)); Block *b = map.BlockAt(df::coord(x,y,z));
if (!b || !b->is_valid()) if (!b || !b->is_valid())