initial commit

This commit is contained in:
Sen 2025-03-11 00:23:54 +01:00 committed by Sen
parent 3c9ee26b06
commit 22186c33b9
1458 changed files with 282792 additions and 0 deletions

View file

@ -0,0 +1,122 @@
package game.world;
import game.block.Block;
import game.init.BlockRegistry;
import game.init.Blocks;
public class BlockArray {
private int yBase;
private int blocks;
private int ticked;
private char[] data;
private NibbleArray blocklight;
private NibbleArray skylight;
public BlockArray(int y, boolean sky) {
this.yBase = y;
this.data = new char[4096];
this.blocklight = new NibbleArray();
if(sky)
this.skylight = new NibbleArray();
}
public State get(int x, int y, int z) {
State iblockstate = BlockRegistry.STATEMAP.getByValue(this.data[y << 8 | z << 4 | x]);
return iblockstate != null ? iblockstate : Blocks.air.getState();
}
public void set(int x, int y, int z, State state) {
State ostate = this.get(x, y, z);
Block oblock = ostate.getBlock();
Block block = state.getBlock();
if(oblock != Blocks.air) {
--this.blocks;
if(oblock.getTickRandomly())
--this.ticked;
}
if(block != Blocks.air) {
++this.blocks;
if(block.getTickRandomly())
++this.ticked;
}
this.data[y << 8 | z << 4 | x] = (char)BlockRegistry.STATEMAP.get(state);
}
public Block getBlock(int x, int y, int z) {
return this.get(x, y, z).getBlock();
}
public int getMeta(int x, int y, int z) {
State state = this.get(x, y, z);
return state.getBlock().getMetaFromState(state);
}
public boolean isEmpty() {
return this.blocks == 0;
}
public boolean isTicked() {
return this.ticked > 0;
}
public int getY() {
return this.yBase;
}
public void setSky(int x, int y, int z, int value) {
this.skylight.set(x, y, z, value);
}
public int getSky(int x, int y, int z) {
return this.skylight.get(x, y, z);
}
public void setLight(int x, int y, int z, int value) {
this.blocklight.set(x, y, z, value);
}
public int getLight(int x, int y, int z) {
return this.blocklight.get(x, y, z);
}
public void update() {
this.blocks = 0;
this.ticked = 0;
for(int i = 0; i < 16; ++i) {
for(int j = 0; j < 16; ++j) {
for(int k = 0; k < 16; ++k) {
Block block = this.getBlock(i, j, k);
if(block != Blocks.air) {
++this.blocks;
if(block.getTickRandomly())
++this.ticked;
}
}
}
}
}
public char[] getData() {
return this.data;
}
public NibbleArray getBlocklight() {
return this.blocklight;
}
public NibbleArray getSkylight() {
return this.skylight;
}
public void setData(char[] data) {
this.data = data;
}
public void setBlocklight(NibbleArray data) {
this.blocklight = data;
}
public void setSkylight(NibbleArray data) {
this.skylight = data;
}
}

360
java/src/game/world/BlockPos.java Executable file
View file

@ -0,0 +1,360 @@
package game.world;
import java.util.Iterator;
import game.collect.AbstractIterator;
import game.entity.Entity;
public class BlockPos extends Vec3i
{
public static final BlockPos ORIGIN = new BlockPos(0, 0, 0);
private static final int NUM_X_BITS = 1 + 26; // ExtMath.calculateLogBaseTwo(ExtMath.roundUpToPowerOfTwo(World.MAX_SIZE));
private static final int NUM_Z_BITS = NUM_X_BITS;
private static final int NUM_Y_BITS = 64 - NUM_X_BITS - NUM_Z_BITS;
private static final int Y_SHIFT = 0 + NUM_Z_BITS;
private static final int X_SHIFT = Y_SHIFT + NUM_Y_BITS;
private static final long X_MASK = (1L << NUM_X_BITS) - 1L;
private static final long Y_MASK = (1L << NUM_Y_BITS) - 1L;
private static final long Z_MASK = (1L << NUM_Z_BITS) - 1L;
public BlockPos(int x, int y, int z)
{
super(x, y, z);
}
public BlockPos(double x, double y, double z)
{
super(x, y, z);
}
public BlockPos(Entity source)
{
this(source.posX, source.posY, source.posZ);
}
public BlockPos(Vec3 source)
{
this(source.xCoord, source.yCoord, source.zCoord);
}
public BlockPos(Vec3i source)
{
this(source.getX(), source.getY(), source.getZ());
}
/**
* Add the given coordinates to the coordinates of this BlockPos
*/
public BlockPos add(double x, double y, double z)
{
return x == 0.0D && y == 0.0D && z == 0.0D ? this : new BlockPos((double)this.getX() + x, (double)this.getY() + y, (double)this.getZ() + z);
}
/**
* Add the given coordinates to the coordinates of this BlockPos
*/
public BlockPos add(int x, int y, int z)
{
return x == 0 && y == 0 && z == 0 ? this : new BlockPos(this.getX() + x, this.getY() + y, this.getZ() + z);
}
/**
* Add the given Vector to this BlockPos
*/
public BlockPos add(Vec3i vec)
{
return vec.getX() == 0 && vec.getY() == 0 && vec.getZ() == 0 ? this : new BlockPos(this.getX() + vec.getX(), this.getY() + vec.getY(), this.getZ() + vec.getZ());
}
/**
* Subtract the given Vector from this BlockPos
*/
public BlockPos subtract(Vec3i vec)
{
return vec.getX() == 0 && vec.getY() == 0 && vec.getZ() == 0 ? this : new BlockPos(this.getX() - vec.getX(), this.getY() - vec.getY(), this.getZ() - vec.getZ());
}
/**
* Offset this BlockPos 1 block up
*/
public BlockPos up()
{
return this.up(1);
}
/**
* Offset this BlockPos n blocks up
*/
public BlockPos up(int n)
{
return this.offset(Facing.UP, n);
}
/**
* Offset this BlockPos 1 block down
*/
public BlockPos down()
{
return this.down(1);
}
/**
* Offset this BlockPos n blocks down
*/
public BlockPos down(int n)
{
return this.offset(Facing.DOWN, n);
}
/**
* Offset this BlockPos 1 block in northern direction
*/
public BlockPos north()
{
return this.north(1);
}
/**
* Offset this BlockPos n blocks in northern direction
*/
public BlockPos north(int n)
{
return this.offset(Facing.NORTH, n);
}
/**
* Offset this BlockPos 1 block in southern direction
*/
public BlockPos south()
{
return this.south(1);
}
/**
* Offset this BlockPos n blocks in southern direction
*/
public BlockPos south(int n)
{
return this.offset(Facing.SOUTH, n);
}
/**
* Offset this BlockPos 1 block in western direction
*/
public BlockPos west()
{
return this.west(1);
}
/**
* Offset this BlockPos n blocks in western direction
*/
public BlockPos west(int n)
{
return this.offset(Facing.WEST, n);
}
/**
* Offset this BlockPos 1 block in eastern direction
*/
public BlockPos east()
{
return this.east(1);
}
/**
* Offset this BlockPos n blocks in eastern direction
*/
public BlockPos east(int n)
{
return this.offset(Facing.EAST, n);
}
/**
* Offset this BlockPos 1 block in the given direction
*/
public BlockPos offset(Facing facing)
{
return this.offset(facing, 1);
}
/**
* Offsets this BlockPos n blocks in the given direction
*/
public BlockPos offset(Facing facing, int n)
{
return n == 0 ? this : new BlockPos(this.getX() + facing.getFrontOffsetX() * n, this.getY() + facing.getFrontOffsetY() * n, this.getZ() + facing.getFrontOffsetZ() * n);
}
/**
* Calculate the cross product of this and the given Vector
*/
public BlockPos crossProduct(Vec3i vec)
{
return new BlockPos(this.getY() * vec.getZ() - this.getZ() * vec.getY(), this.getZ() * vec.getX() - this.getX() * vec.getZ(), this.getX() * vec.getY() - this.getY() * vec.getX());
}
public long toLong()
{
return ((long)this.getX() & X_MASK) << X_SHIFT | ((long)this.getY() & Y_MASK) << Y_SHIFT | ((long)this.getZ() & Z_MASK) << 0;
}
public static BlockPos fromLong(long serialized)
{
int i = (int)(serialized << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS);
int j = (int)(serialized << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS);
int k = (int)(serialized << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS);
return new BlockPos(i, j, k);
}
public static Iterable<BlockPos> getAllInBox(BlockPos from, BlockPos to)
{
final BlockPos blockpos = new BlockPos(Math.min(from.getX(), to.getX()), Math.min(from.getY(), to.getY()), Math.min(from.getZ(), to.getZ()));
final BlockPos blockpos1 = new BlockPos(Math.max(from.getX(), to.getX()), Math.max(from.getY(), to.getY()), Math.max(from.getZ(), to.getZ()));
return new Iterable<BlockPos>()
{
public Iterator<BlockPos> iterator()
{
return new AbstractIterator<BlockPos>()
{
private BlockPos lastReturned = null;
protected BlockPos computeNext()
{
if (this.lastReturned == null)
{
this.lastReturned = blockpos;
return this.lastReturned;
}
else if (this.lastReturned.equals(blockpos1))
{
return (BlockPos)this.endOfData();
}
else
{
int i = this.lastReturned.getX();
int j = this.lastReturned.getY();
int k = this.lastReturned.getZ();
if (i < blockpos1.getX())
{
++i;
}
else if (j < blockpos1.getY())
{
i = blockpos.getX();
++j;
}
else if (k < blockpos1.getZ())
{
i = blockpos.getX();
j = blockpos.getY();
++k;
}
this.lastReturned = new BlockPos(i, j, k);
return this.lastReturned;
}
}
};
}
};
}
public static Iterable<BlockPos.MutableBlockPos> getAllInBoxMutable(BlockPos from, BlockPos to)
{
final BlockPos blockpos = new BlockPos(Math.min(from.getX(), to.getX()), Math.min(from.getY(), to.getY()), Math.min(from.getZ(), to.getZ()));
final BlockPos blockpos1 = new BlockPos(Math.max(from.getX(), to.getX()), Math.max(from.getY(), to.getY()), Math.max(from.getZ(), to.getZ()));
return new Iterable<BlockPos.MutableBlockPos>()
{
public Iterator<BlockPos.MutableBlockPos> iterator()
{
return new AbstractIterator<BlockPos.MutableBlockPos>()
{
private BlockPos.MutableBlockPos theBlockPos = null;
protected BlockPos.MutableBlockPos computeNext()
{
if (this.theBlockPos == null)
{
this.theBlockPos = new BlockPos.MutableBlockPos(blockpos.getX(), blockpos.getY(), blockpos.getZ());
return this.theBlockPos;
}
else if (this.theBlockPos.equals(blockpos1))
{
return (BlockPos.MutableBlockPos)this.endOfData();
}
else
{
int i = this.theBlockPos.getX();
int j = this.theBlockPos.getY();
int k = this.theBlockPos.getZ();
if (i < blockpos1.getX())
{
++i;
}
else if (j < blockpos1.getY())
{
i = blockpos.getX();
++j;
}
else if (k < blockpos1.getZ())
{
i = blockpos.getX();
j = blockpos.getY();
++k;
}
this.theBlockPos.x = i;
this.theBlockPos.y = j;
this.theBlockPos.z = k;
return this.theBlockPos;
}
}
};
}
};
}
public static final class MutableBlockPos extends BlockPos
{
private int x;
private int y;
private int z;
public MutableBlockPos()
{
this(0, 0, 0);
}
public MutableBlockPos(int x_, int y_, int z_)
{
super(0, 0, 0);
this.x = x_;
this.y = y_;
this.z = z_;
}
public int getX()
{
return this.x;
}
public int getY()
{
return this.y;
}
public int getZ()
{
return this.z;
}
public BlockPos.MutableBlockPos set(int xIn, int yIn, int zIn)
{
this.x = xIn;
this.y = yIn;
this.z = zIn;
return this;
}
}
}

View file

@ -0,0 +1,414 @@
package game.world;
import game.world.HitPosition.ObjectType;
public class BoundingBox
{
public final double minX;
public final double minY;
public final double minZ;
public final double maxX;
public final double maxY;
public final double maxZ;
public BoundingBox(double x1, double y1, double z1, double x2, double y2, double z2)
{
this.minX = Math.min(x1, x2);
this.minY = Math.min(y1, y2);
this.minZ = Math.min(z1, z2);
this.maxX = Math.max(x1, x2);
this.maxY = Math.max(y1, y2);
this.maxZ = Math.max(z1, z2);
}
public BoundingBox(BlockPos pos1, BlockPos pos2)
{
this.minX = (double)pos1.getX();
this.minY = (double)pos1.getY();
this.minZ = (double)pos1.getZ();
this.maxX = (double)pos2.getX();
this.maxY = (double)pos2.getY();
this.maxZ = (double)pos2.getZ();
}
/**
* Adds the coordinates to the bounding box extending it if the point lies outside the current ranges. Args: x, y, z
*/
public BoundingBox addCoord(double x, double y, double z)
{
double d0 = this.minX;
double d1 = this.minY;
double d2 = this.minZ;
double d3 = this.maxX;
double d4 = this.maxY;
double d5 = this.maxZ;
if (x < 0.0D)
{
d0 += x;
}
else if (x > 0.0D)
{
d3 += x;
}
if (y < 0.0D)
{
d1 += y;
}
else if (y > 0.0D)
{
d4 += y;
}
if (z < 0.0D)
{
d2 += z;
}
else if (z > 0.0D)
{
d5 += z;
}
return new BoundingBox(d0, d1, d2, d3, d4, d5);
}
/**
* Returns a bounding box expanded by the specified vector (if negative numbers are given it will shrink). Args: x,
* y, z
*/
public BoundingBox expand(double x, double y, double z)
{
double d0 = this.minX - x;
double d1 = this.minY - y;
double d2 = this.minZ - z;
double d3 = this.maxX + x;
double d4 = this.maxY + y;
double d5 = this.maxZ + z;
return new BoundingBox(d0, d1, d2, d3, d4, d5);
}
public BoundingBox union(BoundingBox other)
{
double d0 = Math.min(this.minX, other.minX);
double d1 = Math.min(this.minY, other.minY);
double d2 = Math.min(this.minZ, other.minZ);
double d3 = Math.max(this.maxX, other.maxX);
double d4 = Math.max(this.maxY, other.maxY);
double d5 = Math.max(this.maxZ, other.maxZ);
return new BoundingBox(d0, d1, d2, d3, d4, d5);
}
/**
* returns an AABB with corners x1, y1, z1 and x2, y2, z2
*/
public static BoundingBox fromBounds(double x1, double y1, double z1, double x2, double y2, double z2)
{
double d0 = Math.min(x1, x2);
double d1 = Math.min(y1, y2);
double d2 = Math.min(z1, z2);
double d3 = Math.max(x1, x2);
double d4 = Math.max(y1, y2);
double d5 = Math.max(z1, z2);
return new BoundingBox(d0, d1, d2, d3, d4, d5);
}
/**
* Offsets the current bounding box by the specified coordinates. Args: x, y, z
*/
public BoundingBox offset(double x, double y, double z)
{
return new BoundingBox(this.minX + x, this.minY + y, this.minZ + z, this.maxX + x, this.maxY + y, this.maxZ + z);
}
/**
* if instance and the argument bounding boxes overlap in the Y and Z dimensions, calculate the offset between them
* in the X dimension. return var2 if the bounding boxes do not overlap or if var2 is closer to 0 then the
* calculated offset. Otherwise return the calculated offset.
*/
public double calculateXOffset(BoundingBox other, double offsetX)
{
if (other.maxY > this.minY && other.minY < this.maxY && other.maxZ > this.minZ && other.minZ < this.maxZ)
{
if (offsetX > 0.0D && other.maxX <= this.minX)
{
double d1 = this.minX - other.maxX;
if (d1 < offsetX)
{
offsetX = d1;
}
}
else if (offsetX < 0.0D && other.minX >= this.maxX)
{
double d0 = this.maxX - other.minX;
if (d0 > offsetX)
{
offsetX = d0;
}
}
return offsetX;
}
else
{
return offsetX;
}
}
/**
* if instance and the argument bounding boxes overlap in the X and Z dimensions, calculate the offset between them
* in the Y dimension. return var2 if the bounding boxes do not overlap or if var2 is closer to 0 then the
* calculated offset. Otherwise return the calculated offset.
*/
public double calculateYOffset(BoundingBox other, double offsetY)
{
if (other.maxX > this.minX && other.minX < this.maxX && other.maxZ > this.minZ && other.minZ < this.maxZ)
{
if (offsetY > 0.0D && other.maxY <= this.minY)
{
double d1 = this.minY - other.maxY;
if (d1 < offsetY)
{
offsetY = d1;
}
}
else if (offsetY < 0.0D && other.minY >= this.maxY)
{
double d0 = this.maxY - other.minY;
if (d0 > offsetY)
{
offsetY = d0;
}
}
return offsetY;
}
else
{
return offsetY;
}
}
/**
* if instance and the argument bounding boxes overlap in the Y and X dimensions, calculate the offset between them
* in the Z dimension. return var2 if the bounding boxes do not overlap or if var2 is closer to 0 then the
* calculated offset. Otherwise return the calculated offset.
*/
public double calculateZOffset(BoundingBox other, double offsetZ)
{
if (other.maxX > this.minX && other.minX < this.maxX && other.maxY > this.minY && other.minY < this.maxY)
{
if (offsetZ > 0.0D && other.maxZ <= this.minZ)
{
double d1 = this.minZ - other.maxZ;
if (d1 < offsetZ)
{
offsetZ = d1;
}
}
else if (offsetZ < 0.0D && other.minZ >= this.maxZ)
{
double d0 = this.maxZ - other.minZ;
if (d0 > offsetZ)
{
offsetZ = d0;
}
}
return offsetZ;
}
else
{
return offsetZ;
}
}
/**
* Returns whether the given bounding box intersects with this one. Args: axisAlignedBB
*/
public boolean intersectsWith(BoundingBox other)
{
return other.maxX > this.minX && other.minX < this.maxX ? (other.maxY > this.minY && other.minY < this.maxY ? other.maxZ > this.minZ && other.minZ < this.maxZ : false) : false;
}
/**
* Returns if the supplied Vec3D is completely inside the bounding box
*/
public boolean isVecInside(Vec3 vec)
{
return vec.xCoord > this.minX && vec.xCoord < this.maxX ? (vec.yCoord > this.minY && vec.yCoord < this.maxY ? vec.zCoord > this.minZ && vec.zCoord < this.maxZ : false) : false;
}
/**
* Returns the average length of the edges of the bounding box.
*/
public double getAverageEdgeLength()
{
double d0 = this.maxX - this.minX;
double d1 = this.maxY - this.minY;
double d2 = this.maxZ - this.minZ;
return (d0 + d1 + d2) / 3.0D;
}
/**
* Returns a bounding box that is inset by the specified amounts
*/
public BoundingBox contract(double x, double y, double z)
{
double d0 = this.minX + x;
double d1 = this.minY + y;
double d2 = this.minZ + z;
double d3 = this.maxX - x;
double d4 = this.maxY - y;
double d5 = this.maxZ - z;
return new BoundingBox(d0, d1, d2, d3, d4, d5);
}
public HitPosition calculateIntercept(Vec3 vecA, Vec3 vecB)
{
Vec3 vec3 = vecA.getIntermediateWithXValue(vecB, this.minX);
Vec3 vec31 = vecA.getIntermediateWithXValue(vecB, this.maxX);
Vec3 vec32 = vecA.getIntermediateWithYValue(vecB, this.minY);
Vec3 vec33 = vecA.getIntermediateWithYValue(vecB, this.maxY);
Vec3 vec34 = vecA.getIntermediateWithZValue(vecB, this.minZ);
Vec3 vec35 = vecA.getIntermediateWithZValue(vecB, this.maxZ);
if (!this.isVecInYZ(vec3))
{
vec3 = null;
}
if (!this.isVecInYZ(vec31))
{
vec31 = null;
}
if (!this.isVecInXZ(vec32))
{
vec32 = null;
}
if (!this.isVecInXZ(vec33))
{
vec33 = null;
}
if (!this.isVecInXY(vec34))
{
vec34 = null;
}
if (!this.isVecInXY(vec35))
{
vec35 = null;
}
Vec3 vec36 = null;
if (vec3 != null)
{
vec36 = vec3;
}
if (vec31 != null && (vec36 == null || vecA.squareDistanceTo(vec31) < vecA.squareDistanceTo(vec36)))
{
vec36 = vec31;
}
if (vec32 != null && (vec36 == null || vecA.squareDistanceTo(vec32) < vecA.squareDistanceTo(vec36)))
{
vec36 = vec32;
}
if (vec33 != null && (vec36 == null || vecA.squareDistanceTo(vec33) < vecA.squareDistanceTo(vec36)))
{
vec36 = vec33;
}
if (vec34 != null && (vec36 == null || vecA.squareDistanceTo(vec34) < vecA.squareDistanceTo(vec36)))
{
vec36 = vec34;
}
if (vec35 != null && (vec36 == null || vecA.squareDistanceTo(vec35) < vecA.squareDistanceTo(vec36)))
{
vec36 = vec35;
}
if (vec36 == null)
{
return null;
}
else
{
Facing enumfacing = null;
if (vec36 == vec3)
{
enumfacing = Facing.WEST;
}
else if (vec36 == vec31)
{
enumfacing = Facing.EAST;
}
else if (vec36 == vec32)
{
enumfacing = Facing.DOWN;
}
else if (vec36 == vec33)
{
enumfacing = Facing.UP;
}
else if (vec36 == vec34)
{
enumfacing = Facing.NORTH;
}
else
{
enumfacing = Facing.SOUTH;
}
return new HitPosition(ObjectType.BLOCK, vec36, enumfacing, BlockPos.ORIGIN);
}
}
/**
* Checks if the specified vector is within the YZ dimensions of the bounding box. Args: Vec3D
*/
private boolean isVecInYZ(Vec3 vec)
{
return vec == null ? false : vec.yCoord >= this.minY && vec.yCoord <= this.maxY && vec.zCoord >= this.minZ && vec.zCoord <= this.maxZ;
}
/**
* Checks if the specified vector is within the XZ dimensions of the bounding box. Args: Vec3D
*/
private boolean isVecInXZ(Vec3 vec)
{
return vec == null ? false : vec.xCoord >= this.minX && vec.xCoord <= this.maxX && vec.zCoord >= this.minZ && vec.zCoord <= this.maxZ;
}
/**
* Checks if the specified vector is within the XY dimensions of the bounding box. Args: Vec3D
*/
private boolean isVecInXY(Vec3 vec)
{
return vec == null ? false : vec.xCoord >= this.minX && vec.xCoord <= this.maxX && vec.yCoord >= this.minY && vec.yCoord <= this.maxY;
}
public String toString()
{
return "box[" + this.minX + ", " + this.minY + ", " + this.minZ + " -> " + this.maxX + ", " + this.maxY + ", " + this.maxZ + "]";
}
public boolean hasNaN()
{
return Double.isNaN(this.minX) || Double.isNaN(this.minY) || Double.isNaN(this.minZ) || Double.isNaN(this.maxX) || Double.isNaN(this.maxY) || Double.isNaN(this.maxZ);
}
}

