mirror of
https://github.com/GabsPuNs/Project-Zenith-Main.git
synced 2026-05-22 02:35:26 +00:00
1405 lines
34 KiB
C++
1405 lines
34 KiB
C++
#include "stdafx.h"
|
|
#include "net.minecraft.world.level.levelgen.structure.h"
|
|
#include "net.minecraft.world.level.h"
|
|
#include "net.minecraft.world.level.tile.h"
|
|
#include "net.minecraft.world.level.material.h"
|
|
#include "net.minecraft.world.level.tile.entity.h"
|
|
#include "net.minecraft.world.entity.h"
|
|
#include "net.minecraft.world.entity.monster.h"
|
|
#include "net.minecraft.world.entity.npc.h"
|
|
#include "WeighedTreasure.h"
|
|
#include "StructurePiece.h"
|
|
#include "BoundingBox.h"
|
|
#include "Direction.h"
|
|
#include "JavaMath.h"
|
|
#include "Facing.h"
|
|
#include "DoorItem.h"
|
|
#include "EnchantedBookItem.h"
|
|
|
|
/**
|
|
*
|
|
* A structure piece is a construction or room, located somewhere in the world
|
|
* with a given orientatino (out of Direction.java). Structure pieces have a
|
|
* bounding box that says where the piece is located and its bounds, and the
|
|
* orientation is used to translate local coordinates into world coordinates.
|
|
* <p>
|
|
* The default orientation is Direction.UNDEFINED, in which case no translation
|
|
* will occur. If the orientation is Direction::NORTH, coordinate (0, 0, 0) will
|
|
* be at (boundingBox.x0, boundingBox.y0, boundingBox.z1). In other words, (1,
|
|
* 1, 1) will be translated to (boundingBox.x0 + 1, boundingBox.y0 + 1,
|
|
* boundingBox.z1 - 1).
|
|
* <p>
|
|
* When using Direction::SOUTH, the x coordinate will be the same, and the z
|
|
* coordinate will be flipped. In other words, the bounding box is NOT rotated!
|
|
* It is only flipped along the z axis. Also note that the bounding box is in
|
|
* world coordinates, so the local drawing must never reach outside of this.
|
|
* <p>
|
|
* When using east and west coordinates, the local z coordinate will be swapped
|
|
* with the local x coordinate. For example, (0, 0, 0) is (boundingBox.z1,
|
|
* boundingBox.y0, boundingBox.z0), and (1, 1, 1) becomes (boundingBox.x1 - 1,
|
|
* boundingBox.y0 + 1, boundingBox.z0 + 1) when using Direction::WEST.
|
|
* <p>
|
|
* When-ever a structure piece is placing blocks, it is VERY IMPORTANT to always
|
|
* make sure that all getTile and setTile calls are within the chunk's bounding
|
|
* box. Failing to check this will cause the level generator to create new
|
|
* chunks, leading to infinite loops and other errors.
|
|
*/
|
|
|
|
StructurePiece::StructurePiece()
|
|
{
|
|
boundingBox = nullptr;
|
|
orientation = 0;
|
|
genDepth = 0;
|
|
dirty = false;
|
|
// for reflection
|
|
}
|
|
|
|
StructurePiece::StructurePiece( int genDepth )
|
|
{
|
|
boundingBox = nullptr;
|
|
this->genDepth = genDepth;
|
|
orientation = Direction::UNDEFINED;
|
|
}
|
|
|
|
StructurePiece::~StructurePiece()
|
|
{
|
|
if(boundingBox != nullptr) delete boundingBox;
|
|
}
|
|
|
|
CompoundTag *StructurePiece::createTag()
|
|
{
|
|
CompoundTag *tag = new CompoundTag();
|
|
|
|
return tag;
|
|
}
|
|
|
|
void StructurePiece::write(DataOutputStream *dos)
|
|
{
|
|
wstring encodeId = StructureFeatureIO::getEncodeId(this);
|
|
dos->writeUTF(encodeId);
|
|
boundingBox->write(dos);
|
|
dos->writeInt(orientation);
|
|
dos->writeInt(genDepth);
|
|
addAdditionalSaveData(dos);
|
|
}
|
|
|
|
void StructurePiece::load(Level *level, DataInputStream *dis)
|
|
{
|
|
boundingBox = new BoundingBox();
|
|
boundingBox->read(dis);
|
|
|
|
orientation = dis->readInt();
|
|
genDepth = dis->readInt();
|
|
|
|
readAdditonalSaveData(dis);
|
|
}
|
|
|
|
void StructurePiece::addChildren( StructurePiece* startPiece, list< StructurePiece* > *pieces, Random* random )
|
|
{
|
|
}
|
|
|
|
BoundingBox* StructurePiece::getBoundingBox()
|
|
{
|
|
return boundingBox;
|
|
}
|
|
|
|
int StructurePiece::getGenDepth()
|
|
{
|
|
return genDepth;
|
|
}
|
|
|
|
bool StructurePiece::isInChunk( ChunkPos* pos )
|
|
{
|
|
int cx = ( pos->x << 4 );
|
|
int cz = ( pos->z << 4 );
|
|
|
|
return boundingBox->intersects( cx, cz, cx + 15, cz + 15 );
|
|
}
|
|
|
|
StructurePiece* StructurePiece::findCollisionPiece( list< StructurePiece* > *pieces, BoundingBox* box )
|
|
{
|
|
for (auto& piece : *pieces)
|
|
{
|
|
if ( piece && piece->getBoundingBox() && piece->getBoundingBox()->intersects( box ) )
|
|
{
|
|
return piece;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// 4J-PB - Added from 1.2.3
|
|
TilePos *StructurePiece::getLocatorPosition()
|
|
{
|
|
return new TilePos(boundingBox->getXCenter(), boundingBox->getYCenter(), boundingBox->getZCenter());
|
|
}
|
|
|
|
bool StructurePiece::edgesLiquid( Level* level, BoundingBox* chunkBB )
|
|
{
|
|
int x0 = Math::_max( boundingBox->x0 - 1, chunkBB->x0 );
|
|
int y0 = Math::_max( boundingBox->y0 - 1, chunkBB->y0 );
|
|
int z0 = Math::_max( boundingBox->z0 - 1, chunkBB->z0 );
|
|
int x1 = Math::_min( boundingBox->x1 + 1, chunkBB->x1 );
|
|
int y1 = Math::_min( boundingBox->y1 + 1, chunkBB->y1 );
|
|
int z1 = Math::_min( boundingBox->z1 + 1, chunkBB->z1 );
|
|
|
|
// roof and floor
|
|
for ( int x = x0; x <= x1; x++ )
|
|
{
|
|
for ( int z = z0; z <= z1; z++ )
|
|
{
|
|
int tile = level->getTile( x, y0, z );
|
|
if ( tile > 0 && Tile::tiles[tile]->material->isLiquid() )
|
|
{
|
|
return true;
|
|
}
|
|
tile = level->getTile( x, y1, z );
|
|
if ( tile > 0 && Tile::tiles[tile]->material->isLiquid() )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// north and south
|
|
for ( int x = x0; x <= x1; x++ )
|
|
{
|
|
for ( int y = y0; y <= y1; y++ )
|
|
{
|
|
int tile = level->getTile( x, y, z0 );
|
|
if ( tile > 0 && Tile::tiles[tile]->material->isLiquid() )
|
|
{
|
|
return true;
|
|
}
|
|
tile = level->getTile( x, y, z1 );
|
|
if ( tile > 0 && Tile::tiles[tile]->material->isLiquid() )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// east and west
|
|
for ( int z = z0; z <= z1; z++ )
|
|
{
|
|
for ( int y = y0; y <= y1; y++ )
|
|
{
|
|
int tile = level->getTile( x0, y, z );
|
|
if ( tile > 0 && Tile::tiles[tile]->material->isLiquid() )
|
|
{
|
|
return true;
|
|
}
|
|
tile = level->getTile( x1, y, z );
|
|
if ( tile > 0 && Tile::tiles[tile]->material->isLiquid() )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
int StructurePiece::getWorldX( int x, int z )
|
|
{
|
|
switch ( orientation )
|
|
{
|
|
case Direction::NORTH:
|
|
case Direction::SOUTH:
|
|
return boundingBox->x0 + x;
|
|
case Direction::WEST:
|
|
return boundingBox->x1 - z;
|
|
case Direction::EAST:
|
|
return boundingBox->x0 + z;
|
|
default:
|
|
return x;
|
|
}
|
|
}
|
|
|
|
int StructurePiece::getWorldY( int y )
|
|
{
|
|
if ( orientation == Direction::UNDEFINED )
|
|
{
|
|
return y;
|
|
}
|
|
return y + boundingBox->y0;
|
|
}
|
|
|
|
int StructurePiece::getWorldZ( int x, int z )
|
|
{
|
|
switch ( orientation )
|
|
{
|
|
case Direction::NORTH:
|
|
return boundingBox->z1 - z;
|
|
case Direction::SOUTH:
|
|
return boundingBox->z0 + z;
|
|
case Direction::WEST:
|
|
case Direction::EAST:
|
|
return boundingBox->z0 + x;
|
|
default:
|
|
return z;
|
|
}
|
|
}
|
|
|
|
int StructurePiece::getOrientationData( int tile, int data )
|
|
{
|
|
if ( tile == Tile::rail->id )
|
|
{
|
|
if ( orientation == Direction::WEST || orientation == Direction::EAST )
|
|
{
|
|
if ( data == BaseRailTile::DIR_FLAT_X )
|
|
{
|
|
return BaseRailTile::DIR_FLAT_Z;
|
|
}
|
|
else
|
|
{
|
|
return BaseRailTile::DIR_FLAT_X;
|
|
}
|
|
}
|
|
}
|
|
else if ( tile == Tile::door_wood_Id || tile == Tile::door_iron_Id )
|
|
{
|
|
if ( orientation == Direction::SOUTH )
|
|
{
|
|
if ( data == 0 )
|
|
{
|
|
return 2;
|
|
}
|
|
if ( data == 2 )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else if ( orientation == Direction::WEST )
|
|
{
|
|
// 0 = 1
|
|
// 1 = 2
|
|
// 2 = 3
|
|
// 3 = 0
|
|
return ( data + 1 ) & 3;
|
|
}
|
|
else if ( orientation == Direction::EAST )
|
|
{
|
|
// 0 = 3
|
|
// 1 = 0
|
|
// 2 = 1
|
|
// 3 = 2
|
|
return ( data + 3 ) & 3;
|
|
}
|
|
}
|
|
else if ( tile == Tile::stairs_stone_Id || tile == Tile::stairs_wood_Id || tile == Tile::stairs_netherBricks_Id || tile == Tile::stairs_stoneBrick_Id || tile == Tile::stairs_sandstone_Id)
|
|
{
|
|
if ( orientation == Direction::SOUTH )
|
|
{
|
|
if ( data == 2 )
|
|
{
|
|
return 3;
|
|
}
|
|
if ( data == 3 )
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
else if ( orientation == Direction::WEST )
|
|
{
|
|
if ( data == 0 )
|
|
{
|
|
return 2;
|
|
}
|
|
if ( data == 1 )
|
|
{
|
|
return 3;
|
|
}
|
|
if ( data == 2 )
|
|
{
|
|
return 0;
|
|
}
|
|
if ( data == 3 )
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
else if ( orientation == Direction::EAST )
|
|
{
|
|
if ( data == 0 )
|
|
{
|
|
return 2;
|
|
}
|
|
if ( data == 1 )
|
|
{
|
|
return 3;
|
|
}
|
|
if ( data == 2 )
|
|
{
|
|
return 1;
|
|
}
|
|
if ( data == 3 )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else if ( tile == Tile::ladder->id )
|
|
{
|
|
if ( orientation == Direction::SOUTH )
|
|
{
|
|
if ( data == Facing::NORTH )
|
|
{
|
|
return Facing::SOUTH;
|
|
}
|
|
if ( data == Facing::SOUTH )
|
|
{
|
|
return Facing::NORTH;
|
|
}
|
|
}
|
|
else if ( orientation == Direction::WEST )
|
|
{
|
|
if ( data == Facing::NORTH )
|
|
{
|
|
return Facing::WEST;
|
|
}
|
|
if ( data == Facing::SOUTH )
|
|
{
|
|
return Facing::EAST;
|
|
}
|
|
if ( data == Facing::WEST )
|
|
{
|
|
return Facing::NORTH;
|
|
}
|
|
if ( data == Facing::EAST )
|
|
{
|
|
return Facing::SOUTH;
|
|
}
|
|
}
|
|
else if ( orientation == Direction::EAST )
|
|
{
|
|
if ( data == Facing::NORTH )
|
|
{
|
|
return Facing::EAST;
|
|
}
|
|
if ( data == Facing::SOUTH )
|
|
{
|
|
return Facing::WEST;
|
|
}
|
|
if ( data == Facing::WEST )
|
|
{
|
|
return Facing::NORTH;
|
|
}
|
|
if ( data == Facing::EAST )
|
|
{
|
|
return Facing::SOUTH;
|
|
}
|
|
}
|
|
|
|
}
|
|
else if ( tile == Tile::button->id )
|
|
{
|
|
if ( orientation == Direction::SOUTH )
|
|
{
|
|
if ( data == 3 )
|
|
{
|
|
return 4;
|
|
}
|
|
if ( data == 4 )
|
|
{
|
|
return 3;
|
|
}
|
|
}
|
|
else if ( orientation == Direction::WEST )
|
|
{
|
|
if ( data == 3 )
|
|
{
|
|
return 1;
|
|
}
|
|
if ( data == 4 )
|
|
{
|
|
return 2;
|
|
}
|
|
if ( data == 2 )
|
|
{
|
|
return 3;
|
|
}
|
|
if ( data == 1 )
|
|
{
|
|
return 4;
|
|
}
|
|
}
|
|
else if ( orientation == Direction::EAST )
|
|
{
|
|
if ( data == 3 )
|
|
{
|
|
return 2;
|
|
}
|
|
if ( data == 4 )
|
|
{
|
|
return 1;
|
|
}
|
|
if ( data == 2 )
|
|
{
|
|
return 3;
|
|
}
|
|
if ( data == 1 )
|
|
{
|
|
return 4;
|
|
}
|
|
}
|
|
}
|
|
else if (tile == Tile::tripWireSource_Id || (Tile::tiles[tile] != nullptr && dynamic_cast<DirectionalTile *>(Tile::tiles[tile])))
|
|
{
|
|
if (orientation == Direction::SOUTH)
|
|
{
|
|
if (data == Direction::SOUTH || data == Direction::NORTH)
|
|
{
|
|
return Direction::DIRECTION_OPPOSITE[data];
|
|
}
|
|
}
|
|
else if (orientation == Direction::WEST)
|
|
{
|
|
if (data == Direction::NORTH)
|
|
{
|
|
return Direction::WEST;
|
|
}
|
|
if (data == Direction::SOUTH)
|
|
{
|
|
return Direction::EAST;
|
|
}
|
|
if (data == Direction::WEST)
|
|
{
|
|
return Direction::NORTH;
|
|
}
|
|
if (data == Direction::EAST)
|
|
{
|
|
return Direction::SOUTH;
|
|
}
|
|
}
|
|
else if (orientation == Direction::EAST)
|
|
{
|
|
if (data == Direction::NORTH)
|
|
{
|
|
return Direction::EAST;
|
|
}
|
|
if (data == Direction::SOUTH)
|
|
{
|
|
return Direction::WEST;
|
|
}
|
|
if (data == Direction::WEST)
|
|
{
|
|
return Direction::NORTH;
|
|
}
|
|
if (data == Direction::EAST)
|
|
{
|
|
return Direction::SOUTH;
|
|
}
|
|
}
|
|
}
|
|
else if (tile == Tile::pistonBase_Id || tile == Tile::pistonStickyBase_Id || tile == Tile::lever_Id || tile == Tile::dispenser_Id)
|
|
{
|
|
if (orientation == Direction::SOUTH)
|
|
{
|
|
if (data == Facing::NORTH || data == Facing::SOUTH)
|
|
{
|
|
return Facing::OPPOSITE_FACING[data];
|
|
}
|
|
}
|
|
else if (orientation == Direction::WEST)
|
|
{
|
|
if (data == Facing::NORTH)
|
|
{
|
|
return Facing::WEST;
|
|
}
|
|
if (data == Facing::SOUTH)
|
|
{
|
|
return Facing::EAST;
|
|
}
|
|
if (data == Facing::WEST)
|
|
{
|
|
return Facing::NORTH;
|
|
}
|
|
if (data == Facing::EAST)
|
|
{
|
|
return Facing::SOUTH;
|
|
}
|
|
} else if (orientation == Direction::EAST)
|
|
{
|
|
if (data == Facing::NORTH)
|
|
{
|
|
return Facing::EAST;
|
|
}
|
|
if (data == Facing::SOUTH)
|
|
{
|
|
return Facing::WEST;
|
|
}
|
|
if (data == Facing::WEST)
|
|
{
|
|
return Facing::NORTH;
|
|
}
|
|
if (data == Facing::EAST)
|
|
{
|
|
return Facing::SOUTH;
|
|
}
|
|
}
|
|
}
|
|
return data;
|
|
|
|
}
|
|
|
|
void StructurePiece::placeBlock( Level* level, int block, int data, int x, int y, int z, BoundingBox* chunkBB )
|
|
{
|
|
int worldX = getWorldX( x, z );
|
|
int worldY = getWorldY( y );
|
|
int worldZ = getWorldZ( x, z );
|
|
|
|
if ( !chunkBB->isInside( worldX, worldY, worldZ ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 4J Stu - We shouldn't be removing bedrock when generating things (eg in SuperFlat)
|
|
if(worldY == 0) return;
|
|
|
|
level->setTileAndData( worldX, worldY, worldZ, block, data, Tile::UPDATE_CLIENTS);
|
|
}
|
|
|
|
|
|
/**
|
|
* The purpose of this method is to wrap the getTile call on Level, in order
|
|
* to prevent the level from generating chunks that shouldn't be loaded yet.
|
|
* Returns 0 if the call is out of bounds.
|
|
*
|
|
* @param level
|
|
* @param x
|
|
* @param y
|
|
* @param z
|
|
* @param chunkPosition
|
|
* @return
|
|
*/
|
|
int StructurePiece::getBlock( Level* level, int x, int y, int z, BoundingBox* chunkBB )
|
|
{
|
|
int worldX = getWorldX( x, z );
|
|
int worldY = getWorldY( y );
|
|
int worldZ = getWorldZ( x, z );
|
|
|
|
if ( !chunkBB->isInside( worldX, worldY, worldZ ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return level->getTile( worldX, worldY, worldZ );
|
|
}
|
|
|
|
void StructurePiece::generateAirBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1)
|
|
{
|
|
for (int y = y0; y <= y1; y++)
|
|
{
|
|
for (int x = x0; x <= x1; x++)
|
|
{
|
|
for (int z = z0; z <= z1; z++)
|
|
{
|
|
placeBlock(level, 0, 0, x, y, z, chunkBB);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructurePiece::generateBox( Level* level, BoundingBox* chunkBB, int x0, int y0, int z0, int x1, int y1, int z1,
|
|
int edgeTile, int fillTile, bool skipAir )
|
|
{
|
|
for ( int y = y0; y <= y1; y++ )
|
|
{
|
|
for ( int x = x0; x <= x1; x++ )
|
|
{
|
|
for ( int z = z0; z <= z1; z++ )
|
|
{
|
|
|
|
if ( skipAir && getBlock( level, x, y, z, chunkBB ) == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
if ( y == y0 || y == y1 || x == x0 || x == x1 || z == z0 || z == z1 )
|
|
{
|
|
placeBlock( level, edgeTile, 0, x, y, z, chunkBB );
|
|
}
|
|
else
|
|
{
|
|
placeBlock( level, fillTile, 0, x, y, z, chunkBB );
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructurePiece::generateBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, int edgeTile, int edgeData, int fillTile, int fillData, bool skipAir)
|
|
{
|
|
for (int y = y0; y <= y1; y++)
|
|
{
|
|
for (int x = x0; x <= x1; x++)
|
|
{
|
|
for (int z = z0; z <= z1; z++)
|
|
{
|
|
|
|
if (skipAir && getBlock(level, x, y, z, chunkBB) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
if (y == y0 || y == y1 || x == x0 || x == x1 || z == z0 || z == z1)
|
|
{
|
|
placeBlock(level, edgeTile, edgeData, x, y, z, chunkBB);
|
|
}
|
|
else
|
|
{
|
|
placeBlock(level, fillTile, fillData, x, y, z, chunkBB);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructurePiece::generateBox( Level* level, BoundingBox* chunkBB, BoundingBox* boxBB, int edgeTile, int fillTile,
|
|
bool skipAir )
|
|
{
|
|
generateBox( level, chunkBB, boxBB->x0, boxBB->y0, boxBB->z0, boxBB->x1, boxBB->y1, boxBB->z1, edgeTile, fillTile,
|
|
skipAir );
|
|
}
|
|
|
|
void StructurePiece::generateBox( Level* level, BoundingBox* chunkBB, int x0, int y0, int z0, int x1, int y1, int z1,
|
|
bool skipAir, Random* random, StructurePiece::BlockSelector* selector )
|
|
{
|
|
for ( int y = y0; y <= y1; y++ )
|
|
{
|
|
for ( int x = x0; x <= x1; x++ )
|
|
{
|
|
for ( int z = z0; z <= z1; z++ )
|
|
{
|
|
|
|
if ( skipAir && getBlock( level, x, y, z, chunkBB ) == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
selector->next( random, x, y, z, y == y0 || y == y1 || x == x0 || x == x1 || z == z0 || z == z1 );
|
|
placeBlock( level, selector->getNextId(), selector->getNextData(), x, y, z, chunkBB );
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructurePiece::generateBox( Level* level, BoundingBox* chunkBB, BoundingBox* boxBB, bool skipAir, Random* random,
|
|
StructurePiece::BlockSelector* selector )
|
|
{
|
|
generateBox( level, chunkBB, boxBB->x0, boxBB->y0, boxBB->z0, boxBB->x1, boxBB->y1, boxBB->z1, skipAir, random,
|
|
selector );
|
|
}
|
|
|
|
void StructurePiece::generateMaybeBox( Level* level, BoundingBox* chunkBB, Random *random, float probability, int x0,
|
|
int y0, int z0, int x1, int y1, int z1, int edgeTile, int fillTile,
|
|
bool skipAir )
|
|
{
|
|
for ( int y = y0; y <= y1; y++ )
|
|
{
|
|
for ( int x = x0; x <= x1; x++ )
|
|
{
|
|
for ( int z = z0; z <= z1; z++ )
|
|
{
|
|
|
|
if ( random->nextFloat() > probability )
|
|
{
|
|
continue;
|
|
}
|
|
if ( skipAir && getBlock( level, x, y, z, chunkBB ) == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
if ( y == y0 || y == y1 || x == x0 || x == x1 || z == z0 || z == z1 )
|
|
{
|
|
placeBlock( level, edgeTile, 0, x, y, z, chunkBB );
|
|
}
|
|
else
|
|
{
|
|
placeBlock( level, fillTile, 0, x, y, z, chunkBB );
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructurePiece::maybeGenerateBlock( Level* level, BoundingBox* chunkBB, Random *random, float probability, int x,
|
|
int y, int z, int tile, int data )
|
|
{
|
|
if ( random->nextFloat() < probability )
|
|
{
|
|
placeBlock( level, tile, data, x, y, z, chunkBB );
|
|
}
|
|
}
|
|
|
|
void StructurePiece::generateUpperHalfSphere( Level* level, BoundingBox* chunkBB, int x0, int y0, int z0, int x1,
|
|
int y1, int z1, int fillTile, bool skipAir )
|
|
{
|
|
float diagX = static_cast<float>(x1 - x0 + 1);
|
|
float diagY = static_cast<float>(y1 - y0 + 1);
|
|
float diagZ = static_cast<float>(z1 - z0 + 1);
|
|
float cx = x0 + diagX / 2;
|
|
float cz = z0 + diagZ / 2;
|
|
|
|
for ( int y = y0; y <= y1; y++ )
|
|
{
|
|
float normalizedYDistance = static_cast<float>(y - y0) / diagY;
|
|
|
|
for ( int x = x0; x <= x1; x++ )
|
|
{
|
|
float normalizedXDistance = ( float )( x - cx ) / ( diagX * 0.5f );
|
|
|
|
for ( int z = z0; z <= z1; z++ )
|
|
{
|
|
float normalizedZDistance = ( float )( z - cz ) / ( diagZ * 0.5f );
|
|
|
|
if ( skipAir && getBlock( level, x, y, z, chunkBB ) == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
float dist = ( normalizedXDistance * normalizedXDistance ) + ( normalizedYDistance *
|
|
normalizedYDistance ) + ( normalizedZDistance * normalizedZDistance );
|
|
|
|
if ( dist <= 1.05f )
|
|
{
|
|
placeBlock( level, fillTile, 0, x, y, z, chunkBB );
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructurePiece::generateFullSphere( Level* level, BoundingBox* chunkBB, int cx, int cy, int cz, int radius,
|
|
int edgeTile, int edgeData, int fillTile, int fillData, bool skipAir )
|
|
{
|
|
for ( int y = cy - radius; y <= cy + radius; y++ )
|
|
{
|
|
for ( int x = cx - radius; x <= cx + radius; x++ )
|
|
{
|
|
for ( int z = cz - radius; z <= cz + radius; z++ )
|
|
{
|
|
float dx = ( float )( abs( x - cx ) ) + 0.5f;
|
|
float dy = ( float )( abs( y - cy ) ) + 0.5f;
|
|
float dz = ( float )( abs( z - cz ) ) + 0.5f;
|
|
|
|
float dist = sqrtf( dx * dx + dy * dy + dz * dz );
|
|
|
|
if ( !skipAir || getBlock( level, x, y, z, chunkBB ) != 0 )
|
|
{
|
|
if ( fabsf( dist - ( float )radius ) <= 0.5f )
|
|
placeBlock( level, edgeTile, edgeData, x, y, z, chunkBB );
|
|
}
|
|
|
|
if ( ( float ) radius - dist > 0.5f )
|
|
{
|
|
placeBlock( level, fillTile, fillData, x, y, z, chunkBB );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructurePiece::generateAirColumnUp( Level* level, int x, int startY, int z, BoundingBox* chunkBB )
|
|
{
|
|
int worldX = getWorldX( x, z );
|
|
int worldY = getWorldY( startY );
|
|
int worldZ = getWorldZ( x, z );
|
|
|
|
if ( !chunkBB->isInside( worldX, worldY, worldZ ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
while ( !level->isEmptyTile( worldX, worldY, worldZ ) && worldY < Level::maxBuildHeight - 1 )
|
|
{
|
|
level->setTileAndData( worldX, worldY, worldZ, 0, 0, Tile::UPDATE_CLIENTS);
|
|
worldY++;
|
|
}
|
|
}
|
|
|
|
void StructurePiece::generateAirBoxUp( Level* level, int x0, int z0, int x1, int z1, int y, BoundingBox* chunkBB )
|
|
{
|
|
for ( int x = x0; x < x1; ++x )
|
|
{
|
|
for ( int z = z0; z < z1; ++z )
|
|
{
|
|
placeBlock( level, 0, 0, x, y, z, chunkBB );
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructurePiece::fillColumnDown( Level* level, int tile, int tileData, int x, int startY, int z, BoundingBox* chunkBB )
|
|
{
|
|
int worldX = getWorldX( x, z );
|
|
int worldY = getWorldY( startY );
|
|
int worldZ = getWorldZ( x, z );
|
|
|
|
if ( !chunkBB->isInside( worldX, worldY, worldZ ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
while ( ( level->isEmptyTile( worldX, worldY, worldZ ) || level->getMaterial( worldX, worldY, worldZ )->isLiquid() ) && worldY > 1 )
|
|
{
|
|
level->setTileAndData( worldX, worldY, worldZ, tile, tileData, Tile::UPDATE_CLIENTS );
|
|
worldY--;
|
|
}
|
|
}
|
|
|
|
void StructurePiece::fillBoxDown( Level* level, int tileId, int tileData, int x0, int y0, int z0, int x1, int z1, BoundingBox* chunkBB )
|
|
{
|
|
for ( int x = x0; x <= x1; x++ )
|
|
{
|
|
for ( int z = z0; z <= z1; z++ )
|
|
{
|
|
fillColumnDown( level, tileId, tileData, x, y0, z, chunkBB );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool StructurePiece::createChest( Level* level, BoundingBox* chunkBB, Random* random, int x, int y, int z,
|
|
WeighedTreasureArray treasure, int numRolls )
|
|
{
|
|
int worldX = getWorldX( x, z );
|
|
int worldY = getWorldY( y );
|
|
int worldZ = getWorldZ( x, z );
|
|
|
|
if ( chunkBB->isInside( worldX, worldY, worldZ ) )
|
|
{
|
|
if ( level->getTile( worldX, worldY, worldZ ) != Tile::chest->id )
|
|
{
|
|
level->setTileAndData( worldX, worldY, worldZ, Tile::chest->id, 0, Tile::UPDATE_CLIENTS );
|
|
shared_ptr<ChestTileEntity> chest = dynamic_pointer_cast<ChestTileEntity>(level->getTileEntity( worldX, worldY, worldZ ));
|
|
if ( chest != nullptr ) WeighedTreasure::addChestItems( random, treasure, chest, numRolls );
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool StructurePiece::createDispenser(Level *level, BoundingBox *chunkBB, Random *random, int x, int y, int z, int facing, WeighedTreasureArray items, int numRolls)
|
|
{
|
|
int worldX = getWorldX(x, z);
|
|
int worldY = getWorldY(y);
|
|
int worldZ = getWorldZ(x, z);
|
|
|
|
if (chunkBB->isInside(worldX, worldY, worldZ))
|
|
{
|
|
if (level->getTile(worldX, worldY, worldZ) != Tile::dispenser_Id)
|
|
{
|
|
level->setTileAndData(worldX, worldY, worldZ, Tile::dispenser_Id, getOrientationData(Tile::dispenser_Id, facing), Tile::UPDATE_CLIENTS);
|
|
shared_ptr<DispenserTileEntity> dispenser = dynamic_pointer_cast<DispenserTileEntity>(level->getTileEntity(worldX, worldY, worldZ));
|
|
if (dispenser != nullptr) WeighedTreasure::addDispenserItems(random, items, dispenser, numRolls);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int StructurePiece::getBlockDataValue( StructureTable::eBlockDataType type, int tile, int data )
|
|
{
|
|
if ( type == StructureTable::eBlockDataType_Orientation )
|
|
return getOrientationData( tile, data );
|
|
|
|
if ( type == StructureTable::eBlockDataType_Inverted )
|
|
return ~data & 0xF;
|
|
|
|
return data;
|
|
}
|
|
|
|
void StructurePiece::createCrops( Level *level, BoundingBox *chunkBB, Random *random, int x0, int z0, int x1, int z1, int y, int tileId, int minData, int maxData )
|
|
{
|
|
for ( int x = x0; x <= x1; x++ )
|
|
{
|
|
for ( int z = z0; z <= z1; z++ )
|
|
{
|
|
placeBlock( level, tileId, Mth::nextInt( random, minData, maxData ), x, y, z, chunkBB );
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructurePiece::generateStructureFromData( Level *level, BoundingBox *chunkBB, Random *random, StructureTable::StructurePiece *piece, vector<bool> &objectPlacedFlags,
|
|
vector<bool> featureConditions, vector<int> tileOptionRemap, vector<int> &entitySpawnCounts )
|
|
{
|
|
unordered_map<int, bool> failures;
|
|
|
|
int treasureCount = piece->treasure.size();
|
|
WeighedTreasureArray treasureItems;
|
|
|
|
if ( treasureCount > 0 )
|
|
{
|
|
treasureItems = WeighedTreasureArray( treasureCount );
|
|
for ( unsigned int i = 0; i < treasureCount; ++i )
|
|
{
|
|
const StructureTable::TreasureData &t = piece->treasure[i];
|
|
treasureItems[i] = new WeighedTreasure( t.itemId, t.auxValue, t.minCount, t.maxCount, t.weight );
|
|
}
|
|
}
|
|
|
|
for ( unsigned int i = 0; i < piece->structures.size(); ++i )
|
|
{
|
|
StructureTable::StructureData &s = piece->structures[i];
|
|
|
|
bool shouldGenerate = true;
|
|
if ( s.v26.size() == 2 )
|
|
{
|
|
int bitIndex = s.v26[0];
|
|
bool invert = s.v26[1] != 0;
|
|
|
|
if ( bitIndex >= (int)featureConditions.size() )
|
|
{
|
|
shouldGenerate = false;
|
|
}
|
|
else
|
|
{
|
|
bool bit = featureConditions[bitIndex];
|
|
if ( invert )
|
|
{
|
|
if ( bit )
|
|
{
|
|
shouldGenerate = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !bit )
|
|
{
|
|
shouldGenerate = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!s.v27.empty())
|
|
{
|
|
for (unsigned int depIdx = 0; depIdx < s.v27.size(); ++depIdx)
|
|
{
|
|
if (s.id != eGenerateStructure_CheckBlock)
|
|
{
|
|
auto it = failures.find(s.v27[depIdx]);
|
|
if (it != failures.end() && it->second)
|
|
{
|
|
shouldGenerate = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (shouldGenerate && !s.cropAges.empty())
|
|
{
|
|
for (unsigned int exclIdx = 0; exclIdx < s.cropAges.size(); ++exclIdx)
|
|
{
|
|
for (unsigned int remapIdx = 0; remapIdx < tileOptionRemap.size(); ++remapIdx)
|
|
{
|
|
if (s.cropAges[exclIdx] == tileOptionRemap[remapIdx])
|
|
{
|
|
shouldGenerate = false;
|
|
break;
|
|
}
|
|
}
|
|
if (!shouldGenerate) break;
|
|
}
|
|
}
|
|
|
|
if (!shouldGenerate)
|
|
continue;
|
|
|
|
// @Patoke todo: this is broken, please fix
|
|
for (unsigned int remapIdx = 0; remapIdx < tileOptionRemap.size(); ++remapIdx)
|
|
{
|
|
int offsetValue = tileOptionRemap[remapIdx];
|
|
// start
|
|
if (s.startRemap0 == remapIdx) s.x0 += offsetValue;
|
|
if (s.startRemap1 == remapIdx) s.x0 += offsetValue;
|
|
if (s.startRemap2 == remapIdx) s.y0 += offsetValue;
|
|
|
|
// end
|
|
if (s.endRemap0 == remapIdx) s.x1 += offsetValue;
|
|
if (s.endRemap1 == remapIdx) s.x1 += offsetValue;
|
|
if (s.endRemap2 == remapIdx) s.y1 += offsetValue;
|
|
}
|
|
|
|
switch( s.id )
|
|
{
|
|
case eGenerateStructure_Block:
|
|
placeBlock( level, s.tileId, getBlockDataValue( (StructureTable::eBlockDataType)s.dataType, s.tileId, s.data ), s.x0, s.y0, s.z0, chunkBB );
|
|
break;
|
|
|
|
/*
|
|
case eGenerateStructure_maybeGenerateBlock:
|
|
maybeGenerateBlock( level, chunkBB, random, s.probability, s.x0, s.y0, s.z0, s.tileId, s.data );
|
|
break;
|
|
|
|
case eGenerateStructure_AirBox:
|
|
generateAirBox( level, chunkBB, s.x0, s.y0, s.z0, s.x1, s.y1, s.z1 );
|
|
break;
|
|
*/
|
|
|
|
case eGenerateStructure_Box:
|
|
{
|
|
int data0 = getBlockDataValue( (StructureTable::eBlockDataType)s.dataType, s.tileId, s.data );
|
|
int data1 = getBlockDataValue( (StructureTable::eBlockDataType)s.secondDataType, s.secondTileId, s.secondData );
|
|
generateBox( level, chunkBB, s.x0, s.y0, s.z0, s.x1, s.y1, s.z1, s.tileId, data0, s.secondTileId, data1, false );
|
|
break;
|
|
}
|
|
|
|
/*
|
|
case eGenerateStructure_MaybeBox:
|
|
generateMaybeBox( level, chunkBB, random, s.probability, s.x0, s.y0, s.z0, s.x1, s.y1, s.z1, s.tileId, s.data, false );
|
|
break;
|
|
|
|
case eGenerateStructure_UpperHalfSphere:
|
|
generateUpperHalfSphere( level, chunkBB, s.x0, s.y0, s.z0, s.x1, s.y1, s.z1, s.tileId, false );
|
|
break;
|
|
*/
|
|
|
|
case eGenerateStructure_FullSphere:
|
|
{
|
|
int data0 = getBlockDataValue( (StructureTable::eBlockDataType)s.dataType, s.tileId, s.data );
|
|
int data1 = getBlockDataValue( (StructureTable::eBlockDataType)s.secondDataType, s.secondTileId, s.secondData );
|
|
generateFullSphere( level, chunkBB, s.x0, s.y0, s.z0, s.v25[0], s.tileId, data0, s.secondTileId, data1, false );
|
|
break;
|
|
}
|
|
|
|
/*
|
|
case eGenerateStructure_AirColumnUp:
|
|
generateAirColumnUp( level, s.x0, s.y0, s.z0, chunkBB );
|
|
break;
|
|
*/
|
|
|
|
case eGenerateStructure_fillColumnDown:
|
|
{
|
|
int data0 = getBlockDataValue( (StructureTable::eBlockDataType)s.dataType, s.tileId, s.data );
|
|
fillColumnDown( level, s.tileId, data0, s.x0, s.y0, s.z0, chunkBB );
|
|
break;
|
|
}
|
|
|
|
case eGenerateStructure_fillBoxDown:
|
|
{
|
|
int data0 = getBlockDataValue( (StructureTable::eBlockDataType)s.dataType, s.tileId, s.data );
|
|
fillBoxDown( level, s.tileId, data0, s.x0, s.y0, s.z0, s.x1, s.z1, chunkBB );
|
|
break;
|
|
}
|
|
|
|
case eGenerateStructure_generateAirBoxUp:
|
|
generateAirBoxUp( level, s.x0, s.z0, s.x1, s.z1, s.y0, chunkBB );
|
|
break;
|
|
|
|
case eGenerateStructure_Crops:
|
|
{
|
|
if( tileOptionRemap.empty() )
|
|
break;
|
|
if( s.cropAges.size() != 2 )
|
|
break;
|
|
if( piece->cropTiles.empty() )
|
|
break;
|
|
if( s.tileId >= (int)tileOptionRemap.size() )
|
|
break;
|
|
if( s.x0 > s.x1 )
|
|
break;
|
|
|
|
int minCropAge = s.cropAges[0];
|
|
int maxCropAge = s.cropAges[1];
|
|
int remapIdx = tileOptionRemap[s.tileId];
|
|
int cropTileId = ( remapIdx >= (int)piece->cropTiles.size() ) ? piece->cropTiles.back() : piece->cropTiles[remapIdx];
|
|
|
|
createCrops( level, chunkBB, random, s.x0, s.z0, s.x1, s.z1, s.y0, cropTileId, minCropAge, maxCropAge);
|
|
break;
|
|
}
|
|
|
|
case eGenerateStructure_CreateDoor:
|
|
{
|
|
int worldX = getWorldX( s.x0, s.z0 );
|
|
int worldY = getWorldY( s.y0 );
|
|
int worldZ = getWorldZ( s.x0, s.z0 );
|
|
if( chunkBB->isInside( worldX, worldY, worldZ ) )
|
|
{
|
|
int doorData = getBlockDataValue( (StructureTable::eBlockDataType)s.dataType, s.tileId, s.data );
|
|
if( s.tileId == Tile::door_wood_Id )
|
|
{
|
|
DoorItem::place( level, worldX, worldY, worldZ, doorData, Tile::door_wood );
|
|
}
|
|
else
|
|
{
|
|
DoorItem::place( level, worldX, worldY, worldZ, doorData, Tile::door_iron );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case eGenerateStructure_CheckBlock:
|
|
{
|
|
int block = getBlock(level, s.x0, s.y0, s.z0, chunkBB);
|
|
bool match = (block != 0);
|
|
|
|
if (!s.v25.empty() && s.v25[0] == 0)
|
|
{
|
|
match = (block == 0);
|
|
}
|
|
|
|
if (!match)
|
|
{
|
|
if (!s.v27.empty())
|
|
{
|
|
failures[s.v27[0]] = true;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
vector<bool> newObjectPlacedFlags;
|
|
|
|
for ( unsigned int i = 0; i < piece->objects.size(); ++i )
|
|
{
|
|
const StructureTable::ObjectData &o = piece->objects[i];
|
|
|
|
bool process = true;
|
|
if ( (int)objectPlacedFlags.size() == (int)piece->objects.size() )
|
|
{
|
|
process = objectPlacedFlags[i];
|
|
}
|
|
|
|
bool placed = false;
|
|
|
|
if ( process )
|
|
{
|
|
if ( o.id == eGenerateObject_Chest || o.id == eGenerateObject_Dispenser )
|
|
{
|
|
if ( o.canGenEnchantedBooks )
|
|
{
|
|
WeighedTreasure* book = Item::enchantedBook->createForRandomTreasure( random, o.minEnchantedBooks, o.maxEnchantedBooks, o.enchantedBookWeight );
|
|
WeighedTreasureArray treasure = WeighedTreasureArray( treasureCount + 1 );
|
|
|
|
for ( int k = 0; k < treasureCount; k++ )
|
|
{
|
|
treasure[k] = treasureItems[k];
|
|
treasure[treasureCount] = book;
|
|
}
|
|
|
|
int rollOffset = random->nextInt( o.rollWeight );
|
|
if ( o.id == eGenerateObject_Chest )
|
|
{
|
|
placed = createChest( level, chunkBB, random, o.x, o.y, o.z, treasure, o.rollCount + rollOffset );
|
|
}
|
|
else
|
|
{
|
|
placed = createDispenser( level, chunkBB, random, o.x, o.y, o.z, o.dispenserDir, treasure, o.rollCount + rollOffset );
|
|
}
|
|
|
|
delete book;
|
|
}
|
|
else
|
|
{
|
|
int rollOffset = random->nextInt( o.rollWeight );
|
|
if ( o.id == eGenerateObject_Chest )
|
|
{
|
|
placed = createChest( level, chunkBB, random, o.x, o.y, o.z, treasureItems, o.rollCount + rollOffset );
|
|
}
|
|
else
|
|
{
|
|
placed = createDispenser( level, chunkBB, random, o.x, o.y, o.z, o.dispenserDir, treasureItems, o.rollCount + rollOffset );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
newObjectPlacedFlags.push_back( placed );
|
|
}
|
|
|
|
objectPlacedFlags = newObjectPlacedFlags;
|
|
|
|
for ( unsigned int j = 0; j < piece->entities.size(); ++j )
|
|
{
|
|
const StructureTable::EntityData &e = piece->entities[j];
|
|
|
|
if ( j >= entitySpawnCounts.size() )
|
|
{
|
|
entitySpawnCounts.push_back( 0 );
|
|
}
|
|
|
|
spawnEntity( level, chunkBB, e.x, e.y, e.z, (eGenerateEntity)e.id, e.count, const_cast<vector<int>&>( e.professions ), entitySpawnCounts[j] );
|
|
}
|
|
|
|
for (int i = 0; i < treasureItems.length; i++)
|
|
{
|
|
delete treasureItems[i];
|
|
}
|
|
}
|
|
|
|
void StructurePiece::setDirty()
|
|
{
|
|
dirty = true;
|
|
}
|
|
|
|
void StructurePiece::spawnEntity( Level *level, BoundingBox *chunkBB, int x, int y, int z, eGenerateEntity entityType, int count, vector<int> &professions, int &entitySpawnCounts )
|
|
{
|
|
while ( entitySpawnCounts < count )
|
|
{
|
|
int worldX = getWorldX( x, z );
|
|
int worldY = getWorldY( y );
|
|
int worldZ = getWorldZ( x, z );
|
|
|
|
worldX += entitySpawnCounts;
|
|
|
|
if ( !chunkBB->isInside( worldX, worldY, worldZ ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( entityType == eGenerateEntity_Witch )
|
|
{
|
|
setDirty();
|
|
|
|
shared_ptr<Witch> witch = shared_ptr<Witch>( new Witch( level ) );
|
|
witch->moveTo( worldX + 0.5, worldY, worldZ + 0.5, 0, 0 );
|
|
level->addEntity( witch );
|
|
}
|
|
else if ( entityType == eGenerateEntity_Villager )
|
|
{
|
|
int profession = 0;
|
|
if ( !professions.empty() && entitySpawnCounts < professions.size() )
|
|
profession = professions[entitySpawnCounts];
|
|
|
|
setDirty();
|
|
|
|
shared_ptr<Villager> villager = shared_ptr<Villager>( new Villager( level, profession ) );
|
|
villager->moveTo( worldX + 0.5, worldY, worldZ + 0.5, 0, 0 );
|
|
level->addEntity( villager );
|
|
}
|
|
|
|
entitySpawnCounts++;
|
|
}
|
|
}
|
|
|
|
void StructurePiece::getRandomValuesFromDataSet( StructureTable::StructurePiece *piece, Random *random, vector<bool> &stateConditions, vector<int> &placedTiles )
|
|
{
|
|
for ( int i = 0; i < piece->v8; i++ )
|
|
{
|
|
bool value = random->nextBoolean();
|
|
stateConditions.push_back( value );
|
|
}
|
|
|
|
for ( unsigned int i = 0; i < piece->v11.size(); i++ )
|
|
{
|
|
int value = random->nextInt( piece->v11[i] );
|
|
placedTiles.push_back( value );
|
|
}
|
|
}
|
|
|
|
void StructurePiece::addStructurePieceSaveData(DataOutputStream *dos, vector<bool> &objectState, vector<bool> &featureConditions, vector<int> &tileOptionRemap, vector<int> &entitySpawnCounts)
|
|
{
|
|
addBoolSaveData( dos, objectState );
|
|
addBoolSaveData( dos, featureConditions );
|
|
addIntSaveData( dos, tileOptionRemap );
|
|
addIntSaveData( dos, entitySpawnCounts );
|
|
}
|
|
|
|
void StructurePiece::readStructurePieceSaveData(DataInputStream *dis, vector<bool> &objectState, vector<bool> &featureConditions, vector<int> &tileOptionRemap, vector<int> &entitySpawnCounts)
|
|
{
|
|
objectState = readBoolSaveData( dis );
|
|
featureConditions = readBoolSaveData( dis );
|
|
tileOptionRemap = readIntSaveData( dis );
|
|
entitySpawnCounts = readIntSaveData( dis );
|
|
}
|
|
|
|
void StructurePiece::clearDirty()
|
|
{
|
|
dirty = false;
|
|
}
|
|
|
|
bool StructurePiece::isDirty()
|
|
{
|
|
return dirty;
|
|
}
|
|
|
|
void StructurePiece::addBoolSaveData(DataOutputStream *dos, vector<bool> &data)
|
|
{
|
|
wstring outData;
|
|
outData.assign( L"\0" );
|
|
|
|
for ( size_t i = 0; i < data.size(); ++i )
|
|
{
|
|
wostringstream woss;
|
|
woss << boolalpha << data[i];
|
|
|
|
outData.append( woss.str() );
|
|
|
|
if ( i < data.size() - 1 )
|
|
{
|
|
outData.append( L"," );
|
|
}
|
|
}
|
|
|
|
dos->writeUTF( outData );
|
|
}
|
|
|
|
vector<bool> StructurePiece::readBoolSaveData( DataInputStream *dis )
|
|
{
|
|
wstring data = dis->readUTF();
|
|
|
|
vector<wstring> tokens = stringSplit( data, L',' );
|
|
|
|
vector<bool> outData;
|
|
for ( size_t i = 0; i < tokens.size(); ++i )
|
|
{
|
|
wistringstream wiss( tokens[i] );
|
|
bool outVal = false;
|
|
|
|
wiss >> boolalpha >> outVal;
|
|
|
|
outData.push_back( outVal );
|
|
}
|
|
|
|
return outData;
|
|
}
|
|
|
|
void StructurePiece::addIntSaveData(DataOutputStream *dos, vector<int> &data)
|
|
{
|
|
wstring outData;
|
|
outData.assign( L"\0" );
|
|
|
|
for ( size_t i = 0; i < data.size(); ++i )
|
|
{
|
|
wostringstream woss;
|
|
woss << dec << data[i];
|
|
|
|
outData.append( woss.str() );
|
|
|
|
if ( i < data.size() - 1 )
|
|
{
|
|
outData.append( L"," );
|
|
}
|
|
}
|
|
|
|
dos->writeUTF( outData );
|
|
}
|
|
|
|
vector<int> StructurePiece::readIntSaveData(DataInputStream *dis)
|
|
{
|
|
wstring data = dis->readUTF();
|
|
|
|
vector<wstring> tokens = stringSplit( data, L',' );
|
|
|
|
vector<int> outData;
|
|
for ( size_t i = 0; i < tokens.size(); ++i )
|
|
{
|
|
wistringstream wiss( tokens[i] );
|
|
int outVal = 0;
|
|
|
|
wiss >> dec >> outVal;
|
|
|
|
outData.push_back( outVal );
|
|
}
|
|
|
|
return outData;
|
|
} |