Archived
0

Merge branch 'proto_1.12.2' into world

This commit is contained in:
2018-08-26 00:28:01 +03:00
19 changed files with 518 additions and 211 deletions

View File

@@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j;
import mc.core.events.CS_PlayerMoveEvent;
import mc.core.events.EventBusGetter;
import mc.core.events.SC_ChunkLoadEvent;
import mc.core.events.SC_ChunkUnloadEvent;
import mc.core.player.PlayerManager;
import mc.core.time.TimeProcessor;
import mc.core.utils.CompactedCoords;
@@ -17,6 +18,8 @@ import mc.core.world.World;
import mc.core.world.chunk.Chunk;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Iterator;
@Slf4j
public class GameLoop extends Thread {
private final TpsWatcher TPS_WATCHER = TpsWatcher.getInstance();
@@ -48,22 +51,37 @@ public class GameLoop extends Thread {
@Subscribe
public void playerMoveEventHandler(CS_PlayerMoveEvent event) {
log.trace("(GameLoop) playerMoveEventHandler()");
event.getPlayer().getLocation().setXYZ(event.getNewLocation());
Chunk chunk = event.getNewLocation().getChunk(); // Next chunk
int ncX = chunk.getX();
int ncZ = chunk.getZ();
chunk = event.getPlayer().getLocation().getChunk(); // Current chunk
Chunk chunk;
chunk = event.getOldLocation().getChunk(); // Old chunk
int ccX = chunk.getX();
int ccZ = chunk.getZ();
chunk = event.getNewLocation().getChunk(); // Next chunk
int ncX = chunk.getX();
int ncZ = chunk.getZ();
if (event.isRecalcChunk() || (ncX != ccX && ncZ != ccZ)) {
final int viewDistance = event.getPlayer().getSettings().getViewDistance();
if (event.isRecalcChunk() || (ncX != ccX || ncZ != ccZ)) {
final int viewDistance = event.getPlayer().getSettings().getViewDistance() + 1;
int cMinX = chunk.getX() - viewDistance;
int cMaxX = chunk.getX() + viewDistance;
int cMinZ = chunk.getZ() - viewDistance;
int cMaxZ = chunk.getZ() + viewDistance;
SC_ChunkUnloadEvent eventChunkUnload = new SC_ChunkUnloadEvent(event.getPlayer());
Iterator<Integer> itr = event.getPlayer().getLoadedChunks().iterator();
while(itr.hasNext()) {
int compressXZ = itr.next();
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
if (xz[0] > cMaxX || xz[0] < cMinX || xz[1] > cMaxZ || xz[1] < cMinZ) {
eventChunkUnload.getNeedUnloadChunks().add(compressXZ);
itr.remove();
}
}
if (!eventChunkUnload.getNeedUnloadChunks().isEmpty()) {
EventBusGetter.INSTANCE.post(eventChunkUnload);
}
SC_ChunkLoadEvent eventChunkLoad = new SC_ChunkLoadEvent(event.getPlayer());
for (int cZ = cMinZ; cZ <= cMaxZ; cZ++) {
for (int cX = cMinX; cX <= cMaxX; cX++) {
@@ -71,6 +89,7 @@ public class GameLoop extends Thread {
if (!event.getPlayer().getLoadedChunks().contains(compressXZ)) {
if (!event.getPlayer().getLoadedChunks().contains(compressXZ)) {
eventChunkLoad.getNeedLoadChunks().add(compressXZ);
event.getPlayer().getLoadedChunks().add(compressXZ);
}
}
}
@@ -81,6 +100,8 @@ public class GameLoop extends Thread {
}
}
event.getPlayer().getLocation().setXYZ(event.getNewLocation());
// TODO отсылать клиенту только(!) для корректировки позиции
// SC_PlayerMoveEvent nextEvent = new SC_PlayerMoveEvent(event.getPlayer());
// nextEvent.setNewLocation(event.getNewLocation());

View File

@@ -50,15 +50,15 @@ public class Location implements Cloneable {
}
public int getBlockX() {
return (int) x;
return Double.valueOf(Math.floor(x)).intValue();
}
public int getBlockY() {
return (int) y;
return Double.valueOf(Math.floor(y)).intValue();
}
public int getBlockZ() {
return (int) z;
return Double.valueOf(Math.floor(z)).intValue();
}
public Chunk getChunk() {
@@ -66,7 +66,7 @@ public class Location implements Cloneable {
if (world == null) {
return null;
} else {
return world.getChunk((int)(x / 16), (int)(z / 16));
return world.getChunk(getBlockX() >> 4, getBlockZ() >> 4);
}
}
@@ -75,7 +75,7 @@ public class Location implements Cloneable {
if (chunk == null) {
return null;
} else {
return chunk.getChunkSection((int)(y / 16));
return chunk.getChunkSection(getBlockY() >> 4);
}
}

View File

@@ -0,0 +1,16 @@
package mc.core.events;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import mc.core.player.Player;
import java.util.ArrayList;
import java.util.List;
@RequiredArgsConstructor
public class SC_ChunkUnloadEvent extends EventBase {
@Getter
private final Player player;
@Getter
private List<Integer> needUnloadChunks = new ArrayList<>();
}

View File

@@ -20,4 +20,23 @@ public class CompactedCoords {
(int)(short) (compactValue | 0xFFFF0000)
};
}
private static int floor_double(double value) {
int i = (int)value;
return value < (double)i ? i - 1 : i;
}
public static long compressXYZ(double x, double y, double z) {
return ((floor_double(x) & 0x3FFFFFF) << 38)
| ((floor_double(y) & 0xFFF) << 26)
| (floor_double(z) & 0x3FFFFFF);
}
public static double[] uncompressXYZ(long compactValue) {
return new double[]{
compactValue >> 38,
(compactValue >> 26) & 0x0FFF,
compactValue << 38 >> 38 // is normal?
};
}
}

View File

@@ -1,50 +1,26 @@
package mc.core;
import mc.core.world.World;
import mc.core.world.WorldType;
import mc.core.world.chunk.Chunk;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
public class TestEntityLocation {
@Test
public void cloneTest() {
World dummyWorld = new World() {
@Override
public WorldType getWorldType() {
return null;
}
@Override
public EntityLocation getSpawn() {
return null;
}
@Override
public void setSpawn(EntityLocation location) {
}
@Override
public Chunk getChunk(int x, int z) {
return null;
}
@Override
public void setChunk(int x, int z, Chunk chunk) {
}
};
World dummyWorld = mock(World.class);
EntityLocation firstLocation = new EntityLocation(10, 20, 30, 40, 50, dummyWorld);
Assert.assertSame("Lost world reference before cloning", dummyWorld, firstLocation.getWorld());
assertSame("Lost world reference before cloning", dummyWorld, firstLocation.getWorld());
EntityLocation locationClone = firstLocation.clone();
Assert.assertEquals("X mismatch", firstLocation.getX(), locationClone.getX(), 0);
Assert.assertEquals("Y mismatch", firstLocation.getY(), locationClone.getY(), 0);
Assert.assertEquals("Z mismatch", firstLocation.getZ(), locationClone.getZ(), 0);
Assert.assertEquals("Pitch mismatch", firstLocation.getPitch(), locationClone.getPitch(), 0);
Assert.assertEquals("Yaw mismatch", firstLocation.getYaw(), locationClone.getYaw(), 0);
Assert.assertSame("World mismatch (accidental clone of the World object?)", firstLocation.getWorld(), locationClone.getWorld());
assertEquals("X mismatch", firstLocation.getX(), locationClone.getX(), 0);
assertEquals("Y mismatch", firstLocation.getY(), locationClone.getY(), 0);
assertEquals("Z mismatch", firstLocation.getZ(), locationClone.getZ(), 0);
assertEquals("Pitch mismatch", firstLocation.getPitch(), locationClone.getPitch(), 0);
assertEquals("Yaw mismatch", firstLocation.getYaw(), locationClone.getYaw(), 0);
assertSame("World mismatch (accidental clone of the World object?)", firstLocation.getWorld(), locationClone.getWorld());
}
}

View File

@@ -0,0 +1,124 @@
package mc.core;
import mc.core.world.World;
import mc.core.world.chunk.Chunk;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
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
public void testGetBlockXZ() {
Location location;
location = new Location(0d, 0, 0d, world);
assertEquals(0, location.getBlockX());
assertEquals(0, location.getBlockZ());
location.setXYZ(0.1d, 0, 0.1d);
assertEquals(0, location.getBlockX());
assertEquals(0, location.getBlockZ());
location.setXYZ(0.5d, 0, 0.5d);
assertEquals(0, location.getBlockX());
assertEquals(0, location.getBlockZ());
location.setXYZ(0.9d, 0, 0.9d);
assertEquals(0, location.getBlockX());
assertEquals(0, location.getBlockZ());
location.setXYZ(1d, 0, 1d);
assertEquals(1, location.getBlockX());
assertEquals(1, location.getBlockZ());
location.setXYZ(-0.1d, 0, -0.1d);
assertEquals(-1, location.getBlockX());
assertEquals(-1, location.getBlockZ());
location.setXYZ(-0.5d, 0, -0.5d);
assertEquals(-1, location.getBlockX());
assertEquals(-1, location.getBlockZ());
location.setXYZ(-0.9d, 0, -0.9d);
assertEquals(-1, location.getBlockX());
assertEquals(-1, location.getBlockZ());
location.setXYZ(-1d, 0, -1d);
assertEquals(-1, location.getBlockX());
assertEquals(-1, location.getBlockZ());
location.setXYZ(-1.1d, 0, -1.1d);
assertEquals(-2, location.getBlockX());
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

@@ -1,27 +1,28 @@
package mc.core.utils;
import org.junit.Assert;
import org.junit.Test;
import java.util.Random;
import static org.junit.Assert.assertEquals;
public class TestCompactedCoords {
@Test
public void testSimple() {
public void testXZSimple() {
for (int z = -100; z <= 100; z++) {
for (int x = -100; x <= 100; x++) {
int compressXZ = CompactedCoords.compressXZ(x, z);
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
Assert.assertEquals(x, xz[0]);
Assert.assertEquals(z, xz[1]);
assertEquals(x, xz[0]);
assertEquals(z, xz[1]);
}
}
}
@Test
public void testRandom() {
public void testXZRandom() {
Random random = new Random();
int x,z;
@@ -38,8 +39,24 @@ public class TestCompactedCoords {
int compressXZ = CompactedCoords.compressXZ(x, z);
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
Assert.assertEquals(x, xz[0]);
Assert.assertEquals(z, xz[1]);
assertEquals(x, xz[0]);
assertEquals(z, xz[1]);
}
}
// @Test
public void testXYZSimple() {
for (int z = -100; z <= 100; z++) {
for (int x = -100; x <= 100; x++) {
for (int y = -100; y <= 100; y++) {
long compressXYZ = CompactedCoords.compressXYZ(x, y, z);
double[] xyz = CompactedCoords.uncompressXYZ(compressXYZ);
assertEquals(x, xyz[0], 0.001d);
assertEquals(y, xyz[1], 0.001d);
assertEquals(z, xyz[2], 0.001d);
}
}
}
}
}