1199
java/src/game/world/Chunk.java Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,25 @@
package game.world;
public class ChunkCache
{
protected final int chunkX;
protected final int chunkZ;
protected final Chunk[][] chunkArray;
public ChunkCache(World worldIn, BlockPos posFromIn, BlockPos posToIn, int subIn)
{
this.chunkX = posFromIn.getX() - subIn >> 4;
this.chunkZ = posFromIn.getZ() - subIn >> 4;
int i = posToIn.getX() + subIn >> 4;
int j = posToIn.getZ() + subIn >> 4;
this.chunkArray = new Chunk[i - this.chunkX + 1][j - this.chunkZ + 1];
for (int k = this.chunkX; k <= i; ++k)
{
for (int l = this.chunkZ; l <= j; ++l)
{
this.chunkArray[k - this.chunkX][l - this.chunkZ] = worldIn.getChunk(k, l);
}
}
}
}

View file

@ -0,0 +1,34 @@
package game.world;
public class ChunkPos {
public final int x;
public final int z;
public ChunkPos(int x, int z) {
this.x = x;
this.z = z;
}
public int hashCode() {
int i = 1664525 * this.x + 1013904223;
int j = 1664525 * (this.z ^ -559038737) + 1013904223;
return i ^ j;
}
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
else if(!(obj instanceof ChunkPos)) {
return false;
}
else {
ChunkPos pos = (ChunkPos)obj;
return this.x == pos.x && this.z == pos.z;
}
}
public String toString() {
return "[" + this.x + ", " + this.z + "]";
}
}

View file

@ -0,0 +1,151 @@
package game.world;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import game.collect.Iterators;
import game.collect.Lists;
import game.collect.Maps;
public class ClassInheritanceMultiMap<T> extends AbstractSet<T>
{
private static final Set < Class<? >> CLASSES = Collections.newSetFromMap(new ConcurrentHashMap<Class<?>, Boolean>()); // fix exception
private final Map < Class<?>, List<T >> map = Maps. < Class<?>, List<T >> newHashMap();
private final Set < Class<? >> knownKeys = Collections.newSetFromMap(Maps.<Class<?>, Boolean>newIdentityHashMap());
private final Class<T> baseClass;
private final List<T> values = Lists.<T>newArrayList();
public ClassInheritanceMultiMap(Class<T> baseClassIn)
{
this.baseClass = baseClassIn;
this.knownKeys.add(baseClassIn);
this.map.put(baseClassIn, this.values);
for (Class<?> oclass : CLASSES)
{
this.createLookup(oclass);
}
}
protected void createLookup(Class<?> clazz)
{
CLASSES.add(clazz);
for (T t : this.values)
{
if (clazz.isAssignableFrom(t.getClass()))
{
this.addForClass(t, clazz);
}
}
this.knownKeys.add(clazz);
}
protected Class<?> initializeClassLookup(Class<?> clazz)
{
if (this.baseClass.isAssignableFrom(clazz))
{
if (!this.knownKeys.contains(clazz))
{
this.createLookup(clazz);
}
return clazz;
}
else
{
throw new IllegalArgumentException("Don\'t know how to search for " + clazz);
}
}
public boolean add(T p_add_1_)
{
for (Class<?> oclass : this.knownKeys)
{
if (oclass.isAssignableFrom(p_add_1_.getClass()))
{
this.addForClass(p_add_1_, oclass);
}
}
return true;
}
private void addForClass(T value, Class<?> parentClass)
{
List<T> list = (List)this.map.get(parentClass);
if (list == null)
{
this.map.put(parentClass, Lists.newArrayList(value));
}
else
{
list.add(value);
}
}
public boolean remove(Object p_remove_1_)
{
T t = (T)p_remove_1_;
boolean flag = false;
for (Class<?> oclass : this.knownKeys)
{
if (oclass.isAssignableFrom(t.getClass()))
{
List<T> list = (List)this.map.get(oclass);
if (list != null && list.remove(t))
{
flag = true;
}
}
}
return flag;
}
public boolean contains(Object p_contains_1_)
{
return Iterators.contains(this.getByClass(p_contains_1_.getClass()).iterator(), p_contains_1_);
}
public <S> Iterable<S> getByClass(final Class<S> clazz)
{
return new Iterable<S>()
{
public Iterator<S> iterator()
{
List<T> list = (List)ClassInheritanceMultiMap.this.map.get(ClassInheritanceMultiMap.this.initializeClassLookup(clazz));
if (list == null)
{
return Iterators.<S>emptyIterator();
}
else
{
Iterator<T> iterator = list.iterator();
return Iterators.filter(iterator, clazz);
}
}
};
}
public Iterator<T> iterator()
{
return this.values.isEmpty() ? Iterators.<T>emptyIterator() : Iterators.unmodifiableIterator(this.values.iterator());
}
public int size()
{
return this.values.size();
}
}

1346
java/src/game/world/Converter.java Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,98 @@
package game.world;
import java.util.List;
import java.util.function.Predicate;
import game.block.Block;
import game.entity.Entity;
import game.init.Blocks;
import game.tileentity.TileEntity;
public class EmptyChunk extends Chunk {
public EmptyChunk(WorldClient world) {
super(world, 0, 0);
}
public int getHeight(int x, int z) {
return 0;
}
public void genHeights() {
}
public void genSkyLight() {
}
public Block getBlock(BlockPos pos) {
return Blocks.air;
}
public int getOpacity(BlockPos pos) {
return 255;
}
public int getMeta(BlockPos pos) {
return 0;
}
public int getLight(LightType type, BlockPos pos) {
return type.defValue;
}
public void setLight(LightType type, BlockPos pos, int value) {
}
public int getLightSub(BlockPos pos, int amount) {
return 0;
}
public void addEntity(Entity entity) {
}
public void removeEntity(Entity entity) {
}
public boolean canSeeSky(BlockPos pos) {
return false;
}
public TileEntity getTileEntity(BlockPos pos, TileEntity.EnumCreateEntityType type) {
return null;
}
public void addTileEntity(TileEntity tile) {
}
public void addTileEntity(BlockPos pos, TileEntity tile) {
}
public void removeTileEntity(BlockPos pos) {
}
public void onChunkLoad() {
}
public void onChunkUnload() {
}
public void setModified() {
}
public void getEntities(Entity exclude, BoundingBox bb, List<Entity> list, Predicate<? super Entity> pred) {
}
public <T extends Entity> void getEntities(Class<? extends T> clazz, BoundingBox bb, List<T> list, Predicate<? super T> pred) {
}
public boolean isDirty() {
return false;
}
public boolean isEmpty() {
return true;
}
public boolean isEmpty(int bottom, int top) {
return true;
}
}

View file

@ -0,0 +1,353 @@
package game.world;
import java.util.List;
import java.util.Map;
import java.util.Set;
import game.ExtMath;
import game.block.Block;
import game.collect.Lists;
import game.collect.Maps;
import game.collect.Sets;
import game.enchantment.EnchantmentProtection;
import game.entity.DamageSource;
import game.entity.Entity;
import game.entity.item.EntityTnt;
import game.entity.npc.EntityNPC;
import game.entity.types.EntityLiving;
import game.init.Blocks;
import game.init.Config;
import game.init.SoundEvent;
import game.material.Material;
import game.renderer.particle.ParticleType;
import game.rng.Random;
public class Explosion
{
/** whether or not the explosion sets fire to blocks around it */
private final boolean isFlaming;
/** whether or not this explosion spawns smoke particles */
private final boolean isSmoking;
private final Random explosionRNG;
private final World worldObj;
private final double explosionX;
private final double explosionY;
private final double explosionZ;
private final Entity exploder;
private final float explosionSize;
private final List<BlockPos> affectedBlockPositions;
private final Map<EntityNPC, Vec3> playerKnockbackMap;
public Explosion(World worldIn, Entity entityIn, double x, double y, double z, float size, List<BlockPos> affectedPositions)
{
this(worldIn, entityIn, x, y, z, size, false, true, affectedPositions);
}
public Explosion(World worldIn, Entity entityIn, double x, double y, double z, float size, boolean flaming, boolean smoking, List<BlockPos> affectedPositions)
{
this(worldIn, entityIn, x, y, z, size, flaming, smoking);
this.affectedBlockPositions.addAll(affectedPositions);
}
public Explosion(World worldIn, Entity entityIn, double x, double y, double z, float size, boolean flaming, boolean smoking)
{
this.explosionRNG = new Random();
this.affectedBlockPositions = Lists.<BlockPos>newArrayList();
this.playerKnockbackMap = Maps.<EntityNPC, Vec3>newHashMap();
this.worldObj = worldIn;
this.exploder = entityIn;
this.explosionSize = size;
this.explosionX = x;
this.explosionY = y;
this.explosionZ = z;
this.isFlaming = flaming;
this.isSmoking = smoking;
}
public void doExplosionAlgo1(Set<BlockPos> set)
{
int i = 16;
for (int j = 0; j < 16; ++j)
{
for (int k = 0; k < 16; ++k)
{
for (int l = 0; l < 16; ++l)
{
if (j == 0 || j == 15 || k == 0 || k == 15 || l == 0 || l == 15)
{
double d0 = (double)((float)j / 15.0F * 2.0F - 1.0F);
double d1 = (double)((float)k / 15.0F * 2.0F - 1.0F);
double d2 = (double)((float)l / 15.0F * 2.0F - 1.0F);
double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
d0 = d0 / d3;
d1 = d1 / d3;
d2 = d2 / d3;
float f = this.explosionSize * (0.7F + this.worldObj.rand.floatv() * 0.6F);
double d4 = this.explosionX;
double d6 = this.explosionY;
double d8 = this.explosionZ;
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F)
{
BlockPos blockpos = new BlockPos(d4, d6, d8);
State iblockstate = this.worldObj.getState(blockpos);
if (iblockstate.getBlock().getMaterial() != Material.air)
{
float f2 = this.exploder != null ? this.exploder.getExplosionResistance(this, this.worldObj, blockpos, iblockstate) : iblockstate.getBlock().getExplosionResistance((Entity)null);
f -= (f2 + 0.3F) * 0.3F;
}
if (f > 0.0F && (this.exploder == null || this.exploder.verifyExplosion(this, this.worldObj, blockpos, iblockstate, f)))
{
set.add(blockpos);
}
d4 += d0 * 0.30000001192092896D;
d6 += d1 * 0.30000001192092896D;
d8 += d2 * 0.30000001192092896D;
}
}
}
}
}
}
public void doExplosionAlgo2(Set<BlockPos> set)
{
int d = ((int)this.explosionSize) + 1;
double falloff = this.explosionSize * 0.125d;
falloff = falloff > 4.0d ? 4.0d : falloff;
for (int x = -d; x <= d; ++x)
{
for (int y = -d; y <= d; ++y)
{
for (int z = -d; z <= d; ++z)
{
double dist = (double)ExtMath.sqrtd(((double)x) * ((double)x) + ((double)y) * ((double)y) + ((double)z) * ((double)z));
if(dist < this.explosionSize - falloff ||
(dist < this.explosionSize && this.explosionRNG.doublev() + ((dist - (this.explosionSize - falloff)) / falloff) < 1.0d)) {
BlockPos blockpos = new BlockPos(this.explosionX + x, this.explosionY + y, this.explosionZ + z);
State iblockstate = this.worldObj.getState(blockpos);
float f = this.explosionSize; // * (0.7F + this.worldObj.rand.nextFloat() * 0.6F);
if (iblockstate.getBlock().getMaterial() != Material.air)
{
float f2 = this.exploder != null ? this.exploder.getExplosionResistance(this, this.worldObj, blockpos, iblockstate) : iblockstate.getBlock().getExplosionResistance((Entity)null);
f -= (f2 + 0.3F) * 0.3F;
}
if (f > 0.0F && (this.exploder == null || this.exploder.verifyExplosion(this, this.worldObj, blockpos, iblockstate, f)))
{
set.add(blockpos);
}
}
}
}
}
}
public static void doExplosionAlgo3(World worldObj, double explosionX, double explosionY, double explosionZ, Random rand, double explosionSize, double minDist)
{
int d = ((int)explosionSize) + 1;
double falloff = explosionSize * 0.125d;
falloff = falloff > 4.0d ? 4.0d : falloff;
for (int x = -d; x <= d; ++x)
{
for (int y = -d; y <= d; ++y)
{
for (int z = -d; z <= d; ++z)
{
double dist = (double)ExtMath.sqrtd(((double)x) * ((double)x) + ((double)y) * ((double)y) + ((double)z) * ((double)z));
if(dist > minDist && (dist < explosionSize - falloff ||
(dist < explosionSize && rand.doublev() + ((dist - (explosionSize - falloff)) / falloff) < 1.0d))) {
BlockPos blockpos = new BlockPos(explosionX + x, explosionY + y, explosionZ + z);
State iblockstate = worldObj.getState(blockpos);
if(iblockstate.getBlock().getMaterial() != Material.air && iblockstate.getBlock().getExplosionResistance(null) < 60000.0f) {
worldObj.setState(blockpos, Blocks.air.getState(), 3);
if(rand.chance(1000)) {
worldObj.playSound(SoundEvent.EXPLODE, explosionX + x, explosionY + y, explosionZ + z, 4.0F, (1.0F + (worldObj.rand.floatv() - worldObj.rand.floatv()) * 0.2F) * 0.7F);
((WorldServer)worldObj).spawnParticle(ParticleType.EXPLOSION_HUGE, explosionX + x, explosionY + y, explosionZ + z, 0, rand.gaussian() * 0.02D, rand.gaussian() * 0.02D, rand.gaussian() * 0.02D, 1.0);
}
}
}
}
}
}
if(worldObj.client || Config.damageExplosion) {
List<Entity> list = worldObj.getEntitiesWithinAABB(Entity.class, new BoundingBox(explosionX - (5.0 + (double)d), explosionY - (5.0 + (double)d),
explosionZ - (5.0 + (double)d), explosionX + 5.0 + (double)d, explosionY + 5.0 + (double)d, explosionZ + 5.0 + (double)d));
for (Entity entity : list)
{
if (!entity.isImmuneToExplosions())
{
double dist = (double)ExtMath.sqrtd((entity.posX - explosionX) * (entity.posX - explosionX) +
(entity.posY - explosionY) * (entity.posY - explosionY) + (entity.posZ - explosionZ) * (entity.posZ - explosionZ));
if((dist > minDist - 5.0) && (dist < explosionSize + 5.0)) {
entity.attackEntityFrom(DamageSource.causeExplosionDamage(null), 10000);
}
}
}
}
}
/**
* Does the first part of the explosion (destroy blocks)
*/
public void doExplosionA()
{
Set<BlockPos> set = Sets.<BlockPos>newHashSet();
if(this.explosionSize <= 8.0d) {
this.doExplosionAlgo1(set);
}
else {
this.doExplosionAlgo2(set);
}
this.affectedBlockPositions.addAll(set);
float f3 = this.explosionSize * 2.0F;
int k1 = ExtMath.floord(this.explosionX - (double)f3 - 1.0D);
int l1 = ExtMath.floord(this.explosionX + (double)f3 + 1.0D);
int i2 = ExtMath.floord(this.explosionY - (double)f3 - 1.0D);
int i1 = ExtMath.floord(this.explosionY + (double)f3 + 1.0D);
int j2 = ExtMath.floord(this.explosionZ - (double)f3 - 1.0D);
int j1 = ExtMath.floord(this.explosionZ + (double)f3 + 1.0D);
List<Entity> list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this.exploder, new BoundingBox((double)k1, (double)i2, (double)j2, (double)l1, (double)i1, (double)j1));
Vec3 vec3 = new Vec3(this.explosionX, this.explosionY, this.explosionZ);
for (int k2 = 0; k2 < list.size(); ++k2)
{
Entity entity = (Entity)list.get(k2);
if (!entity.isImmuneToExplosions())
{
double d12 = entity.getDistance(this.explosionX, this.explosionY, this.explosionZ) / (double)f3;
if (d12 <= 1.0D)
{
double d5 = entity.posX - this.explosionX;
double d7 = entity.posY + (double)entity.getEyeHeight() - this.explosionY;
double d9 = entity.posZ - this.explosionZ;
double d13 = (double)ExtMath.sqrtd(d5 * d5 + d7 * d7 + d9 * d9);
if (d13 != 0.0D)
{
d5 = d5 / d13;
d7 = d7 / d13;
d9 = d9 / d13;
double d14 = (double)this.worldObj.getBlockDensity(vec3, entity.getEntityBoundingBox());
double d10 = (1.0D - d12) * d14;
if(this.worldObj.client || Config.damageExplosion)
entity.attackEntityFrom(DamageSource.causeExplosionDamage(this), ((int)((d10 * d10 + d10) / 2.0D * 8.0D * (double)f3 + 1.0D)));
double d11 = EnchantmentProtection.func_92092_a(entity, d10);
entity.motionX += d5 * d11;
entity.motionY += d7 * d11;
entity.motionZ += d9 * d11;
if (entity.isPlayer()) // && !((EntityNPC)entity).creative)
{
this.playerKnockbackMap.put((EntityNPC)entity, new Vec3(d5 * d10, d7 * d10, d9 * d10));
}
}
}
}
}
}
/**
* Does the second part of the explosion (sound, particles, drop spawn)
*/
public void doExplosionB(boolean spawnParticles, boolean altSound)
{
this.worldObj.playSound(altSound ? SoundEvent.EXPLODE_ALT : SoundEvent.EXPLODE, this.explosionX, this.explosionY, this.explosionZ, 4.0F, (1.0F + (this.worldObj.rand.floatv() - this.worldObj.rand.floatv()) * 0.2F) * 0.7F);
if (this.explosionSize >= 2.0F && this.isSmoking)
{
this.worldObj.spawnParticle(ParticleType.EXPLOSION_HUGE, this.explosionX, this.explosionY, this.explosionZ, 1.0D, 0.0D, 0.0D);
}
else
{
this.worldObj.spawnParticle(ParticleType.EXPLOSION_LARGE, this.explosionX, this.explosionY, this.explosionZ, 1.0D, 0.0D, 0.0D);
}
if (this.isSmoking)
{
for (BlockPos blockpos : this.affectedBlockPositions)
{
State state = this.worldObj.getState(blockpos);
Block block = state.getBlock();
if (spawnParticles)
{
double d0 = (double)((float)blockpos.getX() + this.worldObj.rand.floatv());
double d1 = (double)((float)blockpos.getY() + this.worldObj.rand.floatv());
double d2 = (double)((float)blockpos.getZ() + this.worldObj.rand.floatv());
double d3 = d0 - this.explosionX;
double d4 = d1 - this.explosionY;
double d5 = d2 - this.explosionZ;
double d6 = (double)ExtMath.sqrtd(d3 * d3 + d4 * d4 + d5 * d5);
d3 = d3 / d6;
d4 = d4 / d6;
d5 = d5 / d6;
double d7 = 0.5D / (d6 / (double)this.explosionSize + 0.1D);
d7 = d7 * (double)(this.worldObj.rand.floatv() * this.worldObj.rand.floatv() + 0.3F);
d3 = d3 * d7;
d4 = d4 * d7;
d5 = d5 * d7;
this.worldObj.spawnParticle(ParticleType.EXPLOSION_NORMAL, (d0 + this.explosionX * 1.0D) / 2.0D, (d1 + this.explosionY * 1.0D) / 2.0D, (d2 + this.explosionZ * 1.0D) / 2.0D, d3, d4, d5);
this.worldObj.spawnParticle(ParticleType.SMOKE_NORMAL, d0, d1, d2, d3, d4, d5);
}
if (block.getMaterial() != Material.air)
{
if (block.canDropFromExplosion(this))
{
block.dropBlockAsItemWithChance(this.worldObj, blockpos, this.worldObj.getState(blockpos), 1.0F / this.explosionSize, 0);
}
this.worldObj.setState(blockpos, Blocks.air.getState(), 3);
block.onBlockDestroyedByExplosion(this.worldObj, blockpos, this, state);
}
}
}
if (this.isFlaming)
{
for (BlockPos blockpos1 : this.affectedBlockPositions)
{
if (this.worldObj.getState(blockpos1).getBlock().getMaterial() == Material.air && this.worldObj.getState(blockpos1.down()).getBlock().isFullBlock() && this.explosionRNG.zrange(3) == 0)
{
this.worldObj.setState(blockpos1, Blocks.fire.getState());
}
}
}
}
public Map<EntityNPC, Vec3> getPlayerKnockbackMap()
{
return this.playerKnockbackMap;
}
/**
* Returns either the entity that placed the explosive block, the entity that caused the explosion or null.
*/
public EntityLiving getExplosivePlacedBy()
{
return this.exploder == null ? null : (this.exploder instanceof EntityTnt ? ((EntityTnt)this.exploder).getTntPlacedBy() : (this.exploder instanceof EntityLiving ? (EntityLiving)this.exploder : null));
}
public void clearAffectedBlockPositions()
{
this.affectedBlockPositions.clear();
}
public List<BlockPos> getAffectedBlockPositions()
{
return this.affectedBlockPositions;
}
}

