initial commit
This commit is contained in:
parent
3c9ee26b06
commit
22186c33b9
1458 changed files with 282792 additions and 0 deletions
122
java/src/game/world/BlockArray.java
Executable file
122
java/src/game/world/BlockArray.java
Executable 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
360
java/src/game/world/BlockPos.java
Executable 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;
|
||||
}
|
||||
}
|
||||
}
|
414
java/src/game/world/BoundingBox.java
Executable file
414
java/src/game/world/BoundingBox.java
Executable 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
1199
java/src/game/world/Chunk.java
Executable file
File diff suppressed because it is too large
Load diff
25
java/src/game/world/ChunkCache.java
Executable file
25
java/src/game/world/ChunkCache.java
Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
java/src/game/world/ChunkPos.java
Executable file
34
java/src/game/world/ChunkPos.java
Executable 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 + "]";
|
||||
}
|
||||
}
|
151
java/src/game/world/ClassInheritanceMultiMap.java
Executable file
151
java/src/game/world/ClassInheritanceMultiMap.java
Executable 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
1346
java/src/game/world/Converter.java
Executable file
File diff suppressed because it is too large
Load diff
98
java/src/game/world/EmptyChunk.java
Executable file
98
java/src/game/world/EmptyChunk.java
Executable 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;
|
||||
}
|
||||
}
|
353
java/src/game/world/Explosion.java
Executable file
353
java/src/game/world/Explosion.java
Executable 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
493
java/src/game/world/Facing.java
Executable 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());
|
||||
}
|
||||
}
|
||||
}
|
35
java/src/game/world/HitPosition.java
Executable file
35
java/src/game/world/HitPosition.java
Executable 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;
|
||||
}
|
||||
}
|
6
java/src/game/world/IBlockAccess.java
Executable file
6
java/src/game/world/IBlockAccess.java
Executable file
|
@ -0,0 +1,6 @@
|
|||
package game.world;
|
||||
|
||||
public interface IBlockAccess
|
||||
{
|
||||
State getState(BlockPos pos);
|
||||
}
|
11
java/src/game/world/IWorldAccess.java
Executable file
11
java/src/game/world/IWorldAccess.java
Executable 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);
|
||||
}
|
282
java/src/game/world/IntHashMap.java
Executable file
282
java/src/game/world/IntHashMap.java
Executable 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();
|
||||
}
|
||||
}
|
||||
}
|
11
java/src/game/world/LightType.java
Executable file
11
java/src/game/world/LightType.java
Executable 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;
|
||||
}
|
||||
}
|
285
java/src/game/world/LongHashMap.java
Executable file
285
java/src/game/world/LongHashMap.java
Executable 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();
|
||||
}
|
||||
}
|
||||
}
|
73
java/src/game/world/NextTickListEntry.java
Executable file
73
java/src/game/world/NextTickListEntry.java
Executable 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;
|
||||
}
|
||||
}
|
31
java/src/game/world/NibbleArray.java
Executable file
31
java/src/game/world/NibbleArray.java
Executable 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;
|
||||
}
|
||||
}
|
5
java/src/game/world/PortalType.java
Executable file
5
java/src/game/world/PortalType.java
Executable 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;
|
||||
}
|
19
java/src/game/world/Position.java
Executable file
19
java/src/game/world/Position.java
Executable 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
760
java/src/game/world/Region.java
Executable 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
209
java/src/game/world/Spawner.java
Executable 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
138
java/src/game/world/State.java
Executable 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
219
java/src/game/world/Vec3.java
Executable 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
124
java/src/game/world/Vec3i.java
Executable 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
141
java/src/game/world/Weather.java
Executable 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
2139
java/src/game/world/World.java
Executable file
File diff suppressed because it is too large
Load diff
923
java/src/game/world/WorldClient.java
Executable file
923
java/src/game/world/WorldClient.java
Executable 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();
|
||||
}
|
||||
}
|
39
java/src/game/world/WorldPos.java
Executable file
39
java/src/game/world/WorldPos.java
Executable 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();
|
||||
}
|
||||
}
|
2821
java/src/game/world/WorldServer.java
Executable file
2821
java/src/game/world/WorldServer.java
Executable file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue