tcr/server/src/main/java/server/worldgen/structure/StructureComponent.java

771 lines
26 KiB
Java
Executable file

package server.worldgen.structure;
import java.util.List;
import common.block.Block;
import common.block.Directional;
import common.block.Rotatable;
import common.block.artificial.BlockDoor;
import common.block.tech.BlockButton;
import common.block.tech.BlockDispenser;
import common.block.tech.BlockLever;
import common.block.tech.BlockPistonBase;
import common.block.tech.BlockRail;
import common.init.Blocks;
import common.item.RngLoot;
import common.item.block.ItemDoor;
import common.rng.Random;
import common.rng.WeightedList;
import common.tags.TagObject;
import common.tileentity.TileEntity;
import common.tileentity.TileEntityChest;
import common.tileentity.TileEntityDispenser;
import common.util.BlockPos;
import common.util.Facing;
import common.world.State;
import server.world.WorldServer;
public abstract class StructureComponent
{
protected StructureBoundingBox boundingBox;
/** switches the Coordinate System base off the Bounding Box */
protected Facing coordBaseMode;
/** The type ID of this component. */
protected int componentType;
public StructureComponent()
{
}
protected StructureComponent(int type)
{
this.componentType = type;
}
/**
* Writes structure base data (id, boundingbox, {@link
* game.worldgen.structure.StructureComponent#coordBaseMode coordBase} and {@link
* game.worldgen.structure.StructureComponent#componentType componentType}) to new tag and
* returns it.
*/
public TagObject writeBase()
{
TagObject tag = new TagObject();
tag.setString("id", MapGenStructureIO.getStructureComponentName(this));
tag.setIntArray("BB", this.boundingBox.toIntArray());
tag.setInt("O", this.coordBaseMode == null ? -1 : this.coordBaseMode.getHorizontalIndex());
tag.setInt("GD", this.componentType);
this.writeTags(tag);
return tag;
}
/**
* (abstract) Helper method to write subclass data to tag
*/
protected abstract void writeTags(TagObject tag);
/**
* Reads and sets structure base data (boundingbox, {@link
* game.worldgen.structure.StructureComponent#coordBaseMode coordBase} and {@link
* game.worldgen.structure.StructureComponent#componentType componentType})
*/
public void readBase(WorldServer world, TagObject tag)
{
if (tag.hasIntArray("BB"))
{
this.boundingBox = new StructureBoundingBox(tag.getIntArray("BB"));
}
int i = tag.getInt("O");
this.coordBaseMode = i == -1 ? null : Facing.getHorizontal(i);
this.componentType = tag.getInt("GD");
this.readTags(tag);
}
/**
* (abstract) Helper method to read subclass data from tag
*/
protected abstract void readTags(TagObject tag);
/**
* Initiates construction of the Structure Component picked, at the current Location of StructGen
*/
public void buildComponent(StructureComponent componentIn, List<StructureComponent> listIn, Random rand)
{
}
/**
* second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes Mineshafts at
* the end, it adds Fences...
*/
public abstract boolean addComponentParts(WorldServer worldIn, Random randomIn, StructureBoundingBox structureBoundingBoxIn);
public StructureBoundingBox getBoundingBox()
{
return this.boundingBox;
}
/**
* Returns the component type ID of this component.
*/
public int getComponentType()
{
return this.componentType;
}
/**
* Discover if bounding box can fit within the current bounding box object.
*/
public static StructureComponent findIntersecting(List<StructureComponent> listIn, StructureBoundingBox boundingboxIn)
{
for (StructureComponent structurecomponent : listIn)
{
if (structurecomponent.getBoundingBox() != null && structurecomponent.getBoundingBox().intersectsWith(boundingboxIn))
{
return structurecomponent;
}
}
return null;
}
public BlockPos getBoundingBoxCenter()
{
return new BlockPos(this.boundingBox.getCenter());
}
/**
* checks the entire StructureBoundingBox for Liquids
*/
protected boolean isLiquidInStructureBoundingBox(WorldServer worldIn, StructureBoundingBox boundingboxIn)
{
int i = Math.max(this.boundingBox.minX - 1, boundingboxIn.minX);
int j = Math.max(this.boundingBox.minY - 1, boundingboxIn.minY);
int k = Math.max(this.boundingBox.minZ - 1, boundingboxIn.minZ);
int l = Math.min(this.boundingBox.maxX + 1, boundingboxIn.maxX);
int i1 = Math.min(this.boundingBox.maxY + 1, boundingboxIn.maxY);
int j1 = Math.min(this.boundingBox.maxZ + 1, boundingboxIn.maxZ);
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
for (int k1 = i; k1 <= l; ++k1)
{
for (int l1 = k; l1 <= j1; ++l1)
{
if (worldIn.getState(blockpos$mutableblockpos.set(k1, j, l1)).getBlock().getMaterial().isLiquid())
{
return true;
}
if (worldIn.getState(blockpos$mutableblockpos.set(k1, i1, l1)).getBlock().getMaterial().isLiquid())
{
return true;
}
}
}
for (int i2 = i; i2 <= l; ++i2)
{
for (int k2 = j; k2 <= i1; ++k2)
{
if (worldIn.getState(blockpos$mutableblockpos.set(i2, k2, k)).getBlock().getMaterial().isLiquid())
{
return true;
}
if (worldIn.getState(blockpos$mutableblockpos.set(i2, k2, j1)).getBlock().getMaterial().isLiquid())
{
return true;
}
}
}
for (int j2 = k; j2 <= j1; ++j2)
{
for (int l2 = j; l2 <= i1; ++l2)
{
if (worldIn.getState(blockpos$mutableblockpos.set(i, l2, j2)).getBlock().getMaterial().isLiquid())
{
return true;
}
if (worldIn.getState(blockpos$mutableblockpos.set(l, l2, j2)).getBlock().getMaterial().isLiquid())
{
return true;
}
}
}
return false;
}
protected int getXWithOffset(int x, int z)
{
if (this.coordBaseMode == null)
{
return x;
}
else
{
switch (this.coordBaseMode)
{
case NORTH:
case SOUTH:
return this.boundingBox.minX + x;
case WEST:
return this.boundingBox.maxX - z;
case EAST:
return this.boundingBox.minX + z;
default:
return x;
}
}
}
protected int getYWithOffset(int y)
{
return this.coordBaseMode == null ? y : y + this.boundingBox.minY;
}
protected int getZWithOffset(int x, int z)
{
if (this.coordBaseMode == null)
{
return z;
}
else
{
switch (this.coordBaseMode)
{
case NORTH:
return this.boundingBox.maxZ - z;
case SOUTH:
return this.boundingBox.minZ + z;
case WEST:
case EAST:
return this.boundingBox.minZ + x;
default:
return z;
}
}
}
protected final State getMetadataWithOffset(State state)
{
Block blockIn = state.getBlock();
if (blockIn == Blocks.rail)
{
if (this.coordBaseMode == Facing.WEST || this.coordBaseMode == Facing.EAST)
{
if (state.getValue(BlockRail.SHAPE) == BlockRail.EnumRailDirection.EAST_WEST)
{
return state.withProperty(BlockRail.SHAPE, BlockRail.EnumRailDirection.NORTH_SOUTH);
}
return state.withProperty(BlockRail.SHAPE, BlockRail.EnumRailDirection.EAST_WEST);
}
}
else if (blockIn instanceof Rotatable)
{
Facing meta = state.getValue(Rotatable.FACING);
if (this.coordBaseMode == Facing.SOUTH)
{
if (meta == Facing.NORTH)
{
return state.withProperty(Rotatable.FACING, Facing.SOUTH);
}
if (meta == Facing.SOUTH)
{
return state.withProperty(Rotatable.FACING, Facing.NORTH);
}
}
else if (this.coordBaseMode == Facing.WEST)
{
if (meta == Facing.NORTH)
{
return state.withProperty(Rotatable.FACING, Facing.WEST);
}
if (meta == Facing.SOUTH)
{
return state.withProperty(Rotatable.FACING, Facing.EAST);
}
if (meta == Facing.WEST)
{
return state.withProperty(Rotatable.FACING, Facing.NORTH);
}
if (meta == Facing.EAST)
{
return state.withProperty(Rotatable.FACING, Facing.SOUTH);
}
}
else if (this.coordBaseMode == Facing.EAST)
{
if (meta == Facing.NORTH)
{
return state.withProperty(Rotatable.FACING, Facing.EAST);
}
if (meta == Facing.SOUTH)
{
return state.withProperty(Rotatable.FACING, Facing.WEST);
}
if (meta == Facing.WEST)
{
return state.withProperty(Rotatable.FACING, Facing.NORTH);
}
if (meta == Facing.EAST)
{
return state.withProperty(Rotatable.FACING, Facing.SOUTH);
}
}
}
if (blockIn instanceof BlockButton)
{
Facing meta = state.getValue(BlockButton.FACING);
if (this.coordBaseMode == Facing.SOUTH)
{
if (meta == Facing.SOUTH)
{
return state.withProperty(BlockButton.FACING, Facing.NORTH);
}
if (meta == Facing.NORTH)
{
return state.withProperty(BlockButton.FACING, Facing.SOUTH);
}
}
else if (this.coordBaseMode == Facing.WEST)
{
if (meta == Facing.SOUTH)
{
return state.withProperty(BlockButton.FACING, Facing.EAST);
}
if (meta == Facing.NORTH)
{
return state.withProperty(BlockButton.FACING, Facing.WEST);
}
if (meta == Facing.WEST)
{
return state.withProperty(BlockButton.FACING, Facing.SOUTH);
}
if (meta == Facing.EAST)
{
return state.withProperty(BlockButton.FACING, Facing.NORTH);
}
}
else if (this.coordBaseMode == Facing.EAST)
{
if (meta == Facing.SOUTH)
{
return state.withProperty(BlockButton.FACING, Facing.WEST);
}
if (meta == Facing.NORTH)
{
return state.withProperty(BlockButton.FACING, Facing.EAST);
}
if (meta == Facing.WEST)
{
return state.withProperty(BlockButton.FACING, Facing.SOUTH);
}
if (meta == Facing.EAST)
{
return state.withProperty(BlockButton.FACING, Facing.NORTH);
}
}
}
else if (blockIn instanceof BlockPistonBase || blockIn instanceof BlockDispenser)
{
Facing meta = state.getValue(Directional.FACING);
if (this.coordBaseMode == Facing.SOUTH)
{
if (meta == Facing.NORTH || meta == Facing.SOUTH)
{
return state.withProperty(Directional.FACING, meta.getOpposite());
}
}
else if (this.coordBaseMode == Facing.WEST)
{
if (meta == Facing.NORTH)
{
return state.withProperty(Directional.FACING, Facing.WEST);
}
if (meta == Facing.SOUTH)
{
return state.withProperty(Directional.FACING, Facing.EAST);
}
if (meta == Facing.WEST)
{
return state.withProperty(Directional.FACING, Facing.NORTH);
}
if (meta == Facing.EAST)
{
return state.withProperty(Directional.FACING, Facing.SOUTH);
}
}
else if (this.coordBaseMode == Facing.EAST)
{
if (meta == Facing.NORTH)
{
return state.withProperty(Directional.FACING, Facing.EAST);
}
if (meta == Facing.SOUTH)
{
return state.withProperty(Directional.FACING, Facing.WEST);
}
if (meta == Facing.WEST)
{
return state.withProperty(Directional.FACING, Facing.NORTH);
}
if (meta == Facing.EAST)
{
return state.withProperty(Directional.FACING, Facing.SOUTH);
}
}
}
else if (blockIn instanceof BlockLever)
{
BlockLever.EnumOrientation meta = state.getValue(BlockLever.FACING);
if (this.coordBaseMode == Facing.SOUTH)
{
if (meta == BlockLever.EnumOrientation.NORTH || meta == BlockLever.EnumOrientation.SOUTH)
{
return state.withProperty(BlockLever.FACING, meta == BlockLever.EnumOrientation.NORTH ? BlockLever.EnumOrientation.SOUTH : BlockLever.EnumOrientation.NORTH);
}
}
else if (this.coordBaseMode == Facing.WEST)
{
if (meta == BlockLever.EnumOrientation.NORTH)
{
return state.withProperty(BlockLever.FACING, BlockLever.EnumOrientation.WEST);
}
if (meta == BlockLever.EnumOrientation.SOUTH)
{
return state.withProperty(BlockLever.FACING, BlockLever.EnumOrientation.EAST);
}
if (meta == BlockLever.EnumOrientation.WEST)
{
return state.withProperty(BlockLever.FACING, BlockLever.EnumOrientation.NORTH);
}
if (meta == BlockLever.EnumOrientation.EAST)
{
return state.withProperty(BlockLever.FACING, BlockLever.EnumOrientation.SOUTH);
}
}
else if (this.coordBaseMode == Facing.EAST)
{
if (meta == BlockLever.EnumOrientation.NORTH)
{
return state.withProperty(BlockLever.FACING, BlockLever.EnumOrientation.EAST);
}
if (meta == BlockLever.EnumOrientation.SOUTH)
{
return state.withProperty(BlockLever.FACING, BlockLever.EnumOrientation.WEST);
}
if (meta == BlockLever.EnumOrientation.WEST)
{
return state.withProperty(BlockLever.FACING, BlockLever.EnumOrientation.NORTH);
}
if (meta == BlockLever.EnumOrientation.EAST)
{
return state.withProperty(BlockLever.FACING, BlockLever.EnumOrientation.SOUTH);
}
}
}
return state;
}
protected void setBlockState(WorldServer worldIn, State blockstateIn, int x, int y, int z, StructureBoundingBox boundingboxIn)
{
BlockPos blockpos = new BlockPos(this.getXWithOffset(x, z), this.getYWithOffset(y), this.getZWithOffset(x, z));
if (boundingboxIn.isVecInside(blockpos))
{
worldIn.setState(blockpos, blockstateIn, 2);
}
}
protected State getBlockStateFromPos(WorldServer worldIn, int x, int y, int z, StructureBoundingBox boundingboxIn)
{
int i = this.getXWithOffset(x, z);
int j = this.getYWithOffset(y);
int k = this.getZWithOffset(x, z);
BlockPos blockpos = new BlockPos(i, j, k);
return !boundingboxIn.isVecInside(blockpos) ? Blocks.air.getState() : worldIn.getState(blockpos);
}
/**
* arguments: (World worldObj, StructureBoundingBox structBB, int minX, int minY, int minZ, int maxX, int maxY, int
* maxZ)
*/
protected void fillWithAir(WorldServer worldIn, StructureBoundingBox structurebb, int minX, int minY, int minZ, int maxX, int maxY, int maxZ)
{
for (int i = minY; i <= maxY; ++i)
{
for (int j = minX; j <= maxX; ++j)
{
for (int k = minZ; k <= maxZ; ++k)
{
this.setBlockState(worldIn, Blocks.air.getState(), j, i, k, structurebb);
}
}
}
}
/**
* Fill the given area with the selected blocks
*/
protected void fillWithBlocks(WorldServer worldIn, StructureBoundingBox boundingboxIn, int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, State boundaryBlockState, State insideBlockState, boolean existingOnly)
{
for (int i = yMin; i <= yMax; ++i)
{
for (int j = xMin; j <= xMax; ++j)
{
for (int k = zMin; k <= zMax; ++k)
{
if (!existingOnly || this.getBlockStateFromPos(worldIn, j, i, k, boundingboxIn).getBlock() != Blocks.air)
{
if (i != yMin && i != yMax && j != xMin && j != xMax && k != zMin && k != zMax)
{
this.setBlockState(worldIn, insideBlockState, j, i, k, boundingboxIn);
}
else
{
this.setBlockState(worldIn, boundaryBlockState, j, i, k, boundingboxIn);
}
}
}
}
}
}
/**
* arguments: World worldObj, StructureBoundingBox structBB, int minX, int minY, int minZ, int maxX, int maxY, int
* maxZ, boolean alwaysreplace, Random rand, StructurePieceBlockSelector blockselector
*/
protected void fillWithRandomizedBlocks(WorldServer worldIn, StructureBoundingBox boundingboxIn, int minX, int minY, int minZ, int maxX, int maxY, int maxZ, boolean alwaysReplace, Random rand, StructureComponent.BlockSelector blockselector)
{
for (int i = minY; i <= maxY; ++i)
{
for (int j = minX; j <= maxX; ++j)
{
for (int k = minZ; k <= maxZ; ++k)
{
if (!alwaysReplace || this.getBlockStateFromPos(worldIn, j, i, k, boundingboxIn).getBlock() != Blocks.air)
{
blockselector.selectBlocks(rand, j, i, k, i == minY || i == maxY || j == minX || j == maxX || k == minZ || k == maxZ);
this.setBlockState(worldIn, blockselector.getBlockState(), j, i, k, boundingboxIn);
}
}
}
}
}
protected void func_175805_a(WorldServer worldIn, StructureBoundingBox boundingboxIn, Random rand, float chance, int minX, int minY, int minZ, int maxX, int maxY, int maxZ, State blockstate1, State blockstate2, boolean p_175805_13_)
{
for (int i = minY; i <= maxY; ++i)
{
for (int j = minX; j <= maxX; ++j)
{
for (int k = minZ; k <= maxZ; ++k)
{
if (rand.floatv() <= chance && (!p_175805_13_ || this.getBlockStateFromPos(worldIn, j, i, k, boundingboxIn).getBlock() != Blocks.air))
{
if (i != minY && i != maxY && j != minX && j != maxX && k != minZ && k != maxZ)
{
this.setBlockState(worldIn, blockstate2, j, i, k, boundingboxIn);
}
else
{
this.setBlockState(worldIn, blockstate1, j, i, k, boundingboxIn);
}
}
}
}
}
}
protected void randomlyPlaceBlock(WorldServer worldIn, StructureBoundingBox boundingboxIn, Random rand, float chance, int x, int y, int z, State blockstateIn)
{
if (rand.floatv() < chance)
{
this.setBlockState(worldIn, blockstateIn, x, y, z, boundingboxIn);
}
}
protected void randomlyRareFillWithBlocks(WorldServer worldIn, StructureBoundingBox boundingboxIn, int minX, int minY, int minZ, int maxX, int maxY, int maxZ, State blockstateIn, boolean p_180777_10_)
{
float f = (float)(maxX - minX + 1);
float f1 = (float)(maxY - minY + 1);
float f2 = (float)(maxZ - minZ + 1);
float f3 = (float)minX + f / 2.0F;
float f4 = (float)minZ + f2 / 2.0F;
for (int i = minY; i <= maxY; ++i)
{
float f5 = (float)(i - minY) / f1;
for (int j = minX; j <= maxX; ++j)
{
float f6 = ((float)j - f3) / (f * 0.5F);
for (int k = minZ; k <= maxZ; ++k)
{
float f7 = ((float)k - f4) / (f2 * 0.5F);
if (!p_180777_10_ || this.getBlockStateFromPos(worldIn, j, i, k, boundingboxIn).getBlock() != Blocks.air)
{
float f8 = f6 * f6 + f5 * f5 + f7 * f7;
if (f8 <= 1.05F)
{
this.setBlockState(worldIn, blockstateIn, j, i, k, boundingboxIn);
}
}
}
}
}
}
/**
* Deletes all continuous blocks from selected position upwards. Stops at hitting air.
*/
protected void clearCurrentPositionBlocksUpwards(WorldServer worldIn, int x, int y, int z, StructureBoundingBox structurebb)
{
BlockPos blockpos = new BlockPos(this.getXWithOffset(x, z), this.getYWithOffset(y), this.getZWithOffset(x, z));
if (structurebb.isVecInside(blockpos))
{
while (!worldIn.isAirBlock(blockpos) && blockpos.getY() < 511)
{
worldIn.setState(blockpos, Blocks.air.getState(), 2);
blockpos = blockpos.up();
}
}
}
/**
* Replaces air and liquid from given position downwards. Stops when hitting anything else than air or liquid
*/
protected void replaceAirAndLiquidDownwards(WorldServer worldIn, State blockstateIn, int x, int y, int z, StructureBoundingBox boundingboxIn)
{
int i = this.getXWithOffset(x, z);
int j = this.getYWithOffset(y);
int k = this.getZWithOffset(x, z);
if (boundingboxIn.isVecInside(new BlockPos(i, j, k)))
{
while ((worldIn.isAirBlock(new BlockPos(i, j, k)) || worldIn.getState(new BlockPos(i, j, k)).getBlock().getMaterial().isLiquid()) && j > 1)
{
worldIn.setState(new BlockPos(i, j, k), blockstateIn, 2);
--j;
}
}
}
protected boolean generateChestContents(WorldServer worldIn, StructureBoundingBox boundingBoxIn, Random rand, int x, int y, int z, WeightedList<RngLoot> listIn, int max)
{
BlockPos blockpos = new BlockPos(this.getXWithOffset(x, z), this.getYWithOffset(y), this.getZWithOffset(x, z));
if (boundingBoxIn.isVecInside(blockpos) && worldIn.getState(blockpos).getBlock() != Blocks.chest)
{
State iblockstate = Blocks.chest.getState();
worldIn.setState(blockpos, Blocks.chest.correctFacing(worldIn, blockpos, iblockstate), 2);
TileEntity tileentity = worldIn.getTileEntity(blockpos);
if (tileentity instanceof TileEntityChest)
{
RngLoot.generateChestContents(rand, listIn, (TileEntityChest)tileentity, max);
}
return true;
}
else
{
return false;
}
}
protected boolean generateDispenserContents(WorldServer worldIn, StructureBoundingBox boundingBoxIn, Random rand, int x, int y, int z, Facing dir, WeightedList<RngLoot> listIn, int max)
{
BlockPos blockpos = new BlockPos(this.getXWithOffset(x, z), this.getYWithOffset(y), this.getZWithOffset(x, z));
if (boundingBoxIn.isVecInside(blockpos) && worldIn.getState(blockpos).getBlock() != Blocks.dispenser)
{
worldIn.setState(blockpos, this.getMetadataWithOffset(Blocks.dispenser.getState().withProperty(BlockDispenser.FACING, dir)), 2);
TileEntity tileentity = worldIn.getTileEntity(blockpos);
if (tileentity instanceof TileEntityDispenser)
{
RngLoot.generateDispenserContents(rand, listIn, (TileEntityDispenser)tileentity, max);
}
return true;
}
else
{
return false;
}
}
/**
* Places door on given position
*/
protected void placeDoorCurrentPosition(WorldServer worldIn, StructureBoundingBox boundingBoxIn, Random rand, int x, int y, int z, State state)
{
BlockPos blockpos = new BlockPos(this.getXWithOffset(x, z), this.getYWithOffset(y), this.getZWithOffset(x, z));
if (boundingBoxIn.isVecInside(blockpos))
{
ItemDoor.placeDoor(worldIn, blockpos, state.getValue(BlockDoor.FACING).rotateYCCW(), Blocks.oak_door, true);
}
}
public void func_181138_a(int p_181138_1_, int p_181138_2_, int p_181138_3_)
{
this.boundingBox.offset(p_181138_1_, p_181138_2_, p_181138_3_);
}
public abstract static class BlockSelector
{
protected State blockstate = Blocks.air.getState();
public abstract void selectBlocks(Random rand, int x, int y, int z, boolean p_75062_5_);
public State getBlockState()
{
return this.blockstate;
}
}
}