493
java/src/game/world/Facing.java Executable file
View file

@ -0,0 +1,493 @@
package game.world;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Predicate;
import game.ExtMath;
import game.collect.Iterators;
import game.collect.Maps;
import game.properties.IStringSerializable;
import game.rng.Random;
public enum Facing implements IStringSerializable
{
DOWN(0, 2, 1, -1, "down", Facing.AxisDirection.NEGATIVE, Facing.Axis.Y, new Vec3i(0, -1, 0)),
UP(1, 3, 0, -1, "up", Facing.AxisDirection.POSITIVE, Facing.Axis.Y, new Vec3i(0, 1, 0)),
NORTH(2, 4, 3, 2, "north", Facing.AxisDirection.NEGATIVE, Facing.Axis.Z, new Vec3i(0, 0, -1)),
SOUTH(3, 5, 2, 0, "south", Facing.AxisDirection.POSITIVE, Facing.Axis.Z, new Vec3i(0, 0, 1)),
WEST(4, 1, 5, 1, "west", Facing.AxisDirection.NEGATIVE, Facing.Axis.X, new Vec3i(-1, 0, 0)),
EAST(5, 0, 4, 3, "east", Facing.AxisDirection.POSITIVE, Facing.Axis.X, new Vec3i(1, 0, 0));
/** Ordering index for D-U-N-S-W-E */
private final int index;
private final int qindex;
/** Index of the opposite Facing in the VALUES array */
private final int opposite;
/** Ordering index for the HORIZONTALS field (S-W-N-E) */
private final int horizontalIndex;
private final String name;
private final Facing.Axis axis;
private final Facing.AxisDirection axisDirection;
/** Normalized Vector that points in the direction of this Facing */
private final Vec3i directionVec;
/** All facings in D-U-N-S-W-E order */
private static final Facing[] VALUES = new Facing[6];
/** All Facings with horizontal axis in order S-W-N-E */
private static final Facing[] HORIZONTALS = new Facing[4];
private static final Map<String, Facing> NAME_LOOKUP = Maps.<String, Facing>newHashMap();
private Facing(int indexIn, int qindexIn, int oppositeIn, int horizontalIndexIn, String nameIn, Facing.AxisDirection axisDirectionIn, Facing.Axis axisIn, Vec3i directionVecIn)
{
this.index = indexIn;
this.qindex = qindexIn;
this.horizontalIndex = horizontalIndexIn;
this.opposite = oppositeIn;
this.name = nameIn;
this.axis = axisIn;
this.axisDirection = axisDirectionIn;
this.directionVec = directionVecIn;
}
/**
* Get the Index of this Facing (0-5). The order is D-U-N-S-W-E
*/
public int getIndex()
{
return this.index;
}
public int getQIndex()
{
return this.qindex;
}
/**
* Get the index of this horizontal facing (0-3). The order is S-W-N-E
*/
public int getHorizontalIndex()
{
return this.horizontalIndex;
}
/**
* Get the AxisDirection of this Facing.
*/
public Facing.AxisDirection getAxisDirection()
{
return this.axisDirection;
}
/**
* Get the opposite Facing (e.g. DOWN => UP)
*/
public Facing getOpposite()
{
return getFront(this.opposite);
}
/**
* Rotate this Facing around the given axis clockwise. If this facing cannot be rotated around the given axis,
* returns this facing without rotating.
*/
public Facing rotateAround(Facing.Axis axis)
{
switch (axis)
{
case X:
if (this != WEST && this != EAST)
{
return this.rotateX();
}
return this;
case Y:
if (this != UP && this != DOWN)
{
return this.rotateY();
}
return this;
case Z:
if (this != NORTH && this != SOUTH)
{
return this.rotateZ();
}
return this;
default:
throw new IllegalStateException("Unable to get CW facing for axis " + axis);
}
}
/**
* Rotate this Facing around the Y axis clockwise (NORTH => EAST => SOUTH => WEST => NORTH)
*/
public Facing rotateY()
{
switch (this)
{
case NORTH:
return EAST;
case EAST:
return SOUTH;
case SOUTH:
return WEST;
case WEST:
return NORTH;
default:
throw new IllegalStateException("Unable to get Y-rotated facing of " + this);
}
}
/**
* Rotate this Facing around the X axis (NORTH => DOWN => SOUTH => UP => NORTH)
*/
private Facing rotateX()
{
switch (this)
{
case NORTH:
return DOWN;
case EAST:
case WEST:
default:
throw new IllegalStateException("Unable to get X-rotated facing of " + this);
case SOUTH:
return UP;
case UP:
return NORTH;
case DOWN:
return SOUTH;
}
}
/**
* Rotate this Facing around the Z axis (EAST => DOWN => WEST => UP => EAST)
*/
private Facing rotateZ()
{
switch (this)
{
case EAST:
return DOWN;
case SOUTH:
default:
throw new IllegalStateException("Unable to get Z-rotated facing of " + this);
case WEST:
return UP;
case UP:
return EAST;
case DOWN:
return WEST;
}
}
/**
* Rotate this Facing around the Y axis counter-clockwise (NORTH => WEST => SOUTH => EAST => NORTH)
*/
public Facing rotateYCCW()
{
switch (this)
{
case NORTH:
return WEST;
case EAST:
return NORTH;
case SOUTH:
return EAST;
case WEST:
return SOUTH;
default:
throw new IllegalStateException("Unable to get CCW facing of " + this);
}
}
/**
* Returns a offset that addresses the block in front of this facing.
*/
public int getFrontOffsetX()
{
return this.axis == Facing.Axis.X ? this.axisDirection.getOffset() : 0;
}
public int getFrontOffsetY()
{
return this.axis == Facing.Axis.Y ? this.axisDirection.getOffset() : 0;
}
/**
* Returns a offset that addresses the block in front of this facing.
*/
public int getFrontOffsetZ()
{
return this.axis == Facing.Axis.Z ? this.axisDirection.getOffset() : 0;
}
/**
* Same as getName, but does not override the method from Enum.
*/
public String getName2()
{
return this.name;
}
public Facing.Axis getAxis()
{
return this.axis;
}
/**
* Get the facing specified by the given name
*/
public static Facing byName(String name)
{
return name == null ? null : (Facing)NAME_LOOKUP.get(name.toLowerCase());
}
/**
* Get a Facing by it's index (0-5). The order is D-U-N-S-W-E. Named getFront for legacy reasons.
*/
public static Facing getFront(int index)
{
return VALUES[ExtMath.absi(index % VALUES.length)];
}
/**
* Get a Facing by it's horizontal index (0-3). The order is S-W-N-E.
*/
public static Facing getHorizontal(int p_176731_0_)
{
return HORIZONTALS[ExtMath.absi(p_176731_0_ % HORIZONTALS.length)];
}
/**
* Get the Facing corresponding to the given angle (0-360). An angle of 0 is SOUTH, an angle of 90 would be WEST.
*/
public static Facing fromAngle(double angle)
{
return getHorizontal(ExtMath.floord(angle / 90.0D + 0.5D) & 3);
}
/**
* Choose a random Facing using the given Random
*/
public static Facing random(Random rand)
{
return values()[rand.zrange(values().length)];
}
public static Facing randHorizontal(Random rand)
{
return rand.pick(HORIZONTALS);
}
public static Facing getFacingFromVector(float p_176737_0_, float p_176737_1_, float p_176737_2_)
{
Facing enumfacing = NORTH;
float f = Float.MIN_VALUE;
for (Facing enumfacing1 : values())
{
float f1 = p_176737_0_ * (float)enumfacing1.directionVec.getX() + p_176737_1_ * (float)enumfacing1.directionVec.getY() + p_176737_2_ * (float)enumfacing1.directionVec.getZ();
if (f1 > f)
{
f = f1;
enumfacing = enumfacing1;
}
}
return enumfacing;
}
public String toString()
{
return this.name;
}
public String getName()
{
return this.name;
}
public static Facing getFacingFromAxis(Facing.AxisDirection p_181076_0_, Facing.Axis p_181076_1_)
{
for (Facing enumfacing : values())
{
if (enumfacing.getAxisDirection() == p_181076_0_ && enumfacing.getAxis() == p_181076_1_)
{
return enumfacing;
}
}
throw new IllegalArgumentException("No such direction: " + p_181076_0_ + " " + p_181076_1_);
}
/**
* Get a normalized Vector that points in the direction of this Facing.
*/
public Vec3i getDirectionVec()
{
return this.directionVec;
}
static {
for (Facing enumfacing : values())
{
VALUES[enumfacing.index] = enumfacing;
if (enumfacing.getAxis().isHorizontal())
{
HORIZONTALS[enumfacing.horizontalIndex] = enumfacing;
}
NAME_LOOKUP.put(enumfacing.getName2().toLowerCase(), enumfacing);
}
}
public static enum Axis implements Predicate<Facing>, IStringSerializable {
X("x", Facing.Plane.HORIZONTAL),
Y("y", Facing.Plane.VERTICAL),
Z("z", Facing.Plane.HORIZONTAL);
private static final Map<String, Facing.Axis> NAME_LOOKUP = Maps.<String, Facing.Axis>newHashMap();
private final String name;
private final Facing.Plane plane;
private Axis(String name, Facing.Plane plane)
{
this.name = name;
this.plane = plane;
}
public static Facing.Axis byName(String name)
{
return name == null ? null : (Facing.Axis)NAME_LOOKUP.get(name.toLowerCase());
}
public String getName2()
{
return this.name;
}
public boolean isVertical()
{
return this.plane == Facing.Plane.VERTICAL;
}
public boolean isHorizontal()
{
return this.plane == Facing.Plane.HORIZONTAL;
}
public String toString()
{
return this.name;
}
public boolean test(Facing p_apply_1_)
{
return p_apply_1_ != null && p_apply_1_.getAxis() == this;
}
public Facing.Plane getPlane()
{
return this.plane;
}
public String getName()
{
return this.name;
}
static {
for (Facing.Axis enumfacing$axis : values())
{
NAME_LOOKUP.put(enumfacing$axis.getName2().toLowerCase(), enumfacing$axis);
}
}
}
public static enum AxisDirection {
POSITIVE(1, "Towards positive"),
NEGATIVE(-1, "Towards negative");
private final int offset;
private final String description;
private AxisDirection(int offset, String description)
{
this.offset = offset;
this.description = description;
}
public int getOffset()
{
return this.offset;
}
public String toString()
{
return this.description;
}
}
public static enum Plane implements Predicate<Facing>, Iterable<Facing> {
HORIZONTAL,
VERTICAL;
public Facing[] facings()
{
switch (this)
{
case HORIZONTAL:
return new Facing[] {Facing.NORTH, Facing.EAST, Facing.SOUTH, Facing.WEST};
case VERTICAL:
return new Facing[] {Facing.UP, Facing.DOWN};
default:
throw new Error("Someone\'s been tampering with the universe!");
}
}
public Facing random(Random rand)
{
Facing[] aenumfacing = this.facings();
return aenumfacing[rand.zrange(aenumfacing.length)];
}
public boolean test(Facing p_apply_1_)
{
return p_apply_1_ != null && p_apply_1_.getAxis().getPlane() == this;
}
public Iterator<Facing> iterator()
{
return Iterators.<Facing>forArray(this.facings());
}
}
}

View file

@ -0,0 +1,35 @@
package game.world;
import game.entity.Entity;
public class HitPosition {
public static enum ObjectType {
MISS, BLOCK, ENTITY;
}
public final ObjectType type;
public final BlockPos block;
public final Facing side;
public final Vec3 vec;
public final Entity entity;
public HitPosition(Entity entity) {
this(entity, new Vec3(entity.posX, entity.posY, entity.posZ));
}
public HitPosition(ObjectType type, Vec3 vec, Facing side, BlockPos block) {
this.type = type;
this.block = block;
this.side = side;
this.entity = null;
this.vec = new Vec3(vec.xCoord, vec.yCoord, vec.zCoord);
}
public HitPosition(Entity entity, Vec3 vec) {
this.type = ObjectType.ENTITY;
this.block = null;
this.side = null;
this.entity = entity;
this.vec = vec;
}
}

View file

@ -0,0 +1,6 @@
package game.world;
public interface IBlockAccess
{
State getState(BlockPos pos);
}

View file

@ -0,0 +1,11 @@
package game.world;
import game.biome.Biome;
import game.tileentity.TileEntity;
public interface IWorldAccess extends IBlockAccess
{
TileEntity getTileEntity(BlockPos pos);
int getCombinedLight(BlockPos pos, int lightValue);
Biome getBiomeGenForCoords(BlockPos pos);
}

View file

@ -0,0 +1,282 @@
package game.world;
public class IntHashMap<V>
{
private transient IntHashMap.Entry<V>[] slots = new IntHashMap.Entry[16];
/** The number of items stored in this map */
private transient int count;
/** The grow threshold */
private int threshold = 12;
/** The scale factor used to determine when to grow the table */
private final float growFactor = 0.75F;
/**
* Makes the passed in integer suitable for hashing by a number of shifts
*/
private static int computeHash(int integer)
{
integer = integer ^ integer >>> 20 ^ integer >>> 12;
return integer ^ integer >>> 7 ^ integer >>> 4;
}
/**
* Computes the index of the slot for the hash and slot count passed in.
*/
private static int getSlotIndex(int hash, int slotCount)
{
return hash & slotCount - 1;
}
/**
* Returns the object associated to a key
*/
public V lookup(int p_76041_1_)
{
int i = computeHash(p_76041_1_);
for (IntHashMap.Entry<V> entry = this.slots[getSlotIndex(i, this.slots.length)]; entry != null; entry = entry.nextEntry)
{
if (entry.hashEntry == p_76041_1_)
{
return entry.valueEntry;
}
}
return (V)null;
}
/**
* Returns true if this hash table contains the specified item.
*/
public boolean containsItem(int p_76037_1_)
{
return this.lookupEntry(p_76037_1_) != null;
}
final IntHashMap.Entry<V> lookupEntry(int p_76045_1_)
{
int i = computeHash(p_76045_1_);
for (IntHashMap.Entry<V> entry = this.slots[getSlotIndex(i, this.slots.length)]; entry != null; entry = entry.nextEntry)
{
if (entry.hashEntry == p_76045_1_)
{
return entry;
}
}
return null;
}
/**
* Adds a key and associated value to this map
*/
public void addKey(int p_76038_1_, V p_76038_2_)
{
int i = computeHash(p_76038_1_);
int j = getSlotIndex(i, this.slots.length);
for (IntHashMap.Entry<V> entry = this.slots[j]; entry != null; entry = entry.nextEntry)
{
if (entry.hashEntry == p_76038_1_)
{
entry.valueEntry = p_76038_2_;
return;
}
}
this.insert(i, p_76038_1_, p_76038_2_, j);
}
/**
* Increases the number of hash slots
*/
private void grow(int p_76047_1_)
{
IntHashMap.Entry<V>[] entry = this.slots;
int i = entry.length;
if (i == 1073741824)
{
this.threshold = Integer.MAX_VALUE;
}
else
{
IntHashMap.Entry<V>[] entry1 = new IntHashMap.Entry[p_76047_1_];
this.copyTo(entry1);
this.slots = entry1;
this.threshold = (int)((float)p_76047_1_ * this.growFactor);
}
}
/**
* Copies the hash slots to a new array
*/
private void copyTo(IntHashMap.Entry<V>[] p_76048_1_)
{
IntHashMap.Entry<V>[] entry = this.slots;
int i = p_76048_1_.length;
for (int j = 0; j < entry.length; ++j)
{
IntHashMap.Entry<V> entry1 = entry[j];
if (entry1 != null)
{
entry[j] = null;
while (true)
{
IntHashMap.Entry<V> entry2 = entry1.nextEntry;
int k = getSlotIndex(entry1.slotHash, i);
entry1.nextEntry = p_76048_1_[k];
p_76048_1_[k] = entry1;
entry1 = entry2;
if (entry2 == null)
{
break;
}
}
}
}
}
/**
* Removes the specified object from the map and returns it
*/
public V removeObject(int p_76049_1_)
{
IntHashMap.Entry<V> entry = this.removeEntry(p_76049_1_);
return (V)(entry == null ? null : entry.valueEntry);
}
final IntHashMap.Entry<V> removeEntry(int p_76036_1_)
{
int i = computeHash(p_76036_1_);
int j = getSlotIndex(i, this.slots.length);
IntHashMap.Entry<V> entry = this.slots[j];
IntHashMap.Entry<V> entry1;
IntHashMap.Entry<V> entry2;
for (entry1 = entry; entry1 != null; entry1 = entry2)
{
entry2 = entry1.nextEntry;
if (entry1.hashEntry == p_76036_1_)
{
--this.count;
if (entry == entry1)
{
this.slots[j] = entry2;
}
else
{
entry.nextEntry = entry2;
}
return entry1;
}
entry = entry1;
}
return entry1;
}
/**
* Removes all entries from the map
*/
public void clearMap()
{
IntHashMap.Entry<V>[] entry = this.slots;
for (int i = 0; i < entry.length; ++i)
{
entry[i] = null;
}
this.count = 0;
}
/**
* Adds an object to a slot
*/
private void insert(int p_76040_1_, int p_76040_2_, V p_76040_3_, int p_76040_4_)
{
IntHashMap.Entry<V> entry = this.slots[p_76040_4_];
this.slots[p_76040_4_] = new IntHashMap.Entry(p_76040_1_, p_76040_2_, p_76040_3_, entry);
if (this.count++ >= this.threshold)
{
this.grow(2 * this.slots.length);
}
}
static class Entry<V>
{
final int hashEntry;
V valueEntry;
IntHashMap.Entry<V> nextEntry;
final int slotHash;
Entry(int p_i1552_1_, int p_i1552_2_, V p_i1552_3_, IntHashMap.Entry<V> p_i1552_4_)
{
this.valueEntry = p_i1552_3_;
this.nextEntry = p_i1552_4_;
this.hashEntry = p_i1552_2_;
this.slotHash = p_i1552_1_;
}
public final int getHash()
{
return this.hashEntry;
}
public final V getValue()
{
return this.valueEntry;
}
public final boolean equals(Object p_equals_1_)
{
if (!(p_equals_1_ instanceof IntHashMap.Entry))
{
return false;
}
else
{
IntHashMap.Entry<V> entry = (IntHashMap.Entry)p_equals_1_;
Object object = Integer.valueOf(this.getHash());
Object object1 = Integer.valueOf(entry.getHash());
if (object == object1 || object != null && object.equals(object1))
{
Object object2 = this.getValue();
Object object3 = entry.getValue();
if (object2 == object3 || object2 != null && object2.equals(object3))
{
return true;
}
}
return false;
}
}
public final int hashCode()
{
return IntHashMap.computeHash(this.hashEntry);
}
public final String toString()
{
return this.getHash() + "=" + this.getValue();
}
}
}

View file

@ -0,0 +1,11 @@
package game.world;
public enum LightType {
SKY(15), BLOCK(0);
public final int defValue;
private LightType(int def) {
this.defValue = def;
}
}

View file

@ -0,0 +1,285 @@
package game.world;
public class LongHashMap<V>
{
private transient LongHashMap.Entry<V>[] hashArray = new LongHashMap.Entry[4096];
private transient int numHashElements;
private int mask;
private int capacity = 3072;
private final float percentUseable = 0.75F;
private transient volatile int modCount;
public static long packInt(int x, int z) {
return (long)x & 4294967295L | ((long)z & 4294967295L) << 32;
}
public LongHashMap()
{
this.mask = this.hashArray.length - 1;
}
/**
* returns the hashed key given the original key
*/
private static int getHashedKey(long originalKey)
{
return hash((int)(originalKey ^ originalKey >>> 32));
}
/**
* the hash function
*/
private static int hash(int integer)
{
integer = integer ^ integer >>> 20 ^ integer >>> 12;
return integer ^ integer >>> 7 ^ integer >>> 4;
}
/**
* gets the index in the hash given the array length and the hashed key
*/
private static int getHashIndex(int p_76158_0_, int p_76158_1_)
{
return p_76158_0_ & p_76158_1_;
}
public int getNumHashElements()
{
return this.numHashElements;
}
/**
* get the value from the map given the key
*/
public V getValueByKey(long p_76164_1_)
{
int i = getHashedKey(p_76164_1_);
for (LongHashMap.Entry<V> entry = this.hashArray[getHashIndex(i, this.mask)]; entry != null; entry = entry.nextEntry)
{
if (entry.key == p_76164_1_)
{
return entry.value;
}
}
return (V)null;
}
public boolean containsItem(long p_76161_1_)
{
return this.getEntry(p_76161_1_) != null;
}
final LongHashMap.Entry<V> getEntry(long p_76160_1_)
{
int i = getHashedKey(p_76160_1_);
for (LongHashMap.Entry<V> entry = this.hashArray[getHashIndex(i, this.mask)]; entry != null; entry = entry.nextEntry)
{
if (entry.key == p_76160_1_)
{
return entry;
}
}
return null;
}
/**
* Add a key-value pair.
*/
public void add(long p_76163_1_, V p_76163_3_)
{
int i = getHashedKey(p_76163_1_);
int j = getHashIndex(i, this.mask);
for (LongHashMap.Entry<V> entry = this.hashArray[j]; entry != null; entry = entry.nextEntry)
{
if (entry.key == p_76163_1_)
{
entry.value = p_76163_3_;
return;
}
}
++this.modCount;
this.createKey(i, p_76163_1_, p_76163_3_, j);
}
/**
* resizes the table
*/
private void resizeTable(int p_76153_1_)
{
LongHashMap.Entry<V>[] entry = this.hashArray;
int i = entry.length;
if (i == 1073741824)
{
this.capacity = Integer.MAX_VALUE;
}
else
{
LongHashMap.Entry<V>[] entry1 = new LongHashMap.Entry[p_76153_1_];
this.copyHashTableTo(entry1);
this.hashArray = entry1;
this.mask = this.hashArray.length - 1;
this.capacity = (int)((float)p_76153_1_ * this.percentUseable);
}
}
/**
* copies the hash table to the specified array
*/
private void copyHashTableTo(LongHashMap.Entry<V>[] p_76154_1_)
{
LongHashMap.Entry<V>[] entry = this.hashArray;
int i = p_76154_1_.length;
for (int j = 0; j < entry.length; ++j)
{
LongHashMap.Entry<V> entry1 = entry[j];
if (entry1 != null)
{
entry[j] = null;
while (true)
{
LongHashMap.Entry<V> entry2 = entry1.nextEntry;
int k = getHashIndex(entry1.hash, i - 1);
entry1.nextEntry = p_76154_1_[k];
p_76154_1_[k] = entry1;
entry1 = entry2;
if (entry2 == null)
{
break;
}
}
}
}
}
/**
* calls the removeKey method and returns removed object
*/
public V remove(long p_76159_1_)
{
LongHashMap.Entry<V> entry = this.removeKey(p_76159_1_);
return (V)(entry == null ? null : entry.value);
}
final LongHashMap.Entry<V> removeKey(long p_76152_1_)
{
int i = getHashedKey(p_76152_1_);
int j = getHashIndex(i, this.mask);
LongHashMap.Entry<V> entry = this.hashArray[j];
LongHashMap.Entry<V> entry1;
LongHashMap.Entry<V> entry2;
for (entry1 = entry; entry1 != null; entry1 = entry2)
{
entry2 = entry1.nextEntry;
if (entry1.key == p_76152_1_)
{
++this.modCount;
--this.numHashElements;
if (entry == entry1)
{
this.hashArray[j] = entry2;
}
else
{
entry.nextEntry = entry2;
}
return entry1;
}
entry = entry1;
}
return entry1;
}
/**
* creates the key in the hash table
*/
private void createKey(int p_76156_1_, long p_76156_2_, V p_76156_4_, int p_76156_5_)
{
LongHashMap.Entry<V> entry = this.hashArray[p_76156_5_];
this.hashArray[p_76156_5_] = new LongHashMap.Entry(p_76156_1_, p_76156_2_, p_76156_4_, entry);
if (this.numHashElements++ >= this.capacity)
{
this.resizeTable(2 * this.hashArray.length);
}
}
static class Entry<V>
{
final long key;
V value;
LongHashMap.Entry<V> nextEntry;
final int hash;
Entry(int p_i1553_1_, long p_i1553_2_, V p_i1553_4_, LongHashMap.Entry<V> p_i1553_5_)
{
this.value = p_i1553_4_;
this.nextEntry = p_i1553_5_;
this.key = p_i1553_2_;
this.hash = p_i1553_1_;
}
public final long getKey()
{
return this.key;
}
public final V getValue()
{
return this.value;
}
public final boolean equals(Object p_equals_1_)
{
if (!(p_equals_1_ instanceof LongHashMap.Entry))
{
return false;
}
else
{
LongHashMap.Entry<V> entry = (LongHashMap.Entry)p_equals_1_;
Object object = Long.valueOf(this.getKey());
Object object1 = Long.valueOf(entry.getKey());
if (object == object1 || object != null && object.equals(object1))
{
Object object2 = this.getValue();
Object object3 = entry.getValue();
if (object2 == object3 || object2 != null && object2.equals(object3))
{
return true;
}
}
return false;
}
}
public final int hashCode()
{
return LongHashMap.getHashedKey(this.key);
}
public final String toString()
{
return this.getKey() + "=" + this.getValue();
}
}
}

View file

@ -0,0 +1,73 @@
package game.world;
import game.block.Block;
import game.init.BlockRegistry;
public class NextTickListEntry implements Comparable<NextTickListEntry>
{
/** The id number for the next tick entry */
private static long nextTickEntryID;
private final Block block;
public final BlockPos position;
/** Time this tick is scheduled to occur at */
public long scheduledTime;
public int priority;
/** The id of the tick entry */
private long tickEntryID;
public NextTickListEntry(BlockPos positionIn, Block blockIn)
{
this.tickEntryID = (long)(nextTickEntryID++);
this.position = positionIn;
this.block = blockIn;
}
public boolean equals(Object p_equals_1_)
{
if (!(p_equals_1_ instanceof NextTickListEntry))
{
return false;
}
else
{
NextTickListEntry nextticklistentry = (NextTickListEntry)p_equals_1_;
return this.position.equals(nextticklistentry.position) && Block.isEqualTo(this.block, nextticklistentry.block);
}
}
public int hashCode()
{
return this.position.hashCode();
}
/**
* Sets the scheduled time for this tick entry
*/
public NextTickListEntry setScheduledTime(long scheduledTimeIn)
{
this.scheduledTime = scheduledTimeIn;
return this;
}
public void setPriority(int priorityIn)
{
this.priority = priorityIn;
}
public int compareTo(NextTickListEntry p_compareTo_1_)
{
return this.scheduledTime < p_compareTo_1_.scheduledTime ? -1 : (this.scheduledTime > p_compareTo_1_.scheduledTime ? 1 : (this.priority != p_compareTo_1_.priority ? this.priority - p_compareTo_1_.priority : (this.tickEntryID < p_compareTo_1_.tickEntryID ? -1 : (this.tickEntryID > p_compareTo_1_.tickEntryID ? 1 : 0))));
}
public String toString()
{
return BlockRegistry.getIdFromBlock(this.block) + ": " + this.position + ", " + this.scheduledTime + ", " + this.priority + ", " + this.tickEntryID;
}
public Block getBlock()
{
return this.block;
}
}

View file

@ -0,0 +1,31 @@
package game.world;
public class NibbleArray {
private final byte[] data;
public NibbleArray() {
this.data = new byte[2048];
}
public NibbleArray(byte[] data) {
if(data.length != 2048)
throw new IllegalArgumentException("NibbleArray sollte 2048 Bytes groß sein, nicht " + data.length);
this.data = data;
}
public int get(int x, int y, int z) {
int idx = y << 8 | z << 4 | x;
int off = idx >> 1;
return (idx & 1) == 0 ? this.data[off] & 15 : this.data[off] >> 4 & 15;
}
public void set(int x, int y, int z, int value) {
int idx = y << 8 | z << 4 | x;
int off = idx >> 1;
this.data[off] = (idx & 1) == 0 ? (byte)(this.data[off] & 240 | value & 15) : (byte)(this.data[off] & 15 | (value & 15) << 4);
}
public byte[] getData() {
return this.data;
}
}

View file

@ -0,0 +1,5 @@
package game.world;
public enum PortalType {
STAND_BLACK, STAND_RED, STAND_YELLOW, STAND_GREEN, STAND_CYAN, STAND_BLUE, STAND_MAGENTA, STAND_WHITE, FLOOR, VOID;
}

View file

@ -0,0 +1,19 @@
package game.world;
public class Position {
public final double x;
public final double y;
public final double z;
public final float yaw;
public final float pitch;
public final int dim;
public Position(double x, double y, double z, float yaw, float pitch, int dim) {
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
this.dim = dim;
}
}

760
java/src/game/world/Region.java Executable file
View file

