Archived
0

исключена ссылка на World в Location и ChunkSection

This commit is contained in:
2018-08-26 01:13:21 +03:00
parent 2147c18f81
commit 464a2e7be6
12 changed files with 133 additions and 154 deletions

View File

@@ -6,16 +6,24 @@ package mc.core;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import mc.core.exception.ResourceUnloadedException;
import mc.core.world.World; import mc.core.world.World;
import mc.core.world.chunk.Chunk;
import mc.core.world.chunk.ChunkSection;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
public class EntityLocation extends Location implements Cloneable { public class EntityLocation extends Location implements Cloneable {
@Getter @Getter
@Setter @Setter
private float yaw, pitch; private float yaw, pitch;
private Reference<World> refWorld;
public EntityLocation(double x, double y, double z, float yaw, float pitch, World world) { public EntityLocation(double x, double y, double z, float yaw, float pitch, World world) {
super(x, y, z, world); super(x, y, z);
setYawPitch(yaw, pitch); setYawPitch(yaw, pitch);
setWorld(world);
} }
public void setYawPitch(float yaw, float pitch) { public void setYawPitch(float yaw, float pitch) {
@@ -27,6 +35,38 @@ public class EntityLocation extends Location implements Cloneable {
setYawPitch(entityLocation.yaw, entityLocation.pitch); setYawPitch(entityLocation.yaw, entityLocation.pitch);
} }
public World getWorld() {
if (refWorld == null) {
return null;
} else if (refWorld.get() == null) {
throw new ResourceUnloadedException("World unloaded");
} else {
return refWorld.get();
}
}
public void setWorld (World world) {
this.refWorld = new WeakReference<>(world);
}
public Chunk getChunk() {
World world = getWorld();
if (world == null) {
return null;
} else {
return world.getChunk(getBlockX() >> 4, getBlockZ() >> 4);
}
}
public ChunkSection getChunkSection() {
Chunk chunk = getChunk();
if (chunk == null) {
return null;
} else {
return chunk.getChunkSection(getBlockY() >> 4);
}
}
@Override @Override
public EntityLocation clone() { public EntityLocation clone() {
return (EntityLocation) super.clone(); return (EntityLocation) super.clone();

View File

@@ -6,23 +6,14 @@ package mc.core;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import mc.core.exception.ResourceUnloadedException;
import mc.core.world.World;
import mc.core.world.chunk.Chunk;
import mc.core.world.chunk.ChunkSection;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
public class Location implements Cloneable { public class Location implements Cloneable {
@Getter @Getter
@Setter @Setter
private double x, y, z; private double x, y, z;
private Reference<World> refWorld;
public Location (double x, double y, double z, World world) { public Location (double x, double y, double z) {
setXYZ(x, y, z); setXYZ(x, y, z);
setWorld(world);
} }
public void setXYZ(double x, double y, double z) { public void setXYZ(double x, double y, double z) {
@@ -35,20 +26,6 @@ public class Location implements Cloneable {
setXYZ(location.x, location.y, location.z); setXYZ(location.x, location.y, location.z);
} }
public World getWorld() {
if (refWorld == null) {
return null;
} else if (refWorld.get() == null) {
throw new ResourceUnloadedException("World unloaded");
} else {
return refWorld.get();
}
}
public void setWorld (World world) {
this.refWorld = new WeakReference<>(world);
}
public int getBlockX() { public int getBlockX() {
return Double.valueOf(Math.floor(x)).intValue(); return Double.valueOf(Math.floor(x)).intValue();
} }
@@ -61,24 +38,6 @@ public class Location implements Cloneable {
return Double.valueOf(Math.floor(z)).intValue(); return Double.valueOf(Math.floor(z)).intValue();
} }
public Chunk getChunk() {
World world = getWorld();
if (world == null) {
return null;
} else {
return world.getChunk(getBlockX() >> 4, getBlockZ() >> 4);
}
}
public ChunkSection getChunkSection() {
Chunk chunk = getChunk();
if (chunk == null) {
return null;
} else {
return chunk.getChunkSection(getBlockY() >> 4);
}
}
@Override @Override
public Location clone() { public Location clone() {
try { try {

View File

@@ -5,15 +5,15 @@ import mc.core.world.World;
public class BlockFactory { public class BlockFactory {
public Block create(BlockType blockType, int x, int y, int z, World world) { public Block create(BlockType blockType, int x, int y, int z) {
return new EmbeddedBlock(blockType, x, y, z, world); return new EmbeddedBlock(blockType, x, y, z);
} }
/** For first-time generation */ /** For first-time generation */
private class EmbeddedBlock extends AbstractBlock { private class EmbeddedBlock extends AbstractBlock {
EmbeddedBlock(BlockType type, int x, int y, int z, World world) { EmbeddedBlock(BlockType type, int x, int y, int z) {
super(type); super(type);
setLocation(new Location(x,y,z, world)); setLocation(new Location(x, y, z));
} }
} }
} }

View File

@@ -24,6 +24,4 @@ public interface ChunkSection {
void setAddition(int x, int y, int z, int value); void setAddition(int x, int y, int z, int value);
Biome getBiome(int localX, int localZ); Biome getBiome(int localX, int localZ);
World getWorld();
} }

View File

@@ -1,19 +1,37 @@
package mc.core; package mc.core;
import mc.core.world.World; import mc.core.world.World;
import mc.core.world.chunk.Chunk;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class TestEntityLocation { public class TestEntityLocation {
private World world;
@Before
public void prepareWorld() {
this.world = mock(World.class);
when(world.getChunk(anyInt(), anyInt())).thenAnswer(invocation -> {
Object[] args = invocation.getArguments();
Chunk chunk = mock(Chunk.class);
when(chunk.getX()).thenReturn((int) args[0]);
when(chunk.getZ()).thenReturn((int) args[1]);
return chunk;
});
}
@Test @Test
public void cloneTest() { public void cloneTest() {
World dummyWorld = mock(World.class); EntityLocation firstLocation = new EntityLocation(10, 20, 30, 40, 50, world);
assertSame("Lost world reference before cloning", world, firstLocation.getWorld());
EntityLocation firstLocation = new EntityLocation(10, 20, 30, 40, 50, dummyWorld);
assertSame("Lost world reference before cloning", dummyWorld, firstLocation.getWorld());
EntityLocation locationClone = firstLocation.clone(); EntityLocation locationClone = firstLocation.clone();
assertEquals("X mismatch", firstLocation.getX(), locationClone.getX(), 0); assertEquals("X mismatch", firstLocation.getX(), locationClone.getX(), 0);
@@ -23,4 +41,56 @@ public class TestEntityLocation {
assertEquals("Yaw mismatch", firstLocation.getYaw(), locationClone.getYaw(), 0); assertEquals("Yaw mismatch", firstLocation.getYaw(), locationClone.getYaw(), 0);
assertSame("World mismatch (accidental clone of the World object?)", firstLocation.getWorld(), locationClone.getWorld()); assertSame("World mismatch (accidental clone of the World object?)", firstLocation.getWorld(), locationClone.getWorld());
} }
@Test
public void testGetChunk() {
EntityLocation location;
Chunk chunk;
location = new EntityLocation(0d, 0, 0d, 0f, 0f, world);
chunk = location.getChunk();
assertEquals(0, chunk.getX());
assertEquals(0, chunk.getZ());
location.setXYZ(1d, 0, 1d);
chunk = location.getChunk();
assertEquals(0, chunk.getX());
assertEquals(0, chunk.getZ());
location.setXYZ(15d, 0, 15d);
chunk = location.getChunk();
assertEquals(0, chunk.getX());
assertEquals(0, chunk.getZ());
location.setXYZ(16d, 0, 16d);
chunk = location.getChunk();
assertEquals(1, chunk.getX());
assertEquals(1, chunk.getZ());
location.setXYZ(-0.1d, 0, -0.1d);
chunk = location.getChunk();
assertEquals(-1, chunk.getX());
assertEquals(-1, chunk.getZ());
location.setXYZ(-1d, 0, -1d);
chunk = location.getChunk();
assertEquals(-1, chunk.getX());
assertEquals(-1, chunk.getZ());
location.setXYZ(-15d, 0, -15d);
chunk = location.getChunk();
assertEquals(-1, chunk.getX());
assertEquals(-1, chunk.getZ());
//TODO на практике, таких точных значений не встретиться, но тем не менее данный тест не проходит
//location.setXYZ(-16.0d, 0, -16.0d);
//chunk = location.getChunk();
//assertEquals(-2, chunk.getX());
//assertEquals(-2, chunk.getZ());
location.setXYZ(-16.001d, 0, -16.001d);
chunk = location.getChunk();
assertEquals(-2, chunk.getX());
assertEquals(-2, chunk.getZ());
}
} }

View File

@@ -1,35 +1,15 @@
package mc.core; package mc.core;
import mc.core.world.World;
import mc.core.world.chunk.Chunk;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
public class TestLocation { public class TestLocation {
private World world;
@Before
public void prepareWorld() {
this.world = mock(World.class);
when(world.getChunk(anyInt(), anyInt())).thenAnswer(invocation -> {
Object[] args = invocation.getArguments();
Chunk chunk = mock(Chunk.class);
when(chunk.getX()).thenReturn((int) args[0]);
when(chunk.getZ()).thenReturn((int) args[1]);
return chunk;
});
}
@Test @Test
public void testGetBlockXZ() { public void testGetBlockXZ() {
Location location; Location location;
location = new Location(0d, 0, 0d, world); location = new Location(0d, 0, 0d);
assertEquals(0, location.getBlockX()); assertEquals(0, location.getBlockX());
assertEquals(0, location.getBlockZ()); assertEquals(0, location.getBlockZ());
@@ -69,56 +49,4 @@ public class TestLocation {
assertEquals(-2, location.getBlockX()); assertEquals(-2, location.getBlockX());
assertEquals(-2, location.getBlockZ()); assertEquals(-2, location.getBlockZ());
} }
@Test
public void testGetChunk() {
Location location;
Chunk chunk;
location = new Location(0d, 0, 0d, world);
chunk = location.getChunk();
assertEquals(0, chunk.getX());
assertEquals(0, chunk.getZ());
location.setXYZ(1d, 0, 1d);
chunk = location.getChunk();
assertEquals(0, chunk.getX());
assertEquals(0, chunk.getZ());
location.setXYZ(15d, 0, 15d);
chunk = location.getChunk();
assertEquals(0, chunk.getX());
assertEquals(0, chunk.getZ());
location.setXYZ(16d, 0, 16d);
chunk = location.getChunk();
assertEquals(1, chunk.getX());
assertEquals(1, chunk.getZ());
location.setXYZ(-0.1d, 0, -0.1d);
chunk = location.getChunk();
assertEquals(-1, chunk.getX());
assertEquals(-1, chunk.getZ());
location.setXYZ(-1d, 0, -1d);
chunk = location.getChunk();
assertEquals(-1, chunk.getX());
assertEquals(-1, chunk.getZ());
location.setXYZ(-15d, 0, -15d);
chunk = location.getChunk();
assertEquals(-1, chunk.getX());
assertEquals(-1, chunk.getZ());
//TODO на практике, таких точных значений не встретиться, но тем не менее данный тест не проходит
//location.setXYZ(-16.0d, 0, -16.0d);
//chunk = location.getChunk();
//assertEquals(-2, chunk.getX());
//assertEquals(-2, chunk.getZ());
location.setXYZ(-16.001d, 0, -16.001d);
chunk = location.getChunk();
assertEquals(-2, chunk.getX());
assertEquals(-2, chunk.getZ());
}
} }

View File

@@ -21,7 +21,7 @@ public class PlayerBlockPlacementPacket implements CSPacket {
public void readSelf(NetInputStream netStream) { public void readSelf(NetInputStream netStream) {
long compactedCoords = netStream.readLong(); long compactedCoords = netStream.readLong();
double[] xyz = CompactedCoords.uncompressXYZ(compactedCoords); double[] xyz = CompactedCoords.uncompressXYZ(compactedCoords);
location = new Location(xyz[0], xyz[1], xyz[2], null); location = new Location(xyz[0], xyz[1], xyz[2]);
face = Direction.getById(netStream.readVarInt()); face = Direction.getById(netStream.readVarInt());
hand = (netStream.readVarInt() == 1); hand = (netStream.readVarInt() == 1);
cursorX = netStream.readFloat(); cursorX = netStream.readFloat();

View File

@@ -50,7 +50,7 @@ public class PlayerDiggingPacket implements CSPacket {
status = Status.getById(netStream.readVarInt()); status = Status.getById(netStream.readVarInt());
long compactCoord = netStream.readLong(); long compactCoord = netStream.readLong();
double[] xyz = CompactedCoords.uncompressXYZ(compactCoord); double[] xyz = CompactedCoords.uncompressXYZ(compactCoord);
location = new Location(xyz[0], xyz[1], xyz[2], null); location = new Location(xyz[0], xyz[1], xyz[2]);
face = Direction.getById(netStream.readByte()); face = Direction.getById(netStream.readByte());
} }
} }

View File

@@ -27,7 +27,7 @@ public class TabCompletePacket implements CSPacket {
double y = (compactValue >> 26) & 0xFFF; double y = (compactValue >> 26) & 0xFFF;
double z = compactValue << 38 >> 38; // is normal? double z = compactValue << 38 >> 38; // is normal?
this.location = new Location(x, y, z, null); this.location = new Location(x, y, z);
} }
} }
} }

View File

@@ -50,10 +50,10 @@ public class TestChunkdataPacket {
BlockFactory blockFactory = new BlockFactory(); BlockFactory blockFactory = new BlockFactory();
if (y == 0) return blockFactory.create(BlockType.BEDROCK, x, y, z, null); if (y == 0) return blockFactory.create(BlockType.BEDROCK, x, y, z);
else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, x, y, z, null); else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, x, y, z);
else if (y == 3) return blockFactory.create(BlockType.GRASS, x, y, z, null); else if (y == 3) return blockFactory.create(BlockType.GRASS, x, y, z);
else return blockFactory.create(BlockType.AIR, x, y, z, null); else return blockFactory.create(BlockType.AIR, x, y, z);
}); });
world = mock(World.class); world = mock(World.class);

View File

@@ -4,26 +4,20 @@
*/ */
package mc.world.simple; package mc.world.simple;
import mc.core.exception.ResourceUnloadedException;
import mc.core.world.Biome; import mc.core.world.Biome;
import mc.core.world.World;
import mc.core.world.block.Block; import mc.core.world.block.Block;
import mc.core.world.block.BlockFactory; import mc.core.world.block.BlockFactory;
import mc.core.world.block.BlockType; import mc.core.world.block.BlockType;
import mc.core.world.chunk.ChunkSection; import mc.core.world.chunk.ChunkSection;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.List; import java.util.List;
public class SimpleChunkSection implements ChunkSection { public class SimpleChunkSection implements ChunkSection {
private final BlockFactory blockFactory = new BlockFactory(); private final BlockFactory blockFactory = new BlockFactory();
private final List<BlockType> layersBlock; private final List<BlockType> layersBlock;
private Reference<World> refWorld;
public SimpleChunkSection(List<BlockType> layersBlock, World world) { public SimpleChunkSection(List<BlockType> layersBlock) {
this.layersBlock = layersBlock; this.layersBlock = layersBlock;
this.refWorld = new WeakReference<>(world);
} }
@Override @Override
@@ -72,22 +66,12 @@ public class SimpleChunkSection implements ChunkSection {
@Override @Override
public Block getBlock(int x, int y, int z) { public Block getBlock(int x, int y, int z) {
if (y >= layersBlock.size()) { if (y >= layersBlock.size()) {
return blockFactory.create(BlockType.AIR, x, y, z, getWorld()); return blockFactory.create(BlockType.AIR, x, y, z);
} }
BlockType blockType = layersBlock.get(y); BlockType blockType = layersBlock.get(y);
if (blockType == null) return blockFactory.create(BlockType.AIR, x, y, z, getWorld()); if (blockType == null) return blockFactory.create(BlockType.AIR, x, y, z);
return blockFactory.create(blockType, x, y, z, getWorld()); return blockFactory.create(blockType, x, y, z);
}
@Override
public World getWorld() {
World world = refWorld.get();
if (world == null) {
throw new ResourceUnloadedException("World unloaded");
}
return world;
} }
} }

View File

@@ -68,6 +68,6 @@ public class SimpleWorld implements World {
} }
} }
this.chunkSection = new SimpleChunkSection(layoutsBlock, this); this.chunkSection = new SimpleChunkSection(layoutsBlock);
} }
} }