@ -0,0 +1,760 @@
package game.world;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import game.Log;
import game.block.Block;
import game.collect.Lists;
import game.collect.Maps;
import game.entity.Entity;
import game.init.BlockRegistry;
import game.init.Config;
import game.init.EntityRegistry;
import game.init.UniverseRegistry;
import game.nbt.NBTLoader;
import game.nbt.NBTTagCompound;
import game.nbt.NBTTagList;
import game.tileentity.TileEntity;
import game.world.Converter.SaveVersion;
public class Region {
public static class FolderInfo {
public final long time;
public final String user;
public final long lastPlayed;
public final SaveVersion legacy;
public final String version;
public FolderInfo(long time, String user, long lastPlayed, SaveVersion legacy, String version) {
this.time = time;
this.user = user;
this.lastPlayed = lastPlayed;
this.legacy = legacy;
this.version = version;
}
}
private static class ChunkBuffer extends ByteArrayOutputStream {
public ChunkBuffer() {
super(8096);
}
public byte[] getData() {
return this.buf;
}
}
static {
Thread thread = new Thread(new Runnable() {
public void run() {
while(!killed) {
processQueue();
}
}
}, "File IO Thread");
thread.setPriority(1);
thread.start();
}
public static final File SAVE_DIR = new File("saves");
private static final Map<String, Region> CACHE = Maps.<String, Region>newHashMap();
private static final List<WorldServer> QUEUE = Collections.<WorldServer>synchronizedList(Lists.<WorldServer>newArrayList());
// public static long lastPlayed;
// public static int version;
// public static String owner;
private static volatile long queued;
private static volatile long saved;
private static volatile boolean waiting;
private static volatile boolean killed;
private final int[] timestamps = new int[64];
private final int[] positions = new int[64];
private final int[] sizes = new int[64];
private final File regFile;
private final File folder;
private final int xPos;
private final int zPos;
private RandomAccessFile file;
private long lastModified;
private int offset;
private boolean modified;
public Region(File dir, int x, int z) {
File sdir = new File(dir, getRegionFolder(x << 3, z << 3));
if(!sdir.exists())
sdir.mkdirs();
this.regFile = new File(sdir, getRegionName(x << 3, z << 3));
this.folder = dir;
this.xPos = x;
this.zPos = z;
try {
if(this.regFile.exists())
this.lastModified = this.regFile.lastModified();
this.file = new RandomAccessFile(this.regFile, "rw");
this.file.seek(0L);
if(this.file.length() < 512L) {
for(int i = 0; i < 64; i++) {
this.file.writeLong(0L);
}
}
else {
for(int i = 0; i < 64; i++) {
int end = this.positions[i] = this.file.readUnsignedShort();
end += ((this.sizes[i] = this.file.readUnsignedShort()) + 255) >> 8;
this.timestamps[i] = this.file.readInt();
if(end > this.offset)
this.offset = end;
}
}
}
catch(IOException e) {
e.printStackTrace();
}
}
private void reorganize(boolean reopen) throws IOException {
byte[] buffer = new byte[8192];
File tmp = new File(this.folder, this.regFile.getName() + ".tmp");
RandomAccessFile file = new RandomAccessFile(tmp, "rw");
int offset = 0;
for(int i = 0; i < 64; i++) {
file.writeShort(this.sizes[i] == 0 ? 0 : offset);
file.writeShort(this.sizes[i]);
file.writeInt(this.timestamps[i]);
offset += (this.sizes[i] + 255) >> 8;
}
this.offset = offset;
offset = 0;
for(int i = 0; i < 64; i++) {
int size = this.sizes[i];
if(size == 0) {
this.positions[i] = 0;
continue;
}
this.file.seek(512L + (long)(this.positions[i] << 8));
this.file.read(buffer, 0, size);
file.write(buffer, 0, size);
this.positions[i] = offset;
offset += (size + 255) >> 8;
file.seek(512L + (long)(offset << 8));
}
file.close();
this.file.close();
tmp.renameTo(this.regFile);
this.file = reopen ? new RandomAccessFile(this.regFile, "rw") : null;
this.modified = false;
}
private synchronized byte[] read(int x, int z) {
if(this.timestamps[x + z * 8] == 0)
return null;
FileInputStream in = null;
try {
// this.file.seek((long)(512 + (x + z * 8) * 8192));
int size = this.sizes[x + z * 8]; // this.file.readShort();
if(size > 8192 /* - 2 */ || size < 0) {
Log.JNI.warn("Chunk-Region-Datei " + this.regFile + " hat eine ungültige Größe bei " + x + ", " + z + ", überspringe");
return null;
}
byte[] data;
if(size == 0) {
File expand = getExpansionFile(this.folder, this.xPos * 8 + x, this.zPos * 8 + z);
if(!expand.exists()) {
Log.JNI.warn("Chunk-Erweiterungs-Datei " + expand + " ist nicht vorhanden oder nicht lesbar, überspringe");
return null;
}
in = new FileInputStream(expand);
data = new byte[(int)expand.length()];
int remain = data.length;
while(remain > 0) {
int n = Math.min(remain, 8192);
in.read(data, (data.length - remain), n);
remain -= n;
}
try {
if(in != null) {
in.close();
}
}
catch(IOException e) {
}
in = null;
}
else {
int pos = this.positions[x + z * 8] << 8;
if(pos + size > this.file.length() - 512L || pos < 0) {
Log.JNI.warn("Chunk-Region-Datei " + this.regFile + " hat eine ungültige Position bei " + x + ", " + z + ", überspringe");
return null;
}
this.file.seek(512L + (long)pos);
data = new byte[size]; // - 2];
this.file.read(data);
}
return data;
}
catch(IOException e) {
try {
if(in != null) {
in.close();
}
}
catch(IOException e1) {
}
Log.JNI.error(e, "Fehler beim lesen von Chunk-Region-Datei " + this.regFile + " bei " + x + ", " + z + ", überspringe");
return null;
}
}
private synchronized void write(int x, int z, byte[] data, int size) {
try {
if(((int)this.file.length() - 512) >= 1048576)
this.reorganize(true);
this.modified = true;
// if(size >= 8192)
// Log.DATA.info("REG " + x + ", " + z + ": " + size);
int pos = 0;
if(size /* + 2 */ > 8192) {
FileOutputStream out = null;
try {
out = new FileOutputStream(getExpansionFile(this.folder, this.xPos * 8 + x, this.zPos * 8 + z));
int remain = size;
while(remain > 0) {
int n = Math.min(remain, 8192);
out.write(data, (size - remain), n);
remain -= n;
}
}
catch(IOException e) {
e.printStackTrace();
}
try {
if(out != null) {
out.close();
}
}
catch(IOException e) {
}
data = new byte[0];
size = 0;
}
else {
pos = this.offset;
this.offset += (size + 255) >> 8;
this.file.seek(512L + (long)(pos << 8)); // (512 + (x + z * 8) * 8192));
// this.file.writeShort(size);
this.file.write(data, 0, size);
}
int time = (int)(System.currentTimeMillis() / 10000L);
this.timestamps[x + z * 8] = time;
this.positions[x + z * 8] = pos;
this.sizes[x + z * 8] = size;
this.file.seek((long)((x + z * 8) * 8));
this.file.writeShort(pos);
this.file.writeShort(size);
this.file.writeInt(time);
}
catch(IOException e) {
e.printStackTrace();
}
}
public synchronized void close(boolean reorg) throws IOException { // FIX ??
if(this.file != null) {
if(reorg && this.modified)
this.reorganize(false);
else
this.file.close();
this.file = null;
}
}
public long getTimestamp(int x, int z) {
return (long)this.timestamps[x + z * 8] * 10000L;
}
public void writeTag(int x, int z, NBTTagCompound tag) throws IOException {
ChunkBuffer buf = new ChunkBuffer();
DataOutputStream out = new DataOutputStream(new DeflaterOutputStream(buf));
NBTLoader.write(tag, out);
out.close();
this.write(x, z, buf.getData(), buf.size());
}
// public NBTTagCompound readTag(int x, int z) throws IOException {
// byte[] data = this.read(x, z);
// if(data == null)
// return null;
// return CompressedStreamTools.read(new DataInputStream(new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(data)))));
// }
public File getFile() {
return this.regFile;
}
private static synchronized Region getRegionFile(File dir, int x, int z) {
Region reg = CACHE.get(dir + "." + x + "." + z);
if(reg != null)
return reg;
if(CACHE.size() >= 256)
clearCache(false);
Region nreg = new Region(dir, x, z);
CACHE.put(dir + "." + x + "." + z, nreg);
return nreg;
}
private static File getExpansionFile(File dir, int x, int z) {
File sdir = new File(dir, getRegionFolder(x, z));
if(!sdir.exists())
sdir.mkdirs();
return new File(sdir, String.format("c.%c%X%c%X.chk", x < 0 ? 'n' : 'p', (x < 0) ? -x : x, z < 0 ? 'n' : 'p', (z < 0) ? -z : z));
}
private static synchronized void clearCache(boolean all) {
if(all) {
for(Region reg : CACHE.values()) {
try {
reg.close(true);
}
catch(IOException e) {
e.printStackTrace();
}
}
CACHE.clear();
}
else {
Iterator<Region> iter = CACHE.values().iterator();
for(int z = 0; z < 8 && iter.hasNext(); z++) {
try {
iter.next().close(true);
}
catch(IOException e) {
e.printStackTrace();
}
iter.remove();
}
}
}
public static void finishWrite() {
waiting = true;
try {
while(queued != saved) {
Thread.sleep(10L);
}
}
catch(InterruptedException e) {
e.printStackTrace();
}
waiting = false;
clearCache(true);
}
public static /* synchronized */ NBTTagCompound readChunk(File dir, int x, int z) throws IOException {
// return getRegionFile(dir, x >> 3, z >> 3).readTag(x & 7, z & 7);
byte[] data = getRegionFile(dir, x >> 3, z >> 3).read(x & 7, z & 7);
if(data == null)
return null;
return NBTLoader.read(new DataInputStream(new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(data)))));
}
public static /* synchronized */ void writeChunk(File dir, int x, int z, NBTTagCompound tag) throws IOException {
ChunkBuffer buf = new ChunkBuffer();
DataOutputStream out = new DataOutputStream(new DeflaterOutputStream(buf));
NBTLoader.write(tag, out);
out.close();
getRegionFile(dir, x >> 3, z >> 3).write(x & 7, z & 7, buf.getData(), buf.size());
// getRegionFile(dir, x >> 3, z >> 3).writeTag(x & 7, z & 7, tag);
}
public static String getRegionFolder(int x, int z) {
return String.format("%c%03X%c%03X", x < 0 ? 'n' : 'p', ((x < 0) ? -x : x) >> 9, z < 0 ? 'n' : 'p', ((z < 0) ? -z : z) >> 9);
}
public static String getRegionName(int x, int z) {
return String.format("r.%c%X%c%X.rgn", x < 0 ? 'n' : 'p', ((x < 0) ? -x : x) >> 3, z < 0 ? 'n' : 'p', ((z < 0) ? -z : z) >> 3);
}
public static Chunk readNbt(WorldServer world, int x, int z, NBTTagCompound tag) {
// if(!tag.hasKey("Level", 10)) {
// Log.error("Chunk-Datei bei " + x + "," + z + " hat keine Level-Daten, überspringe");
// return null;
// }
// tag = tag.getCompoundTag("Level");
if(!tag.hasKey("Sections", 9)) {
Log.JNI.warn("Chunk-Datei bei " + x + "," + z + " hat keine Block-Daten, überspringe");
return null;
}
Chunk chunk = new Chunk(world, x, z);
chunk.setHeights(tag.getIntArray("HeightMap"));
chunk.setTerrainPopulated(tag.getBoolean("TerrainPopulated"));
chunk.setLightPopulated(tag.getBoolean("LightPopulated"));
chunk.setInhabited(tag.getLong("InhabitedTime"));
NBTTagList sects = tag.getTagList("Sections", 10);
int stor = 32;
BlockArray[] sections = new BlockArray[stor];
boolean light = !world.dimension.hasNoLight();
for(int n = 0; n < sects.tagCount(); ++n) {
NBTTagCompound sect = sects.getCompoundTagAt(n);
int y = sect.getByte("Y");
BlockArray storage = new BlockArray(y << 4, light);
byte[] blocks = sect.getByteArray("Blocks");
NibbleArray data = new NibbleArray(sect.getByteArray("Data"));
NibbleArray adddata = sect.hasKey("Add", 7) ? new NibbleArray(sect.getByteArray("Add")) : null;
char[] seg = new char[blocks.length];
for(int c = 0; c < seg.length; ++c) {
int cx = c & 15;
int cy = c >> 8 & 15;
int cz = c >> 4 & 15;
int ca = adddata != null ? adddata.get(cx, cy, cz) : 0;
seg[c] = (char)(ca << 12 | (blocks[c] & 255) << 4 | data.get(cx, cy, cz));
}
storage.setData(seg);
storage.setBlocklight(new NibbleArray(sect.getByteArray("BlockLight")));
if(light) {
storage.setSkylight(new NibbleArray(sect.getByteArray("SkyLight")));
}
storage.update();
sections[y] = storage;
}
chunk.setStorage(sections);
if(tag.hasKey("Biomes", 7)) {
chunk.setBiomes(tag.getByteArray("Biomes"));
}
NBTTagList entities = tag.getTagList("Entities", 10);
if(entities != null) {
for(int n = 0; n < entities.tagCount(); ++n) {
NBTTagCompound ent = entities.getCompoundTagAt(n);
Entity entity = EntityRegistry.createEntityFromNBT(ent, world);
chunk.setHasEntities(true);
if(entity != null) {
chunk.addEntity(entity);
Entity rider = entity;
for(NBTTagCompound ride = ent; ride.hasKey("Riding", 10); ride = ride.getCompoundTag("Riding")) {
Entity pass = EntityRegistry.createEntityFromNBT(ride.getCompoundTag("Riding"), world);
if(pass != null) {
chunk.addEntity(pass);
rider.mountEntity(pass);
}
rider = pass;
}
}
}
}
NBTTagList tiles = tag.getTagList("TileEntities", 10);
if(tiles != null) {
for(int n = 0; n < tiles.tagCount(); ++n) {
NBTTagCompound tile = tiles.getCompoundTagAt(n);
TileEntity tileentity = TileEntity.createAndLoadEntity(tile);
if(tileentity != null) {
chunk.addTileEntity(tileentity);
}
}
}
if(tag.hasKey("TileTicks", 9)) {
NBTTagList ticks = tag.getTagList("TileTicks", 10);
if(ticks != null) {
int invalid = 0;
for(int n = 0; n < ticks.tagCount(); ++n) {
NBTTagCompound tick = ticks.getCompoundTagAt(n);
Block block;
if(tick.hasKey("i", 8)) {
block = BlockRegistry.getByIdFallback(tick.getString("i"));
}
else {
block = BlockRegistry.getBlockById(tick.getInteger("i"));
}
if(block != null) { // FIX
world.scheduleBlockUpdate(new BlockPos(tick.getInteger("x"), tick.getInteger("y"), tick.getInteger("z")), block,
tick.getInteger("t"), tick.getInteger("p"));
}
else if(invalid++ < 10) {
Log.JNI.warn("Unbekannter Block-Tick in Chunk " + x + "," + z + ": " +
(tick.hasKey("i", 8) ? ("'" + tick.getString("i") + "'") : ("#" + tick.getInteger("i"))));
}
}
if(invalid > 10) {
Log.JNI.warn((invalid - 10) + " weitere ...");
}
}
}
return chunk;
}
public static NBTTagCompound writeNbt(WorldServer world, Chunk chunk) {
NBTTagCompound tag = new NBTTagCompound();
// tag.setShort("V", (short)Config.PROTOCOL);
tag.setLong("LastUpdate", world.getTime());
tag.setIntArray("HeightMap", chunk.getHeights());
tag.setBoolean("TerrainPopulated", chunk.isTerrainPopulated());
tag.setBoolean("LightPopulated", chunk.isLightPopulated());
tag.setLong("InhabitedTime", chunk.getInhabited());
BlockArray[] sections = chunk.getStorage();
NBTTagList sects = new NBTTagList();
boolean light = !world.dimension.hasNoLight();
for(BlockArray storage : sections) {
if(storage != null) {
NBTTagCompound sect = new NBTTagCompound();
sect.setByte("Y", (byte)(storage.getY() >> 4 & 511));
byte[] blocks = new byte[storage.getData().length];
NibbleArray data = new NibbleArray();
NibbleArray adddata = null;
for(int c = 0; c < storage.getData().length; ++c) {
char cd = storage.getData()[c];
int cx = c & 15;
int cy = c >> 8 & 15;
int cz = c >> 4 & 15;
if(cd >> 12 != 0) {
if(adddata == null) {
adddata = new NibbleArray();
}
adddata.set(cx, cy, cz, cd >> 12);
}
blocks[c] = (byte)(cd >> 4 & 255);
data.set(cx, cy, cz, cd & 15);
}
sect.setByteArray("Blocks", blocks);
sect.setByteArray("Data", data.getData());
if(adddata != null) {
sect.setByteArray("Add", adddata.getData());
}
sect.setByteArray("BlockLight", storage.getBlocklight().getData());
if(light) {
sect.setByteArray("SkyLight", storage.getSkylight().getData());
}
else {
sect.setByteArray("SkyLight", new byte[storage.getBlocklight().getData().length]);
}
sects.appendTag(sect);
}
}
tag.setTag("Sections", sects);
tag.setByteArray("Biomes", chunk.getBiomes());
chunk.setHasEntities(false);
NBTTagList entities = new NBTTagList();
for(int n = 0; n < chunk.getEntities().length; ++n) {
for(Entity entity : chunk.getEntities()[n]) {
NBTTagCompound ent = new NBTTagCompound();
if(entity.writeToNBTOptional(ent)) {
chunk.setHasEntities(true);
entities.appendTag(ent);
}
}
}
tag.setTag("Entities", entities);
NBTTagList tiles = new NBTTagList();
for(TileEntity tileentity : chunk.getTiles().values()) {
NBTTagCompound tile = new NBTTagCompound();
tileentity.writeToNBT(tile);
tiles.appendTag(tile);
}
tag.setTag("TileEntities", tiles);
List<NextTickListEntry> tics = world.getPendingBlockUpdates(chunk);
if(tics != null) {
long time = world.getTime();
NBTTagList ticks = new NBTTagList();
for(NextTickListEntry tic : tics) {
NBTTagCompound tick = new NBTTagCompound();
String res = BlockRegistry.REGISTRY.getNameForObject(tic.getBlock());
tick.setString("i", res == null ? "" : res.toString());
tick.setInteger("x", tic.position.getX());
tick.setInteger("y", tic.position.getY());
tick.setInteger("z", tic.position.getZ());
tick.setInteger("t", (int)(tic.scheduledTime - time));
tick.setInteger("p", tic.priority);
ticks.appendTag(tick);
}
tag.setTag("TileTicks", ticks);
}
return tag;
}
private static void processQueue() {
for(int i = 0; i < QUEUE.size(); ++i) {
WorldServer loader = QUEUE.get(i);
boolean flag = loader.writeNextIO();
if(!flag) {
QUEUE.remove(i--);
++saved;
}
try {
Thread.sleep(waiting ? 0L : 10L);
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
if(QUEUE.isEmpty()) {
try {
Thread.sleep(25L);
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public static void queueIO(WorldServer loader) {
if(!QUEUE.contains(loader)) {
++queued;
QUEUE.add(loader);
}
}
public static void killIO() {
killed = true;
}
public static void saveWorldInfo(File worldDir, long time, String owner) {
NBTTagCompound data = new NBTTagCompound();
data.setLong("Time", time);
data.setLong("LastAccess", System.currentTimeMillis());
data.setString("Version", Config.VERSION);
NBTTagCompound cfg = new NBTTagCompound();
for(String cvar : Config.VARS.keySet()) {
cfg.setString(cvar, Config.VARS.get(cvar).getValue());
// Config.Value value = Config.VARS.get(cvar);
// switch(value.getType()) {
// case BOOLEAN:
// cfg.setString(cvar, "" + value.getBoolean());
// break;
// case INTEGER:
// cfg.setString(cvar, "" + value.getInt());
// break;
// case FLOAT:
// cfg.setString(cvar, "" + value.getFloat());
// break;
// case STRING:
// cfg.setString(cvar, value.getString());
// break;
// }
}
data.setTag("Config", cfg);
data.setTag("Universe", UniverseRegistry.saveNbt());
if(owner != null)
data.setString("Owner", owner);
if(worldDir != null)
worldDir.mkdirs();
File nfile = new File(worldDir, "level.nbt.tmp");
File lfile = new File(worldDir, "level.nbt");
try {
// File ofile = new File(worldDir, "level.nbt_old");
NBTLoader.writeGZip(data, nfile);
// if(ofile.exists())
// ofile.delete();
// lfile.renameTo(ofile);
if(lfile.exists())
lfile.delete();
nfile.renameTo(lfile);
// if(nfile.exists())
// nfile.delete();
}
catch(Exception e) {
Log.JNI.error(e, "Fehler beim Schreiben von " + nfile);
}
}
public static FolderInfo loadWorldInfo(File worldDir) {
Config.clear();
UniverseRegistry.clear();
File file = new File(worldDir, "level.nbt");
if(!file.exists())
file = new File(worldDir, "level.nbt.tmp");
if(file.exists()) {
try {
NBTTagCompound tag = NBTLoader.readGZip(file);
NBTTagCompound cfg = tag.getCompoundTag("Config");
for(String key : cfg.getKeySet()) {
Config.set(key, cfg.getString(key), null);
}
UniverseRegistry.loadNbt(tag.getCompoundTag("Universe"));
// tag.getInteger("Version");
long lastPlayed = tag.getLong("LastAccess");
String user = tag.hasKey("Owner", 8) ? tag.getString("Owner") : null;
user = user != null && user.isEmpty() ? null : user;
String version = tag.hasKey("Version", 8) ? tag.getString("Version") : null;
version = version != null && version.isEmpty() ? null : version;
long time = tag.hasKey("Time", 4) ? tag.getLong("Time") : World.START_TIME;
return new FolderInfo(time, user, lastPlayed, null, version);
}
catch(Exception e) {
Log.JNI.error(e, "Fehler beim Lesen von " + file);
}
}
return null;
}
// public static void reloadWorldInfo(File worldDir) {
// File file = new File(worldDir, "level.nbt");
// if(file.exists()) {
// Config.clear();
// try {
// Config.readFromNbt(NBTLoader.readGZip(file).getCompoundTag("Config"), true);
// }
// catch(Exception e) {
// Log.error("Fehler beim Lesen von " + file, e);
// return;
// }
// }
// }
}

209
java/src/game/world/Spawner.java Executable file
View file

@ -0,0 +1,209 @@
package game.world;
import java.util.Set;
import game.ExtMath;
import game.biome.Biome;
import game.block.Block;
import game.collect.Sets;
import game.entity.npc.EntityNPC;
import game.entity.types.EntityLiving;
import game.entity.types.EntityWaterMob;
import game.init.Blocks;
import game.init.Config;
import game.rng.Random;
import game.rng.WeightedList;
public abstract class Spawner {
private static final int MOB_COUNT_DIV = (int)Math.pow(17.0D, 2.0D);
private static final Set<ChunkPos> CHUNKS = Sets.<ChunkPos>newHashSet();
public static boolean canSpawnAt(boolean water, WorldServer world, BlockPos pos) {
if(!World.isValidXZ(pos)) {
return false;
}
Block block = world.getState(pos).getBlock();
if(water) {
return block.getMaterial().isLiquid() && world.getState(pos.down()).getBlock().getMaterial().isLiquid()
&& !world.getState(pos.up()).getBlock().isNormalCube();
}
// else if(place == SpawnRegistry.Placement.IN_AIR) {
// return pos.getY() >= 118;
// }
else {
BlockPos down = pos.down();
if(!world.isBlockSolid(down)) {
return false;
}
else {
Block below = world.getState(down).getBlock();
return below != Blocks.bedrock && !block.isNormalCube() && !block.getMaterial().isLiquid()
&& !world.getState(pos.up()).getBlock().isNormalCube();
}
}
}
public static int spawn(WorldServer world) {
// if(!hostile && !peaceful) {
// return 0;
// }
CHUNKS.clear();
int locs = 0;
int range = Math.max(Config.mobSpawnDist, 1);
for(EntityNPC player : world.players) {
// if(Config.spectatorSpawning || !player.isSpectator()) {
int x = ExtMath.floord(player.posX / 16.0D);
int z = ExtMath.floord(player.posZ / 16.0D);
for(int cx = -range; cx <= range; ++cx) {
for(int cz = -range; cz <= range; ++cz) {
boolean flag = cx == -range || cx == range || cz == -range || cz == range;
ChunkPos coord = new ChunkPos(cx + x, cz + z);
if(!CHUNKS.contains(coord)) {
++locs;
if(!flag && coord.x << 4 >= -World.MAX_SIZE + 64 && coord.z << 4 >= -World.MAX_SIZE + 64
&& coord.x << 4 < World.MAX_SIZE - 64 && coord.z << 4 < World.MAX_SIZE - 64) {
CHUNKS.add(coord);
}
}
}
}
// }
}
// boolean animals = (time % Math.max(Config.animalSpawnDelay, 1)) == 0;
int spawned = 0;
int mobSpread = Math.max(Config.spawnGroupDist, 1);
// double spawnDist = (double)Config.mobSpawnDistance;
double playerDist = (double)Config.mobPlayerDist;
// BlockPos spawn = world.isPrimary() ? Server.getSpawnPoint() : null;
// for(EnumCreatureType type : EnumCreatureType.values()) {
// if((!type.isPeaceful() || peaceful) && (type.isPeaceful() || hostile) && (!type.isAnimal() || animals)) {
int cur = world.countEntities(EntityLiving.class);
int max = Config.maxMobs * locs / MOB_COUNT_DIV;
if(cur <= max) {
typeLabel:
for(ChunkPos coord : CHUNKS) {
Chunk chunk = world.getChunk(coord.x, coord.z);
int x = coord.x * 16 + world.rand.zrange(16);
int z = coord.z * 16 + world.rand.zrange(16);
int h = chunk.getHeight(new BlockPos(x, 0, z)) + 1;
if(h > 0) {
int m = h % 16;
h = m == 0 ? h : h + 16 - m;
}
h = h == 0 ? 16 : (h > 0 ? h : chunk.getTopSegment() + 16 - 1);
int y = world.rand.excl(h <= 8 ? 0 : 8, h);
BlockPos pos = new BlockPos(x, y, z);
Block block = world.getState(pos).getBlock();
if(!block.isNormalCube()) {
int group = 0;
Object data = null;
for(int n = 0; n < Config.spawnGroups; ++n) {
int mx = x;
int my = y;
int mz = z;
Biome.RngSpawn entry = null;
int cmax = 4;
for(int m = 0; m < cmax; ++m) {
mx += world.rand.zrange(mobSpread) - world.rand.zrange(mobSpread);
my += world.rand.zrange(1) - world.rand.zrange(1);
mz += world.rand.zrange(mobSpread) - world.rand.zrange(mobSpread);
BlockPos mpos = new BlockPos(mx, my, mz);
float fx = (float)mx + 0.5F;
float fz = (float)mz + 0.5F;
if(!world.isAnyPlayerWithinRangeAt((double)fx, (double)my, (double)fz, playerDist)) {
// && (spawn == null || spawn.distanceSq((double)fx, (double)my, (double)fz) >= spawnDist)) {
if(entry == null) {
entry = world.getSpawnListEntryForTypeAt(mpos);
if(entry == null) {
break;
}
cmax = m + entry.minGroupCount + world.rand.zrange(1 + entry.maxGroupCount - entry.minGroupCount);
}
if(world.canCreatureTypeSpawnHere(entry, mpos)
&& canSpawnAt(EntityWaterMob.class.isAssignableFrom(entry.entityClass), world, mpos)) {
EntityLiving entity;
try {
entity = entry.entityClass.getConstructor(World.class).newInstance(world);
}
catch(Exception e) {
e.printStackTrace();
return spawned + group;
}
entity.setLocationAndAngles((double)fx, (double)my, (double)fz, world.rand.floatv() * 360.0F, 0.0F);
if(entity.getCanSpawnHere() && entity.isNotColliding()) {
data = entity.onInitialSpawn(data);
if(entity.isNotColliding()) {
++group;
world.spawnEntityInWorld(entity);
}
if(group >= entity.getMaxChunkSpawns()) {
spawned += group;
continue typeLabel;
}
else if(!entity.isPropogatingSpawnData(m >= cmax - 1)) {
data = null;
}
}
}
}
}
}
spawned += group;
}
}
// }
// }
}
return spawned;
}
public static void generate(WorldServer world, Biome biome, int x, int z, int sx, int sz, Random rand) {
int iters = 0;
while(rand.floatv() < biome.getSpawningChance()) {
if(iters++ == 10)
break;
WeightedList<Biome.RngSpawn> list = biome.getSpawnableList();
if(list.isEmpty()) {
continue;
}
Biome.RngSpawn entry = list.pick(world.rand);
int count = entry.minGroupCount + rand.zrange(1 + entry.maxGroupCount - entry.minGroupCount);
Object data = null;
int mx = x + rand.zrange(sx);
int mz = z + rand.zrange(sz);
int gx = mx;
int gz = mz;
for(int n = 0; n < count; ++n) {
boolean flag = false;
for(int m = 0; !flag && m < 4; ++m) {
BlockPos pos = world.getTopSolidOrLiquidBlock(new BlockPos(mx, 0, mz));
if(canSpawnAt(EntityWaterMob.class.isAssignableFrom(entry.entityClass), world, pos)) {
EntityLiving entity;
try {
entity = entry.entityClass.getConstructor(World.class).newInstance(world);
}
catch(Exception e) {
e.printStackTrace();
continue;
}
entity.setLocationAndAngles((double)((float)mx + 0.5F), (double)pos.getY(), (double)((float)mz + 0.5F),
rand.floatv() * 360.0F, 0.0F);
if(entity.getCanSpawnHere() && entity.isNotColliding()) {
data = entity.onInitialSpawn(data);
if(entity.isNotColliding())
world.spawnEntityInWorld(entity);
if(!entity.isPropogatingSpawnData(false))
data = null;
flag = true;
}
}
mx += rand.zrange(5) - rand.zrange(5);
for(mz += rand.zrange(5) - rand.zrange(5); mx < x || mx >= x + sx || mz < z
|| mz >= z + sx; mz = gz + rand.zrange(5) - rand.zrange(5)) {
mx = gx + rand.zrange(5) - rand.zrange(5);
}
}
}
}
}
}

138
java/src/game/world/State.java Executable file
View file

@ -0,0 +1,138 @@
package game.world;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import game.block.Block;
import game.collect.ImmutableMap;
import game.collect.ImmutableTable;
import game.collect.Iterables;
import game.collect.Maps;
import game.collect.StandardTable;
import game.collect.Table;
import game.init.BlockRegistry;
import game.properties.IProperty;
public class State {
// private static final Joiner COMMA_JOINER = Joiner.on(',');
private static final Function<Entry<IProperty, Comparable>, String> MAP_ENTRY_TO_STRING =
new Function<Entry<IProperty, Comparable>, String>() {
public String apply(Entry<IProperty, Comparable> entry) {
if(entry == null) {
return "<NULL>";
}
else {
IProperty prop = entry.getKey();
return prop.getName() + "=" + prop.getName(entry.getValue());
}
}
};
private final Block block;
private final ImmutableMap<IProperty, Comparable> properties;
private ImmutableTable<IProperty, Comparable, State> map;
public State(Block block, ImmutableMap<IProperty, Comparable> properties) {
this.block = block;
this.properties = properties;
}
public <T extends Comparable<T>> State cycleProperty(IProperty<T> property) {
Collection<T> values = property.getAllowedValues();
T value = this.getValue(property);
Iterator<T> iter = values.iterator();
while(iter.hasNext()) {
if(iter.next().equals(value)) {
if(iter.hasNext())
return this.withProperty(property, (T)iter.next());
return this.withProperty(property, (T)values.iterator().next());
}
}
return this.withProperty(property, (T)iter.next());
}
public Collection<IProperty> getPropertyNames() {
return Collections.<IProperty>unmodifiableCollection(this.properties.keySet());
}
public <T extends Comparable<T>> T getValue(IProperty<T> property) {
if(!this.properties.containsKey(property)) {
throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.block);
}
else {
return (T)((Comparable)property.getValueClass().cast(this.properties.get(property)));
}
}
public <T extends Comparable<T>, V extends T> State withProperty(IProperty<T> property, V value) {
if(!this.properties.containsKey(property)) {
throw new IllegalArgumentException("Cannot set property " + property + " as it does not exist in " + this.block);
}
else if(!property.getAllowedValues().contains(value)) {
throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on block "
+ BlockRegistry.REGISTRY.getNameForObject(this.block) + ", it is not an allowed value");
}
else {
return (State)(this.properties.get(property) == value ? this : (State)this.map.get(property, value));
}
}
public ImmutableMap<IProperty, Comparable> getProperties() {
return this.properties;
}
public Block getBlock() {
return this.block;
}
public boolean equals(Object obj) {
return this == obj;
}
public int hashCode() {
return this.properties.hashCode();
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(BlockRegistry.REGISTRY.getNameForObject(this.getBlock()));
if(!this.getProperties().isEmpty()) {
sb.append("[");
Iterable<String> iter = Iterables.transform(this.getProperties().entrySet(), MAP_ENTRY_TO_STRING);
boolean flag = false;
for(String s : iter) {
if(flag)
sb.append(",");
else
flag = true;
sb.append(s);
}
// COMMA_JOINER.appendTo(sb, );
sb.append("]");
}
return sb.toString();
}
public void buildTable(Map<Map<IProperty, Comparable>, State> map) {
if(this.map != null) {
throw new IllegalStateException();
}
else {
Table<IProperty, Comparable, State> table = new StandardTable<IProperty, Comparable, State>();
for(IProperty<? extends Comparable> prop : this.properties.keySet()) {
for(Comparable value : prop.getAllowedValues()) {
if(value != this.properties.get(prop)) {
Map<IProperty, Comparable> props = Maps.<IProperty, Comparable>newHashMap(this.properties);
props.put(prop, value);
table.put(prop, value, map.get(props));
}
}
}
this.map = ImmutableTable.<IProperty, Comparable, State>copyOf(table);
}
}
}

219
java/src/game/world/Vec3.java Executable file
View file

@ -0,0 +1,219 @@
package game.world;
import game.ExtMath;
import game.renderer.model.PositionTextureVertex;
public class Vec3
{
public final double xCoord;
public final double yCoord;
public final double zCoord;
public Vec3(double x, double y, double z)
{
if (x == -0.0D)
{
x = 0.0D;
}
if (y == -0.0D)
{
y = 0.0D;
}
if (z == -0.0D)
{
z = 0.0D;
}
this.xCoord = x;
this.yCoord = y;
this.zCoord = z;
}
public Vec3(Vec3i p_i46377_1_)
{
this((double)p_i46377_1_.getX(), (double)p_i46377_1_.getY(), (double)p_i46377_1_.getZ());
}
public Vec3(int color) {
this((float)(color >> 16 & 255) / 255.0F, (float)(color >> 8 & 255) / 255.0F, (float)(color & 255) / 255.0F);
}
/**
* Returns a new vector with the result of the specified vector minus this.
*/
public Vec3 subtractReverse(Vec3 vec)
{
return new Vec3(vec.xCoord - this.xCoord, vec.yCoord - this.yCoord, vec.zCoord - this.zCoord);
}
/**
* Normalizes the vector to a length of 1 (except if it is the zero vector)
*/
public Vec3 normalize()
{
double d0 = (double)ExtMath.sqrtd(this.xCoord * this.xCoord + this.yCoord * this.yCoord + this.zCoord * this.zCoord);
return d0 < 1.0E-4D ? new Vec3(0.0D, 0.0D, 0.0D) : new Vec3(this.xCoord / d0, this.yCoord / d0, this.zCoord / d0);
}
public double dotProduct(Vec3 vec)
{
return this.xCoord * vec.xCoord + this.yCoord * vec.yCoord + this.zCoord * vec.zCoord;
}
/**
* Returns a new vector with the result of this vector x the specified vector.
*/
public Vec3 crossProduct(Vec3 vec)
{
return new Vec3(this.yCoord * vec.zCoord - this.zCoord * vec.yCoord, this.zCoord * vec.xCoord - this.xCoord * vec.zCoord, this.xCoord * vec.yCoord - this.yCoord * vec.xCoord);
}
public Vec3 subtract(Vec3 vec)
{
return this.subtract(vec.xCoord, vec.yCoord, vec.zCoord);
}
public Vec3 subtract(double x, double y, double z)
{
return this.addVector(-x, -y, -z);
}
public Vec3 add(Vec3 vec)
{
return this.addVector(vec.xCoord, vec.yCoord, vec.zCoord);
}
/**
* Adds the specified x,y,z vector components to this vector and returns the resulting vector. Does not change this
* vector.
*/
public Vec3 addVector(double x, double y, double z)
{
return new Vec3(this.xCoord + x, this.yCoord + y, this.zCoord + z);
}
/**
* Euclidean distance between this and the specified vector, returned as double.
*/
public double distanceTo(Vec3 vec)
{
double d0 = vec.xCoord - this.xCoord;
double d1 = vec.yCoord - this.yCoord;
double d2 = vec.zCoord - this.zCoord;
return (double)ExtMath.sqrtd(d0 * d0 + d1 * d1 + d2 * d2);
}
/**
* The square of the Euclidean distance between this and the specified vector.
*/
public double squareDistanceTo(Vec3 vec)
{
double d0 = vec.xCoord - this.xCoord;
double d1 = vec.yCoord - this.yCoord;
double d2 = vec.zCoord - this.zCoord;
return d0 * d0 + d1 * d1 + d2 * d2;
}
/**
* Returns the length of the vector.
*/
public double lengthVector()
{
return (double)ExtMath.sqrtd(this.xCoord * this.xCoord + this.yCoord * this.yCoord + this.zCoord * this.zCoord);
}
/**
* Returns a new vector with x value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*/
public Vec3 getIntermediateWithXValue(Vec3 vec, double x)
{
double d0 = vec.xCoord - this.xCoord;
double d1 = vec.yCoord - this.yCoord;
double d2 = vec.zCoord - this.zCoord;
if (d0 * d0 < 1.0000000116860974E-7D)
{
return null;
}
else
{
double d3 = (x - this.xCoord) / d0;
return d3 >= 0.0D && d3 <= 1.0D ? new Vec3(this.xCoord + d0 * d3, this.yCoord + d1 * d3, this.zCoord + d2 * d3) : null;
}
}
/**
* Returns a new vector with y value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*/
public Vec3 getIntermediateWithYValue(Vec3 vec, double y)
{
double d0 = vec.xCoord - this.xCoord;
double d1 = vec.yCoord - this.yCoord;
double d2 = vec.zCoord - this.zCoord;
if (d1 * d1 < 1.0000000116860974E-7D)
{
return null;
}
else
{
double d3 = (y - this.yCoord) / d1;
return d3 >= 0.0D && d3 <= 1.0D ? new Vec3(this.xCoord + d0 * d3, this.yCoord + d1 * d3, this.zCoord + d2 * d3) : null;
}
}
/**
* Returns a new vector with z value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*/
public Vec3 getIntermediateWithZValue(Vec3 vec, double z)
{
double d0 = vec.xCoord - this.xCoord;
double d1 = vec.yCoord - this.yCoord;
double d2 = vec.zCoord - this.zCoord;
if (d2 * d2 < 1.0000000116860974E-7D)
{
return null;
}
else
{
double d3 = (z - this.zCoord) / d2;
return d3 >= 0.0D && d3 <= 1.0D ? new Vec3(this.xCoord + d0 * d3, this.yCoord + d1 * d3, this.zCoord + d2 * d3) : null;
}
}
public String toString()
{
return "(" + this.xCoord + ", " + this.yCoord + ", " + this.zCoord + ")";
}
public Vec3 rotatePitch(float pitch)
{
float f = ExtMath.cos(pitch);
float f1 = ExtMath.sin(pitch);
double d0 = this.xCoord;
double d1 = this.yCoord * (double)f + this.zCoord * (double)f1;
double d2 = this.zCoord * (double)f - this.yCoord * (double)f1;
return new Vec3(d0, d1, d2);
}
public Vec3 rotateYaw(float yaw)
{
float f = ExtMath.cos(yaw);
float f1 = ExtMath.sin(yaw);
double d0 = this.xCoord * (double)f + this.zCoord * (double)f1;
double d1 = this.yCoord;
double d2 = this.zCoord * (double)f - this.xCoord * (double)f1;
return new Vec3(d0, d1, d2);
}
public PositionTextureVertex toTextureVertex(float tx, float ty)
{
return new PositionTextureVertex(this, tx, ty);
}
}

124
java/src/game/world/Vec3i.java Executable file
View file

@ -0,0 +1,124 @@
package game.world;
import game.ExtMath;
public class Vec3i implements Comparable<Vec3i>
{
// /** The Null vector constant (0, 0, 0) */
// public static final Vec3i NULL_VECTOR = new Vec3i(0, 0, 0);
/** X coordinate */
private final int x;
/** Y coordinate */
private final int y;
/** Z coordinate */
private final int z;
public Vec3i(int xIn, int yIn, int zIn)
{
this.x = xIn;
this.y = yIn;
this.z = zIn;
}
public Vec3i(double xIn, double yIn, double zIn)
{
this(ExtMath.floord(xIn), ExtMath.floord(yIn), ExtMath.floord(zIn));
}
public boolean equals(Object p_equals_1_)
{
if (this == p_equals_1_)
{
return true;
}
else if (!(p_equals_1_ instanceof Vec3i))
{
return false;
}
else
{
Vec3i vec3i = (Vec3i)p_equals_1_;
return this.getX() != vec3i.getX() ? false : (this.getY() != vec3i.getY() ? false : this.getZ() == vec3i.getZ());
}
}
public int hashCode()
{
return (this.getY() + this.getZ() * 31) * 31 + this.getX();
}
public int compareTo(Vec3i p_compareTo_1_)
{
return this.getY() == p_compareTo_1_.getY() ? (this.getZ() == p_compareTo_1_.getZ() ? this.getX() - p_compareTo_1_.getX() : this.getZ() - p_compareTo_1_.getZ()) : this.getY() - p_compareTo_1_.getY();
}
/**
* Get the X coordinate
*/
public int getX()
{
return this.x;
}
/**
* Get the Y coordinate
*/
public int getY()
{
return this.y;
}
/**
* Get the Z coordinate
*/
public int getZ()
{
return this.z;
}
/**
* Calculate the cross product of this and the given Vector
*/
public Vec3i crossProduct(Vec3i vec)
{
return new Vec3i(this.getY() * vec.getZ() - this.getZ() * vec.getY(), this.getZ() * vec.getX() - this.getX() * vec.getZ(), this.getX() * vec.getY() - this.getY() * vec.getX());
}
/**
* Calculate squared distance to the given coordinates
*/
public double distanceSq(double toX, double toY, double toZ)
{
double d0 = (double)this.getX() - toX;
double d1 = (double)this.getY() - toY;
double d2 = (double)this.getZ() - toZ;
return d0 * d0 + d1 * d1 + d2 * d2;
}
/**
* Compute square of distance from point x, y, z to center of this Block
*/
public double distanceSqToCenter(double xIn, double yIn, double zIn)
{
double d0 = (double)this.getX() + 0.5D - xIn;
double d1 = (double)this.getY() + 0.5D - yIn;
double d2 = (double)this.getZ() + 0.5D - zIn;
return d0 * d0 + d1 * d1 + d2 * d2;
}
/**
* Calculate squared distance to the given Vector
*/
public double distanceSq(Vec3i to)
{
return this.distanceSq((double)to.getX(), (double)to.getY(), (double)to.getZ());
}
public String toString()
{
return this.getX() + ", " + this.getY() + ", " + this.getZ();
}
}

141
java/src/game/world/Weather.java Executable file
View file

@ -0,0 +1,141 @@
package game.world;
import java.util.Map;
import game.collect.Maps;
import game.rng.Random;
import game.rng.RngItem;
import game.rng.WeightedList;
public enum Weather {
CLEAR("clear", "Schön", 0.0f, 0.0f, 12, 30, 9, 7),
FOG("fog", "Nebel", -0.2f, 0.8f, 15, 12, 20, 14),
COLD("cold", "Kalt", -0.4f, 0.1f, 20, 18, 25, 10),
HOT("hot", "Heiß", 0.1f, 0.0f, 0, 1, 0, 0),
FROST("frost", "Frost", -0.75f, 0.8f, 5, 4, 8, 4),
RAIN("rain", "Regen", false, -0.05f, 0.4f, 30, 45, 40, 25),
THUNDER("thunder", "Gewitter", true, -0.3f, 0.3f, 15, 25, 60, 8),
SNOW("snow", "Schnee", false, -0.85f, 0.3f, 10, 4, 14, 30),
HAIL("hail", "Hagel", false, -0.35f, 0.4f, 5, 8, 12, 3),
STORM("storm", "Sturm", false, true, -0.3f, 0.3f, 5, 10, 20, 15),
HAILSTORM("hailstorm", "Hagelsturm", true, -0.35f, 0.3f, 2, 1, 4, 2),
ICE("ice", "Eis", -0.85f, 0.15f, 10, 4, 16, 4),
SNOWSTORM("snowstorm", "Schneesturm", true, -0.85f, 0.25f, 2, 0, 2, 5),
CHILLED("chilled", "Permafrost", -8.0f, 0.0f),
ICEAGE("iceage", "Eiszeit", false, -8.0f, 0.45f),
FIRE("fire", "Feuer", 8.0f, 0.0f),
INFERNO("inferno", "Inferno", true, 8.0f, 0.0f);
private static final Map<String, Weather> LOOKUP = Maps.newHashMap();
private final boolean downfall;
private final boolean dark;
private final float temperature;
private final float fog;
private final String name;
private final String display;
private static class RngWeather extends RngItem {
private static final WeightedList<RngWeather>[] LISTS = new WeightedList[4];
static {
for(int z = 0; z < LISTS.length; z++) {
LISTS[z] = new WeightedList<RngWeather>();
}
}
private final Weather weather;
private RngWeather(Weather weather, int weight) {
super(weight);
this.weather = weather;
}
}
private Weather(String name, String display, float temp, float fog, int ... chances) {
this(name, display, false, false, temp, fog, chances);
}
private Weather(String name, String display, boolean dark, float temp, float fog, int ... chances) {
this(name, display, true, dark, temp, fog, chances);
}
private Weather(String name, String display, boolean downfall, boolean dark, float temp, float fog, int ... chances) {
this.name = name;
this.display = display;
this.downfall = downfall;
this.dark = dark;
this.temperature = temp * 40.0f;
this.fog = fog;
for(int z = 0; chances.length > 0 && z < RngWeather.LISTS.length; z++) {
int chance = z >= chances.length ? chances[0] : chances[z];
if(chance > 0)
RngWeather.LISTS[z].add(new RngWeather(this, chance));
}
}
public int getID() {
return this.ordinal();
}
public String getName() {
return this.name;
}
public String getDisplay() {
return this.display;
}
public boolean hasDownfall() {
return this.downfall;
}
public boolean hasThunder() {
return this.dark;
}
public boolean canRain() {
return this.temperature < 100.0f;
}
public boolean isDark() {
return this.dark;
}
public float getTemperature() {
return this.temperature;
}
public float getFogIntensity() {
return this.fog;
}
public static Weather getByID(int id) {
if(id >= 0 && id < values().length)
return values()[id];
return CLEAR;
}
public static Weather getByName(String name) {
return LOOKUP.get(name.toLowerCase());
// return type == null ? CLEAR : type;
// for(Weather weather : values()) {
// if(("" + weather.getID()).equals(name) || weather.getName().equalsIgnoreCase(name)) {
//// || weather.getName().substring(0, 1).equalsIgnoreCase(name)) {
// return weather;
// }
// }
// return null;
}
static {
for(Weather type : values()) {
LOOKUP.put(type.name, type);
}
}
public static Weather pick(float temp, Random rand) {
temp = World.ABSOLUTE_ZERO + temp;
return RngWeather.LISTS[temp <= 0.0f ? 3 : (temp <= 12.5f ? 2 : (temp <= 25.0f ? 0 : 1))].pick(rand).weather;
}
}

2139
java/src/game/world/World.java Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,923 @@
package game.world;
import java.util.List;
import java.util.Set;
import game.ExtMath;
import game.Game;
import game.Log;
import game.audio.MovingSoundMinecart;
import game.audio.PositionedSound;
import game.biome.Biome;
import game.block.Block;
import game.collect.Lists;
import game.collect.Sets;
import game.dimension.Dimension;
import game.entity.Entity;
import game.entity.item.EntityCart;
import game.entity.npc.EntityNPC;
import game.init.BlockRegistry;
import game.init.ItemRegistry;
import game.init.Items;
import game.init.SoundEvent;
import game.item.ItemDye;
import game.material.Material;
import game.nbt.NBTTagCompound;
import game.renderer.particle.EntityFX;
import game.renderer.particle.EntityFirework;
import game.renderer.particle.ParticleType;
import game.rng.Random;
import game.tileentity.TileEntity;
import game.world.BlockPos.MutableBlockPos;
public class WorldClient extends World
{
private static final int DISPLAY_RANGE = 16;
private final Game gm = Game.getGame();
private final Set<Entity> entityList = Sets.<Entity>newHashSet();
private final Set<Entity> spawnQueue = Sets.<Entity>newHashSet();
private final Set<ChunkPos> previousActive = Sets.<ChunkPos>newHashSet();
private final LongHashMap<Chunk> chunkMapping = new LongHashMap();
private final List<Chunk> chunkListing = Lists.<Chunk>newArrayList();
private final Chunk blankChunk = new EmptyChunk(this);
// public final Profiler profiler;
protected int lastLightning;
protected Vec3 lightColor = new Vec3(0xffffff);
public WorldClient(boolean debug, Dimension dim)
{
super(dim, true, debug);
// this.gm = profiler;
this.calculateInitialSkylight();
this.calculateInitialWeather();
this.setGravity(this.gm.gravity);
this.setTimeFactor(this.gm.timeFactor);
// this.setDifficulty(this.gm.difficulty);
}
public void tick()
{
// this.info.tick();
if (this.gm.dayCycle)
{
this.daytime += this.timeFactor;
}
for (int i = 0; i < 10 && !this.spawnQueue.isEmpty(); ++i)
{
Entity entity = (Entity)this.spawnQueue.iterator().next();
this.spawnQueue.remove(entity);
if (!this.entities.contains(entity))
{
this.spawnEntityInWorld(entity);
}
}
long time = System.currentTimeMillis();
for (Chunk chunk : this.chunkListing)
{
chunk.update(System.currentTimeMillis() - time > 5L);
}
if (System.currentTimeMillis() - time > 100L)
{
Log.JNI.info("Warnung: Render-Chunk-Tick dauerte " + (System.currentTimeMillis() - time) + " ms");
}
this.updateBlocks();
}
protected void updateBlocks()
{
this.setActivePlayerChunksAndCheckLight(this.gm.renderDistance);
this.previousActive.retainAll(this.active);
if (this.previousActive.size() == this.active.size())
{
this.previousActive.clear();
}
int i = 0;
for (ChunkPos chunkcoordintpair : this.active)
{
if (!this.previousActive.contains(chunkcoordintpair))
{
int j = chunkcoordintpair.x * 16;
int k = chunkcoordintpair.z * 16;
Chunk chunk = this.getChunk(chunkcoordintpair.x, chunkcoordintpair.z);
chunk.enqueueRelight();
this.previousActive.add(chunkcoordintpair);
++i;
if (i >= 10)
{
return;
}
}
}
}
public void doPreChunk(int x, int z, boolean load)
{
if (load)
{
if(this.chunkMapping.getValueByKey(LongHashMap.packInt(x, z)) != null)
this.doPreChunk(x, z, false);
Chunk chunk = new Chunk(this, x, z);
this.chunkMapping.add(LongHashMap.packInt(x, z), chunk);
this.chunkListing.add(chunk);
chunk.setLoaded(true);
}
else
{
Chunk chunk = this.getChunk(x, z);
if (!chunk.isEmpty())
{
chunk.onChunkUnload();
}
this.chunkMapping.remove(LongHashMap.packInt(x, z));
this.chunkListing.remove(chunk);
}
if (!load)
{
this.markBlockRangeForRenderUpdate(x * 16, 0, z * 16, x * 16 + 15, 512, z * 16 + 15);
}
}
public boolean spawnEntityInWorld(Entity entityIn)
{
boolean flag = super.spawnEntityInWorld(entityIn);
this.entityList.add(entityIn);
if (!flag)
{
this.spawnQueue.add(entityIn);
}
else if (entityIn instanceof EntityCart)
{
this.gm.getSoundManager().playSound(new MovingSoundMinecart((EntityCart)entityIn));
}
return flag;
}
public void removeEntity(Entity entityIn)
{
super.removeEntity(entityIn);
this.entityList.remove(entityIn);
}
protected void onEntityAdded(Entity entityIn)
{
if (this.spawnQueue.contains(entityIn))
{
this.spawnQueue.remove(entityIn);
}
}
protected void onEntityRemoved(Entity entityIn)
{
boolean flag = false;
if (this.entityList.contains(entityIn))
{
if (entityIn.isEntityAlive())
{
this.spawnQueue.add(entityIn);
flag = true;
}
else
{
this.entityList.remove(entityIn);
}
}
}
public void addEntityToWorld(int entityID, Entity entityToSpawn)
{
Entity entity = this.getEntityByID(entityID);
if (entity != null)
{
this.removeEntity(entity);
}
this.entityList.add(entityToSpawn);
entityToSpawn.setId(entityID);
if (!this.spawnEntityInWorld(entityToSpawn))
{
this.spawnQueue.add(entityToSpawn);
}
this.entityIds.addKey(entityID, entityToSpawn);
}
public Entity getEntityByID(int id)
{
return (Entity)(id == this.gm.thePlayer.getId() ? this.gm.thePlayer : super.getEntityByID(id));
}
public Entity removeEntityFromWorld(int entityID)
{
Entity entity = (Entity)this.entityIds.removeObject(entityID);
if (entity != null)
{
this.entityList.remove(entity);
this.removeEntity(entity);
}
return entity;
}
public boolean invalidateRegionAndSetBlock(BlockPos pos, State state)
{
return super.setState(pos, state, 3);
}
// public boolean canShowVoidParticles() {
// return this.gm.voidParticles; // && this.dimension.getType().voidPortal;
// }
public void displayTick(int posX, int posY, int posZ) {
Random rand = new Random();
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
for(int n = 0; n < 1000; n++) {
int x = posX + rand.zrange(DISPLAY_RANGE) - rand.zrange(DISPLAY_RANGE);
int y = posY + rand.zrange(DISPLAY_RANGE) - rand.zrange(DISPLAY_RANGE);
int z = posZ + rand.zrange(DISPLAY_RANGE) - rand.zrange(DISPLAY_RANGE);
pos.set(x, y, z);
State state = this.getState(pos);
state.getBlock().randomDisplayTick(this, pos, state, rand);
}
// if(this.canShowVoidParticles()) {
for(int n = 0; n < 1000; n++) {
float x = ((float)posX) + (rand.floatv() - rand.floatv() - 0.5f) * 32.0f;
float y = -64.0f + rand.floatv() * 65.0f; // * 68.0f;
float z = ((float)posZ) + (rand.floatv() - rand.floatv() - 0.5f) * 32.0f;
this.spawnParticle(ParticleType.SUSPENDED_DEPTH, (double)x, (double)y, (double)z, 0.0D, 0.0D, 0.0D);
}
// }
}
public void removeAllEntities()
{
this.entities.removeAll(this.unloaded);
for (int i = 0; i < this.unloaded.size(); ++i)
{
Entity entity = (Entity)this.unloaded.get(i);
int j = entity.chunkCoordX;
int k = entity.chunkCoordZ;
if (entity.addedToChunk && this.isLoaded(j, k, true))
{
this.getChunk(j, k).removeEntity(entity);
}
}
for (int l = 0; l < this.unloaded.size(); ++l)
{
this.onEntityRemoved((Entity)this.unloaded.get(l));
}
this.unloaded.clear();
for (int i1 = 0; i1 < this.entities.size(); ++i1)
{
Entity entity1 = (Entity)this.entities.get(i1);
if (entity1.vehicle != null)
{
if (!entity1.vehicle.dead && entity1.vehicle.passenger == entity1)
{
continue;
}
entity1.vehicle.passenger = null;
entity1.vehicle = null;
}
if (entity1.dead)
{
int j1 = entity1.chunkCoordX;
int k1 = entity1.chunkCoordZ;
if (entity1.addedToChunk && this.isLoaded(j1, k1, true))
{
this.getChunk(j1, k1).removeEntity(entity1);
}
this.entities.remove(i1--);
this.onEntityRemoved(entity1);
}
}
}
public void playSound(double x, double y, double z, SoundEvent sound, float volume, float ignored)
{
// if(this.gm.oldStepSounds && (soundName.equals("random.swim") || soundName.equals("step.ladder")))
// return;
// if(this.gm.oldStepSounds && soundName.startsWith("step."))
// soundName = "dig." + soundName.substring(5);
// if(this.gm.oldStepSounds && soundName.equals("random.swim_splash"))
// soundName = "random.splash";
// double d0 = this.gm.getRenderViewEntity().getDistanceSq(x, y, z);
PositionedSound positionedsoundrecord = new PositionedSound(sound, volume, /* pitch, */ (float)x, (float)y, (float)z);
// if (distanceDelay && d0 > 100.0D)
// {
// double d1 = Math.sqrt(d0) / 40.0D;
// this.gm.getSoundHandler().playDelayedSound(positionedsoundrecord, (int)(d1 * 20.0D));
// }
// else
// {
this.gm.getSoundManager().playSound(positionedsoundrecord);
// }
}
public void makeFireworks(double x, double y, double z, double motionX, double motionY, double motionZ, NBTTagCompound compund)
{
this.gm.effectRenderer.addEffect(new EntityFirework.StarterFX(this, x, y, z, motionX, motionY, motionZ, this.gm.effectRenderer, compund));
}
public Chunk getChunk(int x, int z)
{
Chunk chunk = this.chunkMapping.getValueByKey(LongHashMap.packInt(x, z));
return chunk == null ? this.blankChunk : chunk;
}
public String getInfo()
{
return "Chunk-Cache: M " + this.chunkMapping.getNumHashElements() + ", L " + this.chunkListing.size();
}
public void playSound(SoundEvent sound, double x, double y, double z, float volume, float pitch)
{
}
// public void spawnParticle(EnumParticleTypes particleType, boolean force, double xCoord, double yCoord, double zCoord, double xOffset,
// double yOffset, double zOffset, int... data) {
// this.spawnParticle(particleType.getParticleID(), particleType.getShouldIgnoreRange() | force, xCoord, yCoord, zCoord, xOffset, yOffset,
// zOffset, data);
// }
public void spawnParticle(ParticleType particleType, double xCoord, double yCoord, double zCoord, double xOffset, double yOffset,
double zOffset, int... data) {
this.spawnEntityFX(particleType, particleType.getShouldIgnoreRange(), xCoord, yCoord, zCoord, xOffset, yOffset, zOffset, data);
}
public EntityFX spawnEntityFX(ParticleType particle, boolean ignoreRange, double xCoord, double yCoord, double zCoord, double xOffset, double yOffset, double zOffset, int[] parameters)
{
if (this.gm != null && this.gm.getRenderViewEntity() != null && this.gm.effectRenderer != null)
{
int particleID = particle.getParticleID();
// int i = this.gm.particleSetting;
//
// if (i == 1 && this.rand.zrange(3) == 0)
// {
// i = 2;
// }
double d0 = this.gm.getRenderViewEntity().posX - xCoord;
double d1 = this.gm.getRenderViewEntity().posY - yCoord;
double d2 = this.gm.getRenderViewEntity().posZ - zCoord;
if (ignoreRange)
{
return this.gm.effectRenderer.spawnEffectParticle(particleID, xCoord, yCoord, zCoord, xOffset, yOffset, zOffset, parameters);
}
else
{
double d3 = 16.0D;
return d0 * d0 + d1 * d1 + d2 * d2 > 256.0D ? null : (/* i > 1 ? null : */ this.gm.effectRenderer.spawnEffectParticle(particleID, xCoord, yCoord, zCoord, xOffset, yOffset, zOffset, parameters));
}
}
else
{
return null;
}
}
// public void broadcastSound(int soundID, BlockPos pos, int data)
// {
// switch (soundID)
// {
//// case 1013:
// case 1018:
// if (this.gm.getRenderViewEntity() != null)
// {
// double d0 = (double)pos.getX() - this.gm.getRenderViewEntity().posX;
// double d1 = (double)pos.getY() - this.gm.getRenderViewEntity().posY;
// double d2 = (double)pos.getZ() - this.gm.getRenderViewEntity().posZ;
// double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
// double d4 = this.gm.getRenderViewEntity().posX;
// double d5 = this.gm.getRenderViewEntity().posY;
// double d6 = this.gm.getRenderViewEntity().posZ;
//
// if (d3 > 0.0D)
// {
// d4 += d0 / d3 * 2.0D;
// d5 += d1 / d3 * 2.0D;
// d6 += d2 / d3 * 2.0D;
// }
//
//// if (soundID == 1013)
//// {
//// this.playSound(d4, d5, d6, "mob.wither.spawn", 1.0F, 1.0F);
//// }
//// else
//// {
// this.playSound(d4, d5, d6, "mob.dragon.end", 5.0F, 1.0F);
//// }
// }
//
// default:
// }
// }
private void playSoundAtPos(BlockPos pos, SoundEvent sound, float volume, float pitch)
{
this.playSound((double)pos.getX() + 0.5D, (double)pos.getY() + 0.5D, (double)pos.getZ() + 0.5D, sound, volume, pitch);
}
public void playAuxSFX(EntityNPC player, int sfxType, BlockPos blockPosIn, int data)
{
switch (sfxType)
{
case 1000:
this.playSoundAtPos(blockPosIn, SoundEvent.CLICK, 1.0F, 1.0F);
break;
case 1001:
this.playSoundAtPos(blockPosIn, SoundEvent.CLICK, 1.0F, 1.2F);
break;
case 1002:
this.playSoundAtPos(blockPosIn, SoundEvent.THROW, 1.0F, 1.2F);
break;
case 1003:
this.playSoundAtPos(blockPosIn, SoundEvent.DOOR, 1.0F, this.rand.floatv() * 0.1F + 0.9F);
break;
case 1004:
this.playSoundAtPos(blockPosIn, SoundEvent.FIZZ, 0.5F, 2.6F + (this.rand.floatv() - this.rand.floatv()) * 0.8F);
break;
case 1005:
this.playSoundAtPos(blockPosIn, SoundEvent.TELEPORT, 10.0F, (this.rand.floatv() - this.rand.floatv()) * 0.2F + 1.0F);
break;
case 1006:
this.playSoundAtPos(blockPosIn, SoundEvent.DOOR, 1.0F, this.rand.floatv() * 0.1F + 0.9F);
break;
case 1007:
this.playSoundAtPos(blockPosIn, SoundEvent.SPELL, 10.0F, (this.rand.floatv() - this.rand.floatv()) * 0.2F + 0.5F);
break;
case 1008:
this.playSoundAtPos(blockPosIn, SoundEvent.FIREBALL, 10.0F, (this.rand.floatv() - this.rand.floatv()) * 0.2F + 1.0F);
break;
case 1009:
this.playSoundAtPos(blockPosIn, SoundEvent.FIREBALL, 2.0F, (this.rand.floatv() - this.rand.floatv()) * 0.2F + 1.0F);
break;
// case 1010:
// this.playSoundAtPos(blockPosIn, "dig.wood", 0.6F, (random.floatv() - random.floatv()) * 0.2F + 1.0F);
// break;
// case 1011:
// this.playSoundAtPos(blockPosIn, "random.metal", 2.0F, (random.floatv() - random.floatv()) * 0.2F + 1.0F);
// break;
// case 1012:
// this.playSoundAtPos(blockPosIn, "dig.wood", 2.0F, (random.floatv() - random.floatv()) * 0.2F + 1.0F);
// break;
case 1013:
this.playSoundAtPos(blockPosIn, SoundEvent.TELEPORT_REV, 0.5F, (this.rand.floatv() - this.rand.floatv()) * 0.2F + 1.0F);
break;
case 1014:
this.playSoundAtPos(blockPosIn, SoundEvent.METAL, 2.0F, (this.rand.floatv() - this.rand.floatv()) * 0.2F + 1.0F);
break;
case 1015:
this.playSoundAtPos(blockPosIn, SoundEvent.BAT_TAKEOFF, 0.05F, (this.rand.floatv() - this.rand.floatv()) * 0.2F + 1.0F);
break;
case 1016:
this.playSoundAtPos(blockPosIn, SoundEvent.FIREBALL, 2.0F, this.rand.floatv() * 0.1F + 1.5F);
break;
case 1017:
this.playSoundAtPos(blockPosIn, SoundEvent.EXPLODE, 20.0f, 2.0f);
break;
case 1020:
this.playSoundAtPos(blockPosIn, SoundEvent.ANVIL_BREAK, 1.0F, this.rand.floatv() * 0.1F + 0.9F);
break;
case 1021:
this.playSoundAtPos(blockPosIn, SoundEvent.ANVIL_USE, 1.0F, this.rand.floatv() * 0.1F + 0.9F);
break;
case 1022:
this.playSoundAtPos(blockPosIn, SoundEvent.ANVIL_LAND, 0.3F, this.rand.floatv() * 0.1F + 0.9F);
break;
case 1023:
// double d131 = (double)blockPosIn.getX();
// double d141 = (double)blockPosIn.getY();
// double d161 = (double)blockPosIn.getZ();
// for (int i1 = 0; i1 < 8; ++i1) {
// this.spawnEntityFX(EnumParticleTypes.ITEM_CRACK, EnumParticleTypes.ITEM_CRACK.getShouldIgnoreRange(),
// d131, d141, d161, random.gaussian() * 0.15D, random.doublev() * 0.2D, random.gaussian() * 0.15D,
// new int[] {ItemRegistry.getIdFromItem(ItemRegistry.getItemFromBlock(Blocks.glass)), 0});
// }
this.playSoundAtPos(blockPosIn, SoundEvent.GLASS, 1.0F, this.rand.floatv() * 0.1F + 0.9F);
break;
case 1024:
this.playSoundAtPos(blockPosIn, SoundEvent.CLICK, 1.0F, 1.3F);
break;
case 1025:
MutableBlockPos pos = new MutableBlockPos(blockPosIn.getX(), blockPosIn.getY(), blockPosIn.getZ());
for(int z = 0; z < 30; z++) {
this.playSoundAtPos(pos.set(blockPosIn.getX() + this.rand.range(-128, 128),
blockPosIn.getY() + this.rand.range(-4, 4), blockPosIn.getZ() + this.rand.range(-128, 128)),
SoundEvent.EXPLODE, 30.0F, this.rand.floatv() * 0.1F + 0.9F);
}
break;
case 2000:
int l = data % 3 - 1;
int i = data / 3 % 3 - 1;
double d15 = (double)blockPosIn.getX() + (double)l * 0.6D + 0.5D;
double d17 = (double)blockPosIn.getY() + 0.5D;
double d19 = (double)blockPosIn.getZ() + (double)i * 0.6D + 0.5D;
for (int k1 = 0; k1 < 10; ++k1)
{
double d20 = this.rand.doublev() * 0.2D + 0.01D;
double d21 = d15 + (double)l * 0.01D + (this.rand.doublev() - 0.5D) * (double)i * 0.5D;
double d4 = d17 + (this.rand.doublev() - 0.5D) * 0.5D;
double d6 = d19 + (double)i * 0.01D + (this.rand.doublev() - 0.5D) * (double)l * 0.5D;
double d8 = (double)l * d20 + this.rand.gaussian() * 0.01D;
double d10 = -0.03D + this.rand.gaussian() * 0.01D;
double d12 = (double)i * d20 + this.rand.gaussian() * 0.01D;
this.spawnEntityFX(ParticleType.SMOKE_NORMAL, ParticleType.SMOKE_NORMAL.getShouldIgnoreRange(), d21, d4, d6, d8, d10, d12, new int[0]);
}
return;
case 2001:
Block block = BlockRegistry.getBlockById(data & 4095);
if (block.getMaterial() != Material.air)
{
this.gm.getSoundManager().playSound(new PositionedSound(block.sound.getBreakSound(), (block.sound.getVolume() + 1.0F) / 2.0F, /* block.sound.getFrequency() * 0.8F, */ (float)blockPosIn.getX() + 0.5F, (float)blockPosIn.getY() + 0.5F, (float)blockPosIn.getZ() + 0.5F));
}
this.gm.effectRenderer.addBlockDestroyEffects(blockPosIn, block.getStateFromMeta(data >> 12 & 255));
break;
case 2002:
double d13 = (double)blockPosIn.getX();
double d14 = (double)blockPosIn.getY();
double d16 = (double)blockPosIn.getZ();
for (int i1 = 0; i1 < 8; ++i1)
{
this.spawnEntityFX(ParticleType.ITEM_CRACK, ParticleType.ITEM_CRACK.getShouldIgnoreRange(), d13, d14, d16, this.rand.gaussian() * 0.15D, this.rand.doublev() * 0.2D, this.rand.gaussian() * 0.15D, new int[] {ItemRegistry.getIdFromItem(Items.potion), data});
}
ParticleType enumparticletypes = ParticleType.WATER_SPLASH;
float f = 1.0F;
float f1 = 1.0F;
float f2 = 1.0F;
if((data & 16383) != 0) {
int j1 = Items.potion.getColorFromDamage(data);
f = (float)(j1 >> 16 & 255) / 255.0F;
f1 = (float)(j1 >> 8 & 255) / 255.0F;
f2 = (float)(j1 >> 0 & 255) / 255.0F;
enumparticletypes = ParticleType.SPELL;
if (Items.potion.isEffectInstant(data))
{
enumparticletypes = ParticleType.SPELL_INSTANT;
}
}
for (int l1 = 0; l1 < 100; ++l1)
{
double d22 = this.rand.doublev() * 4.0D;
double d23 = this.rand.doublev() * Math.PI * 2.0D;
double d24 = Math.cos(d23) * d22;
double d9 = 0.01D + this.rand.doublev() * 0.5D;
double d11 = Math.sin(d23) * d22;
EntityFX entityfx = this.spawnEntityFX(enumparticletypes, enumparticletypes.getShouldIgnoreRange(), d13 + d24 * 0.1D, d14 + 0.3D, d16 + d11 * 0.1D, d24, d9, d11, new int[0]);
if (entityfx != null)
{
if(enumparticletypes != ParticleType.WATER_SPLASH) {
float f3 = 0.75F + this.rand.floatv() * 0.25F;
entityfx.setRBGColorF(f * f3, f1 * f3, f2 * f3);
}
entityfx.multiplyVelocity((float)d22);
}
}
this.playSoundAtPos(blockPosIn, SoundEvent.GLASS, 1.0F, this.rand.floatv() * 0.1F + 0.9F);
break;
case 2004:
for (int k = 0; k < 20; ++k)
{
double d3 = (double)blockPosIn.getX() + 0.5D + ((double)this.rand.floatv() - 0.5D) * 2.0D;
double d5 = (double)blockPosIn.getY() + 0.5D + ((double)this.rand.floatv() - 0.5D) * 2.0D;
double d7 = (double)blockPosIn.getZ() + 0.5D + ((double)this.rand.floatv() - 0.5D) * 2.0D;
this.spawnParticle(ParticleType.SMOKE_NORMAL, d3, d5, d7, 0.0D, 0.0D, 0.0D);
this.spawnParticle(ParticleType.FLAME, d3, d5, d7, 0.0D, 0.0D, 0.0D);
}
return;
case 2005:
ItemDye.spawnBonemealParticles(this, blockPosIn, data);
}
}
public void markBlockForUpdate(BlockPos pos)
{
int i = pos.getX();
int j = pos.getY();
int k = pos.getZ();
this.gm.renderGlobal.markBlocksForUpdate(i - 1, j - 1, k - 1, i + 1, j + 1, k + 1);
}
public void notifyLightSet(BlockPos pos)
{
int i = pos.getX();
int j = pos.getY();
int k = pos.getZ();
this.gm.renderGlobal.markBlocksForUpdate(i - 1, j - 1, k - 1, i + 1, j + 1, k + 1);
}
public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2)
{
this.gm.renderGlobal.markBlocksForUpdate(x1 - 1, y1 - 1, z1 - 1, x2 + 1, y2 + 1, z2 + 1);
}
public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress)
{
this.gm.renderGlobal.sendBlockBreakProgress(breakerId, pos, progress);
}
public float getSunBrightness(float p_72971_1_) {
float f = this.getCelestialAngle(p_72971_1_);
float f1 = 1.0F - (ExtMath.cos(f * (float)Math.PI * 2.0F) * 2.0F + 0.2F);
f1 = ExtMath.clampf(f1, 0.0F, 1.0F);
f1 = 1.0F - f1;
f1 = (float)((double)f1 * (1.0D - (double)(this.getRainStrength() * 5.0F) / 16.0D));
f1 = (float)((double)f1 * (1.0D - (double)(this.getDarkness() * 5.0F) / 16.0D));
return f1 * 0.8F + 0.2F;
}
private static int hsvToRGB(float hue, float saturation, float value)
{
int i = (int)(hue * 6.0F) % 6;
float f = hue * 6.0F - (float)i;
float f1 = value * (1.0F - saturation);
float f2 = value * (1.0F - f * saturation);
float f3 = value * (1.0F - (1.0F - f) * saturation);
float f4;
float f5;
float f6;
switch (i)
{
case 0:
f4 = value;
f5 = f3;
f6 = f1;
break;
case 1:
f4 = f2;
f5 = value;
f6 = f1;
break;
case 2:
f4 = f1;
f5 = value;
f6 = f3;
break;
case 3:
f4 = f1;
f5 = f2;
f6 = value;
break;
case 4:
f4 = f3;
f5 = f1;
f6 = value;
break;
case 5:
f4 = value;
f5 = f1;
f6 = f2;
break;
default:
throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + hue + ", " + saturation + ", " + value);
}
int j = ExtMath.clampi((int)(f4 * 255.0F), 0, 255);
int k = ExtMath.clampi((int)(f5 * 255.0F), 0, 255);
int l = ExtMath.clampi((int)(f6 * 255.0F), 0, 255);
return j << 16 | k << 8 | l;
}
public Vec3 getSkyColor(Entity entity, float partial) {
BlockPos pos = new BlockPos(ExtMath.floord(entity.posX), ExtMath.floord(entity.posY),
ExtMath.floord(entity.posZ));
Biome biome = this.getBiomeGenForCoords(pos);
Vec3 vec;
if(biome.getSkyColor() != 0xffffffff)
vec = new Vec3(biome.getSkyColor());
else
vec = new Vec3(this.dimension.getSkyColor());
if(this.dimension.getType().days) {
float mult = ExtMath.clampf(ExtMath.cos(this.getCelestialAngle(partial) * (float)Math.PI * 2.0F) * 2.0F + 0.5F,
0.0F, 1.0F);
if(this.dimension.getSkyColor() == 0xffffffff) {
float temp = ExtMath.clampf(((biome.getFloatTemperature(pos) + 14.0f) / 40.0f + 0.15f) / 3.0F,
-1.0F, 1.0F);
Vec3 sky = new Vec3(hsvToRGB(0.62222224F - temp * 0.05F, 0.5F + temp * 0.1F, 1.0F));
vec = new Vec3(vec.xCoord * sky.xCoord * mult, vec.yCoord * sky.yCoord * mult, vec.zCoord * sky.zCoord * mult);
}
else {
vec = new Vec3(vec.xCoord * mult, vec.yCoord * mult, vec.zCoord * mult);
}
}
float r = (float)vec.xCoord;
float g = (float)vec.yCoord;
float b = (float)vec.zCoord;
float rain = this.getRainStrength();
if(rain > 0.0F) {
float mul = (r * 0.3F + g * 0.59F + b * 0.11F) * 0.6F;
float shift = 1.0F - rain * 0.75F;
r = r * shift + mul * (1.0F - shift);
g = g * shift + mul * (1.0F - shift);
b = b * shift + mul * (1.0F - shift);
}
float dark = this.getDarkness();
if(dark > 0.0F) {
float mul = (r * 0.3F + g * 0.59F + b * 0.11F) * 0.2F;
float shift = 1.0F - dark * 0.75F;
r = r * shift + mul * (1.0F - shift);
g = g * shift + mul * (1.0F - shift);
b = b * shift + mul * (1.0F - shift);
}
if(this.lastLightning > 0) {
float light = (float)this.lastLightning - partial;
if(light > 1.0F)
light = 1.0F;
// light = light * 0.45F;
r = r * (1.0F - light) + (float)this.lightColor.xCoord * light;
g = g * (1.0F - light) + (float)this.lightColor.yCoord * light;
b = b * (1.0F - light) + (float)this.lightColor.zCoord * light;
}
return new Vec3((double)r, (double)g, (double)b);
}
public Vec3 getCloudColour(Entity entity, float partialTicks) {
Vec3 color = new Vec3(this.dimension.getCloudColor());
Biome biome = this.getBiomeGenForCoords(new BlockPos(ExtMath.floord(entity.posX), ExtMath.floord(entity.posY),
ExtMath.floord(entity.posZ)));
if(biome.getCloudColor() != 0xffffffff)
color = new Vec3(biome.getCloudColor());
float r = (float)color.xCoord;
float g = (float)color.yCoord;
float b = (float)color.zCoord;
float rain = this.getRainStrength();
if(rain > 0.0F) {
float mul = (r * 0.3F + g * 0.59F + b * 0.11F) * 0.6F;
float shift = 1.0F - rain * 0.95F;
r = r * shift + mul * (1.0F - shift);
g = g * shift + mul * (1.0F - shift);
b = b * shift + mul * (1.0F - shift);
}
if(this.dimension.getType().days) {
float sun = ExtMath.clampf(ExtMath.cos(this.getCelestialAngle(partialTicks) * (float)Math.PI * 2.0F) * 2.0F + 0.5F,
0.0F, 1.0F);
r = r * (sun * 0.9F + 0.1F);
g = g * (sun * 0.9F + 0.1F);
b = b * (sun * 0.85F + 0.15F);
}
float dark = this.getDarkness();
if(dark > 0.0F) {
float mul = (r * 0.3F + g * 0.59F + b * 0.11F) * 0.2F;
float shift = 1.0F - dark * 0.95F;
r = r * shift + mul * (1.0F - shift);
g = g * shift + mul * (1.0F - shift);
b = b * shift + mul * (1.0F - shift);
}
return new Vec3((double)r, (double)g, (double)b);
}
public Vec3 getFogColor(Entity entity, float partialTicks) {
Vec3 color = new Vec3(this.dimension.getFogColor());
Biome biome = this.getBiomeGenForCoords(new BlockPos(ExtMath.floord(entity.posX), ExtMath.floord(entity.posY),
ExtMath.floord(entity.posZ)));
if(biome.getFogColor() != 0xffffffff)
color = new Vec3(biome.getFogColor());
if(!this.dimension.getType().days)
return color;
float sun = ExtMath.clampf(ExtMath.cos(this.getCelestialAngle(partialTicks) * (float)Math.PI * 2.0F) * 2.0F + 0.5F,
0.0F, 1.0F);
float r = (float)color.xCoord;
float g = (float)color.yCoord;
float b = (float)color.zCoord;
r = r * (sun * 0.94F + 0.06F);
g = g * (sun * 0.94F + 0.06F);
b = b * (sun * 0.91F + 0.09F);
return new Vec3((double)r, (double)g, (double)b);
}
public float getStarBrightness(float partialTicks) {
float f = this.getCelestialAngle(partialTicks);
float f1 = 1.0F - (ExtMath.cos(f * (float)Math.PI * 2.0F) * 2.0F + 0.25F);
f1 = ExtMath.clampf(f1, 0.0F, 1.0F);
return f1 * f1 * this.dimension.getStarBrightness();
}
public float getDeepStarBrightness(float partialTicks) {
float f = this.getCelestialAngle(partialTicks);
float f1 = 1.0F - (ExtMath.cos(f * (float)Math.PI * 2.0F) * 2.0F + 0.25F);
f1 = ExtMath.clampf(f1, 0.0F, 1.0F);
return f1 * f1 * this.dimension.getDeepStarBrightness();
}
public int getLastLightning() {
return this.lastLightning;
}
public void decrLightning() {
if(this.lastLightning > 0)
this.lastLightning -= 1;
}
public void setLastLightning(int last, int color) {
this.lastLightning = last;
this.lightColor = new Vec3(color);
}
public void ensureAreaLoaded(Entity entityIn) {
int i = ExtMath.floord(entityIn.posX / 16.0D);
int j = ExtMath.floord(entityIn.posZ / 16.0D);
int k = 2;
for(int l = i - k; l <= i + k; ++l) {
for(int i1 = j - k; i1 <= j + k; ++i1) {
this.getChunk(l, i1);
}
}
if(!this.entities.contains(entityIn)) {
this.entities.add(entityIn);
}
}
public List<Entity> getLoadedEntityList() {
return this.entities;
}
public List<TileEntity> getLoadedTileList() {
return this.tiles;
}
public String getDebugLoadedEntities() {
return "" + this.entities.size();
}
}

View file

@ -0,0 +1,39 @@
package game.world;
public class WorldPos extends BlockPos {
private final int dim;
public WorldPos(int x, int y, int z, int dim) {
super(x, y, z);
this.dim = dim;
}
public WorldPos(BlockPos pos, int dim) {
this(pos.getX(), pos.getY(), pos.getZ(), dim);
}
public int getDimension() {
return this.dim;
}
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
else if(!(obj instanceof WorldPos)) {
return false;
}
else {
WorldPos pos = (WorldPos)obj;
return this.getX() == pos.getX() && this.getY() == pos.getY() && this.getZ() == pos.getZ() && this.dim == pos.dim;
}
}
public int hashCode() {
return super.hashCode() * 31 + this.dim;
}
public String toString() {
return this.dim + ";" + this.getX() + ";" + this.getY() + ";" + this.getZ();
}
}

File diff suppressed because it is too large Load diff