Merge branch 'proto_1.12.2' into world
This commit is contained in:
@@ -36,8 +36,12 @@ subprojects {
|
|||||||
/* Components */
|
/* Components */
|
||||||
compile (group: 'org.projectlombok', name: 'lombok', version: '1.16.16')
|
compile (group: 'org.projectlombok', name: 'lombok', version: '1.16.16')
|
||||||
|
|
||||||
/* Test */
|
/* JUnit */
|
||||||
testCompile (group: 'junit', name: 'junit', version: '4.12')
|
testCompile (group: 'junit', name: 'junit', version: '4.12')
|
||||||
|
/* Simple log */
|
||||||
|
testCompile (group: 'org.slf4j', name: 'slf4j-simple', version: slf4j_version)
|
||||||
|
/* Mockito */
|
||||||
|
testCompile (group: 'org.mockito', name: 'mockito-core', version: '1.9.5')
|
||||||
}
|
}
|
||||||
|
|
||||||
task copyDep(type: Copy) {
|
task copyDep(type: Copy) {
|
||||||
@@ -63,7 +67,7 @@ task runApp(type: JavaExec) {
|
|||||||
|
|
||||||
/* Uncomment, if you used VM args */
|
/* Uncomment, if you used VM args */
|
||||||
//jvmArgs = [
|
//jvmArgs = [
|
||||||
// "-DspringConfig=spring-flat.xml",
|
// "-DspringConfig=spring.xml",
|
||||||
// "-Dlog4j.configurationFile=log4j2.xml"
|
// "-Dlog4j.configurationFile=log4j2.xml"
|
||||||
//]
|
//]
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import mc.core.events.CS_PlayerMoveEvent;
|
import mc.core.events.CS_PlayerMoveEvent;
|
||||||
import mc.core.events.EventBusGetter;
|
import mc.core.events.EventBusGetter;
|
||||||
import mc.core.events.SC_ChunkLoadEvent;
|
import mc.core.events.SC_ChunkLoadEvent;
|
||||||
|
import mc.core.events.SC_ChunkUnloadEvent;
|
||||||
import mc.core.player.PlayerManager;
|
import mc.core.player.PlayerManager;
|
||||||
import mc.core.time.TimeProcessor;
|
import mc.core.time.TimeProcessor;
|
||||||
import mc.core.utils.CompactedCoords;
|
import mc.core.utils.CompactedCoords;
|
||||||
@@ -17,6 +18,8 @@ import mc.core.world.World;
|
|||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.chunk.Chunk;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class GameLoop extends Thread {
|
public class GameLoop extends Thread {
|
||||||
private final TpsWatcher TPS_WATCHER = TpsWatcher.getInstance();
|
private final TpsWatcher TPS_WATCHER = TpsWatcher.getInstance();
|
||||||
@@ -48,22 +51,37 @@ public class GameLoop extends Thread {
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void playerMoveEventHandler(CS_PlayerMoveEvent event) {
|
public void playerMoveEventHandler(CS_PlayerMoveEvent event) {
|
||||||
log.trace("(GameLoop) playerMoveEventHandler()");
|
log.trace("(GameLoop) playerMoveEventHandler()");
|
||||||
event.getPlayer().getLocation().setXYZ(event.getNewLocation());
|
|
||||||
|
|
||||||
Chunk chunk = event.getNewLocation().getChunk(); // Next chunk
|
Chunk chunk;
|
||||||
int ncX = chunk.getX();
|
chunk = event.getOldLocation().getChunk(); // Old chunk
|
||||||
int ncZ = chunk.getZ();
|
|
||||||
chunk = event.getPlayer().getLocation().getChunk(); // Current chunk
|
|
||||||
int ccX = chunk.getX();
|
int ccX = chunk.getX();
|
||||||
int ccZ = chunk.getZ();
|
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)) {
|
if (event.isRecalcChunk() || (ncX != ccX || ncZ != ccZ)) {
|
||||||
final int viewDistance = event.getPlayer().getSettings().getViewDistance();
|
final int viewDistance = event.getPlayer().getSettings().getViewDistance() + 1;
|
||||||
int cMinX = chunk.getX() - viewDistance;
|
int cMinX = chunk.getX() - viewDistance;
|
||||||
int cMaxX = chunk.getX() + viewDistance;
|
int cMaxX = chunk.getX() + viewDistance;
|
||||||
int cMinZ = chunk.getZ() - viewDistance;
|
int cMinZ = chunk.getZ() - viewDistance;
|
||||||
int cMaxZ = 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());
|
SC_ChunkLoadEvent eventChunkLoad = new SC_ChunkLoadEvent(event.getPlayer());
|
||||||
for (int cZ = cMinZ; cZ <= cMaxZ; cZ++) {
|
for (int cZ = cMinZ; cZ <= cMaxZ; cZ++) {
|
||||||
for (int cX = cMinX; cX <= cMaxX; cX++) {
|
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)) {
|
||||||
if (!event.getPlayer().getLoadedChunks().contains(compressXZ)) {
|
if (!event.getPlayer().getLoadedChunks().contains(compressXZ)) {
|
||||||
eventChunkLoad.getNeedLoadChunks().add(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 отсылать клиенту только(!) для корректировки позиции
|
// TODO отсылать клиенту только(!) для корректировки позиции
|
||||||
// SC_PlayerMoveEvent nextEvent = new SC_PlayerMoveEvent(event.getPlayer());
|
// SC_PlayerMoveEvent nextEvent = new SC_PlayerMoveEvent(event.getPlayer());
|
||||||
// nextEvent.setNewLocation(event.getNewLocation());
|
// nextEvent.setNewLocation(event.getNewLocation());
|
||||||
|
|||||||
@@ -50,15 +50,15 @@ public class Location implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getBlockX() {
|
public int getBlockX() {
|
||||||
return (int) x;
|
return Double.valueOf(Math.floor(x)).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBlockY() {
|
public int getBlockY() {
|
||||||
return (int) y;
|
return Double.valueOf(Math.floor(y)).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBlockZ() {
|
public int getBlockZ() {
|
||||||
return (int) z;
|
return Double.valueOf(Math.floor(z)).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Chunk getChunk() {
|
public Chunk getChunk() {
|
||||||
@@ -66,7 +66,7 @@ public class Location implements Cloneable {
|
|||||||
if (world == null) {
|
if (world == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} 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) {
|
if (chunk == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return chunk.getChunkSection((int)(y / 16));
|
return chunk.getChunkSection(getBlockY() >> 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
core/src/main/java/mc/core/events/SC_ChunkUnloadEvent.java
Normal file
16
core/src/main/java/mc/core/events/SC_ChunkUnloadEvent.java
Normal 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<>();
|
||||||
|
}
|
||||||
@@ -20,4 +20,23 @@ public class CompactedCoords {
|
|||||||
(int)(short) (compactValue | 0xFFFF0000)
|
(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?
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +1,26 @@
|
|||||||
package mc.core;
|
package mc.core;
|
||||||
|
|
||||||
import mc.core.world.World;
|
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 org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
public class TestEntityLocation {
|
public class TestEntityLocation {
|
||||||
@Test
|
@Test
|
||||||
public void cloneTest() {
|
public void cloneTest() {
|
||||||
World dummyWorld = new World() {
|
World dummyWorld = mock(World.class);
|
||||||
@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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
EntityLocation firstLocation = new EntityLocation(10, 20, 30, 40, 50, dummyWorld);
|
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();
|
EntityLocation locationClone = firstLocation.clone();
|
||||||
|
|
||||||
Assert.assertEquals("X mismatch", firstLocation.getX(), locationClone.getX(), 0);
|
assertEquals("X mismatch", firstLocation.getX(), locationClone.getX(), 0);
|
||||||
Assert.assertEquals("Y mismatch", firstLocation.getY(), locationClone.getY(), 0);
|
assertEquals("Y mismatch", firstLocation.getY(), locationClone.getY(), 0);
|
||||||
Assert.assertEquals("Z mismatch", firstLocation.getZ(), locationClone.getZ(), 0);
|
assertEquals("Z mismatch", firstLocation.getZ(), locationClone.getZ(), 0);
|
||||||
Assert.assertEquals("Pitch mismatch", firstLocation.getPitch(), locationClone.getPitch(), 0);
|
assertEquals("Pitch mismatch", firstLocation.getPitch(), locationClone.getPitch(), 0);
|
||||||
Assert.assertEquals("Yaw mismatch", firstLocation.getYaw(), locationClone.getYaw(), 0);
|
assertEquals("Yaw mismatch", firstLocation.getYaw(), locationClone.getYaw(), 0);
|
||||||
Assert.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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
124
core/src/test/java/mc/core/TestLocation.java
Normal file
124
core/src/test/java/mc/core/TestLocation.java
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +1,28 @@
|
|||||||
package mc.core.utils;
|
package mc.core.utils;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
public class TestCompactedCoords {
|
public class TestCompactedCoords {
|
||||||
@Test
|
@Test
|
||||||
public void testSimple() {
|
public void testXZSimple() {
|
||||||
for (int z = -100; z <= 100; z++) {
|
for (int z = -100; z <= 100; z++) {
|
||||||
for (int x = -100; x <= 100; x++) {
|
for (int x = -100; x <= 100; x++) {
|
||||||
int compressXZ = CompactedCoords.compressXZ(x, z);
|
int compressXZ = CompactedCoords.compressXZ(x, z);
|
||||||
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
||||||
|
|
||||||
Assert.assertEquals(x, xz[0]);
|
assertEquals(x, xz[0]);
|
||||||
Assert.assertEquals(z, xz[1]);
|
assertEquals(z, xz[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRandom() {
|
public void testXZRandom() {
|
||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
int x,z;
|
int x,z;
|
||||||
|
|
||||||
@@ -38,8 +39,24 @@ public class TestCompactedCoords {
|
|||||||
int compressXZ = CompactedCoords.compressXZ(x, z);
|
int compressXZ = CompactedCoords.compressXZ(x, z);
|
||||||
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
||||||
|
|
||||||
Assert.assertEquals(x, xz[0]);
|
assertEquals(x, xz[0]);
|
||||||
Assert.assertEquals(z, xz[1]);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package mc.core.network.proto_1_12_2;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum Direction {
|
||||||
|
BOTTOM(0), // -Y
|
||||||
|
TOP(1), // +Y
|
||||||
|
NORTH(2), // -Z
|
||||||
|
SOUTH(3), // +Z
|
||||||
|
WEST(4), // -X
|
||||||
|
EAST(5); // +X
|
||||||
|
|
||||||
|
public static Direction getById(final int id) {
|
||||||
|
return Arrays.stream(Direction.values())
|
||||||
|
.filter(direction -> direction.id == id)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int id;
|
||||||
|
}
|
||||||
@@ -80,13 +80,18 @@ public enum State {
|
|||||||
.put(0x0D, PlayerPositionPacket.class)
|
.put(0x0D, PlayerPositionPacket.class)
|
||||||
.put(0x0E, PlayerPositionAndLookPacket.class)
|
.put(0x0E, PlayerPositionAndLookPacket.class)
|
||||||
.put(0x0F, PlayerLookPacket.class)
|
.put(0x0F, PlayerLookPacket.class)
|
||||||
|
.put(0x13, PlayerAbilitiesPacket.class)
|
||||||
|
.put(0x14, PlayerDiggingPacket.class)
|
||||||
|
.put(0x15, EntityActionPacket.class)
|
||||||
.put(0x1A, HeldItemChangePacket.class)
|
.put(0x1A, HeldItemChangePacket.class)
|
||||||
.put(0x1D, AnimationPacket.class)
|
.put(0x1D, AnimationPacket.class)
|
||||||
|
.put(0x1F, PlayerBlockPlacementPacket.class)
|
||||||
.build(),
|
.build(),
|
||||||
ImmutableMap.<Class<? extends SCPacket>, Integer>builder()
|
ImmutableMap.<Class<? extends SCPacket>, Integer>builder()
|
||||||
.put(BossBarPacket.class, 0x0C)
|
.put(BossBarPacket.class, 0x0C)
|
||||||
.put(ChatMessageServerPacket.class, 0x0F)
|
.put(ChatMessageServerPacket.class, 0x0F)
|
||||||
.put(PluginMessagePacket.class, 0x18)
|
.put(PluginMessagePacket.class, 0x18)
|
||||||
|
.put(UnloadChunkPacket.class, 0x1D)
|
||||||
.put(ChangeGameState.class, 0x1E)
|
.put(ChangeGameState.class, 0x1E)
|
||||||
.put(KeepAlivePacket.class, 0x1F)
|
.put(KeepAlivePacket.class, 0x1F)
|
||||||
.put(ChunkDataPacket.class, 0x20)
|
.put(ChunkDataPacket.class, 0x20)
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import mc.core.network.CSPacket;
|
||||||
|
import mc.core.network.NetInputStream;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class EntityActionPacket implements CSPacket {
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum Action {
|
||||||
|
START_SNEAKING(0),
|
||||||
|
STOP_SNEAKING(1),
|
||||||
|
LEAVE_BED(2), // Leave bed is only sent when the “Leave Bed” button is clicked on the sleep GUI, not when waking up due today time.
|
||||||
|
START_SPRINTING(3),
|
||||||
|
STOP_SPRINTING(4),
|
||||||
|
START_JUMP_WITH_HORSE(5),
|
||||||
|
STOP_JUMP_WITH_HORSE(6),
|
||||||
|
OPEN_HORSE_INVENTORY(7), // Open horse inventory is only sent when pressing the inventory key (default: E) while on a horse — all other methods of opening a horse's inventory (involving right-clicking or shift-right-clicking it) do not use this packet.
|
||||||
|
START_FLYING_WITH_ELYTRA(8);
|
||||||
|
|
||||||
|
public static Action getById(final int id) {
|
||||||
|
return Arrays.stream(Action.values())
|
||||||
|
.filter(action -> action.id == id)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int entityId;
|
||||||
|
private Action action;
|
||||||
|
private int jumpBoost; // Only used by the “start jump with horse” action, in which case it ranges from 0 to 100. In all other cases it is 0.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetInputStream netStream) {
|
||||||
|
entityId = netStream.readVarInt();
|
||||||
|
action = Action.getById(netStream.readVarInt());
|
||||||
|
jumpBoost = netStream.readVarInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,22 +4,27 @@
|
|||||||
*/
|
*/
|
||||||
package mc.core.network.proto_1_12_2.packets;
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import mc.core.network.CSPacket;
|
||||||
|
import mc.core.network.NetInputStream;
|
||||||
import mc.core.network.NetOutputStream;
|
import mc.core.network.NetOutputStream;
|
||||||
import mc.core.network.SCPacket;
|
import mc.core.network.SCPacket;
|
||||||
|
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ToString
|
@ToString
|
||||||
public class PlayerAbilitiesPacket implements SCPacket {
|
public class PlayerAbilitiesPacket implements SCPacket, CSPacket {
|
||||||
private boolean godMode = false;
|
private boolean godMode = false;
|
||||||
private boolean flying = false;
|
private boolean flying = false;
|
||||||
private boolean canFly = false;
|
private boolean canFly = false;
|
||||||
private boolean instantDestroyBlocks = false;
|
private boolean instantDestroyBlocks = false;
|
||||||
private float flyingSpeed = 0.05f;
|
private float flyingSpeed = 0.05f;
|
||||||
private float fieldOfView = flyingSpeed;
|
private float fieldOfView = flyingSpeed;
|
||||||
|
private float walkingSpeed;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSelf(NetOutputStream netStream) {
|
public void writeSelf(NetOutputStream netStream) {
|
||||||
@@ -33,4 +38,17 @@ public class PlayerAbilitiesPacket implements SCPacket {
|
|||||||
netStream.writeFloat(flyingSpeed);
|
netStream.writeFloat(flyingSpeed);
|
||||||
netStream.writeFloat(fieldOfView);
|
netStream.writeFloat(fieldOfView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetInputStream netStream) {
|
||||||
|
byte flag = netStream.readByte();
|
||||||
|
//FIXME треубет проверки
|
||||||
|
godMode = (flag == 0x08);
|
||||||
|
canFly = (flag == 0x04);
|
||||||
|
flying = (flag == 0x02);
|
||||||
|
instantDestroyBlocks = (flag == 0x01);
|
||||||
|
|
||||||
|
flyingSpeed = netStream.readFloat();
|
||||||
|
walkingSpeed = netStream.readFloat();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import mc.core.Location;
|
||||||
|
import mc.core.network.CSPacket;
|
||||||
|
import mc.core.network.NetInputStream;
|
||||||
|
import mc.core.network.proto_1_12_2.Direction;
|
||||||
|
import mc.core.utils.CompactedCoords;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class PlayerBlockPlacementPacket implements CSPacket {
|
||||||
|
private Location location;
|
||||||
|
private Direction face;
|
||||||
|
/** true - main hand; false - off hand */
|
||||||
|
private boolean hand;
|
||||||
|
private float cursorX, cursorY, cursorZ;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetInputStream netStream) {
|
||||||
|
long compactedCoords = netStream.readLong();
|
||||||
|
double[] xyz = CompactedCoords.uncompressXYZ(compactedCoords);
|
||||||
|
location = new Location(xyz[0], xyz[1], xyz[2], null);
|
||||||
|
face = Direction.getById(netStream.readVarInt());
|
||||||
|
hand = (netStream.readVarInt() == 1);
|
||||||
|
cursorX = netStream.readFloat();
|
||||||
|
cursorY = netStream.readFloat();
|
||||||
|
cursorZ = netStream.readFloat();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import mc.core.Location;
|
||||||
|
import mc.core.network.CSPacket;
|
||||||
|
import mc.core.network.NetInputStream;
|
||||||
|
import mc.core.network.proto_1_12_2.Direction;
|
||||||
|
import mc.core.utils.CompactedCoords;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class PlayerDiggingPacket implements CSPacket {
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum Status {
|
||||||
|
STARTED_DIGGING(0),
|
||||||
|
CANCELLED_DIGGING(1),
|
||||||
|
FINISHED_DIGGING(2),
|
||||||
|
DROP_ITEM_STACK(3),
|
||||||
|
DROP_ITEM(4),
|
||||||
|
/* Indicates that the currently held item should have its
|
||||||
|
* state updated such as eating food, pulling back bows,
|
||||||
|
* using buckets, etc. Location is always set to 0/0/0,
|
||||||
|
* Face is always set to -Y.
|
||||||
|
*/
|
||||||
|
SHOOT_ARROW(5),
|
||||||
|
FINISH_EATING(5),
|
||||||
|
SWAP_ITEM_IN_HAND(6);
|
||||||
|
|
||||||
|
public static Status getById(final int id) {
|
||||||
|
return Arrays.stream(Status.values())
|
||||||
|
.filter(status -> status.id == id)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Status status;
|
||||||
|
private Location location;
|
||||||
|
private Direction face;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetInputStream netStream) {
|
||||||
|
status = Status.getById(netStream.readVarInt());
|
||||||
|
long compactCoord = netStream.readLong();
|
||||||
|
double[] xyz = CompactedCoords.uncompressXYZ(compactCoord);
|
||||||
|
location = new Location(xyz[0], xyz[1], xyz[2], null);
|
||||||
|
face = Direction.getById(netStream.readByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
import mc.core.network.NetOutputStream;
|
||||||
|
import mc.core.network.SCPacket;
|
||||||
|
|
||||||
|
public class UnloadChunkPacket implements SCPacket {
|
||||||
|
@Setter
|
||||||
|
private int x, z;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSelf(NetOutputStream netStream) {
|
||||||
|
netStream.writeInt(x);
|
||||||
|
netStream.writeInt(z);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
package mc.core.network.proto_1_12_2.packets;
|
|
||||||
|
|
||||||
import mc.core.EntityLocation;
|
|
||||||
import mc.core.world.Biome;
|
|
||||||
import mc.core.world.World;
|
|
||||||
import mc.core.world.WorldType;
|
|
||||||
import mc.core.world.block.Block;
|
|
||||||
import mc.core.world.block.BlockFactory;
|
|
||||||
import mc.core.world.block.BlockType;
|
|
||||||
import mc.core.world.chunk.Chunk;
|
|
||||||
import mc.core.world.chunk.ChunkSection;
|
|
||||||
|
|
||||||
public class DummyWorld implements World {
|
|
||||||
private class DummyChunkSection implements ChunkSection {
|
|
||||||
@Override
|
|
||||||
public int getSkyLight(int x, int y, int z) {
|
|
||||||
if (y <= 3) return 0;
|
|
||||||
else return 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSkyLight(int x, int y, int z, int lightLevel) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getAddition(int x, int y, int z) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAddition(int x, int y, int z, int value) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Biome getBiome(int localX, int localZ) {
|
|
||||||
return Biome.PLAINS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getX() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getY() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getZ() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBlock(Block block) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Block getBlock(int x, int y, int z) {
|
|
||||||
BlockFactory blockFactory = new BlockFactory();
|
|
||||||
|
|
||||||
if (y == 0) return blockFactory.create(BlockType.BEDROCK, x, y, z, getWorld());
|
|
||||||
else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, x, y, z, getWorld());
|
|
||||||
else if (y == 3) return blockFactory.create(BlockType.GRASS, x, y, z, getWorld());
|
|
||||||
else return blockFactory.create(BlockType.AIR, x, y, z, getWorld());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public World getWorld() {
|
|
||||||
return DummyWorld.this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DummyChunk implements Chunk {
|
|
||||||
@Override
|
|
||||||
public World getWorld() {
|
|
||||||
return DummyWorld.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWorld(World world) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChunkSection getChunkSection(int height) {
|
|
||||||
if (height < 1) return new DummyChunkSection();
|
|
||||||
else return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setChunkSection(int height, ChunkSection chunkSection) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Biome getBiome(int localX, int localZ) {
|
|
||||||
return Biome.PLAINS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBiome(int localX, int localZ, Biome biome) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getX() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getZ() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Chunk chunk = new DummyChunk();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WorldType getWorldType() {
|
|
||||||
return WorldType.FLAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EntityLocation getSpawn() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSpawn(EntityLocation location) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Chunk getChunk(int x, int z) {
|
|
||||||
return chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setChunk(int x, int z, Chunk chunk) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,15 +2,29 @@ package mc.core.network.proto_1_12_2.packets;
|
|||||||
|
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
||||||
|
import mc.core.world.Biome;
|
||||||
import mc.core.world.World;
|
import mc.core.world.World;
|
||||||
import org.junit.Assert;
|
import mc.core.world.WorldType;
|
||||||
|
import mc.core.world.block.BlockFactory;
|
||||||
|
import mc.core.world.block.BlockType;
|
||||||
|
import mc.core.world.chunk.Chunk;
|
||||||
|
import mc.core.world.chunk.ChunkSection;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class TestChunkdataPacket {
|
public class TestChunkdataPacket {
|
||||||
private static byte[] expectedPacketData;
|
private static byte[] expectedPacketData;
|
||||||
|
private World world;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeClassTest() throws IOException {
|
public static void beforeClassTest() throws IOException {
|
||||||
@@ -18,8 +32,48 @@ public class TestChunkdataPacket {
|
|||||||
expectedPacketData = ByteStreams.toByteArray(inputStream);
|
expectedPacketData = ByteStreams.toByteArray(inputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
private World createDummyWorld() {
|
@Before
|
||||||
return new DummyWorld();
|
public void prepareWorld() {
|
||||||
|
final ChunkSection chunkSection = mock(ChunkSection.class);
|
||||||
|
when(chunkSection.getSkyLight(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||||
|
int y = (int)invocation.getArguments()[1];
|
||||||
|
|
||||||
|
if (y <= 3) return 0;
|
||||||
|
else return 15;
|
||||||
|
});
|
||||||
|
when(chunkSection.getBiome(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||||
|
when(chunkSection.getBlock(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||||
|
Object[] args = invocation.getArguments();
|
||||||
|
int x = (int) args[0];
|
||||||
|
int y = (int) args[1];
|
||||||
|
int z = (int) args[2];
|
||||||
|
|
||||||
|
BlockFactory blockFactory = new BlockFactory();
|
||||||
|
|
||||||
|
if (y == 0) return blockFactory.create(BlockType.BEDROCK, x, y, z, null);
|
||||||
|
else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, x, y, z, null);
|
||||||
|
else if (y == 3) return blockFactory.create(BlockType.GRASS, x, y, z, null);
|
||||||
|
else return blockFactory.create(BlockType.AIR, x, y, z, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
world = mock(World.class);
|
||||||
|
when(world.getWorldType()).thenReturn(WorldType.FLAT);
|
||||||
|
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]);
|
||||||
|
when(chunk.getBiome(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||||
|
when(chunk.getChunkSection(anyInt())).thenAnswer(invocation1 -> {
|
||||||
|
int height = (int)invocation1.getArguments()[0];
|
||||||
|
|
||||||
|
if (height < 1) return chunkSection;
|
||||||
|
else return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return chunk;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -27,14 +81,14 @@ public class TestChunkdataPacket {
|
|||||||
ChunkDataPacket packet = new ChunkDataPacket();
|
ChunkDataPacket packet = new ChunkDataPacket();
|
||||||
packet.setX(0);
|
packet.setX(0);
|
||||||
packet.setZ(0);
|
packet.setZ(0);
|
||||||
packet.setChunk(createDummyWorld().getChunk(0, 0));
|
packet.setChunk(world.getChunk(0, 0));
|
||||||
packet.setInitChunk(true);
|
packet.setInitChunk(true);
|
||||||
|
|
||||||
ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream();
|
ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream();
|
||||||
packet.writeSelf(netStream);
|
packet.writeSelf(netStream);
|
||||||
byte[] actualPacketData = netStream.toByteArray();
|
byte[] actualPacketData = netStream.toByteArray();
|
||||||
|
|
||||||
Assert.assertEquals(expectedPacketData.length, actualPacketData.length);
|
assertEquals(expectedPacketData.length, actualPacketData.length);
|
||||||
Assert.assertArrayEquals(expectedPacketData, actualPacketData);
|
assertArrayEquals(expectedPacketData, actualPacketData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,13 +51,19 @@ public class PacketDecoder extends ByteToMessageDecoder {
|
|||||||
Class<? extends CSPacket> packetClass = state.getClientSidePacket(packetId);
|
Class<? extends CSPacket> packetClass = state.getClientSidePacket(packetId);
|
||||||
if (packetClass == null) {
|
if (packetClass == null) {
|
||||||
log.warn("Unknown packet: {}:0x{}", state.name(), hexPacketId);
|
log.warn("Unknown packet: {}:0x{}", state.name(), hexPacketId);
|
||||||
in.skipBytes(packetSize - rb);
|
in.skipBytes(in.readableBytes());
|
||||||
} else {
|
} else {
|
||||||
netStream.setDataSize(packetSize - rb);
|
netStream.setDataSize(packetSize - rb);
|
||||||
CSPacket packet = packetClass.newInstance();
|
CSPacket packet = packetClass.newInstance();
|
||||||
|
try {
|
||||||
packet.readSelf(netStream);
|
packet.readSelf(netStream);
|
||||||
log.debug("Known packet: {}:{}", state.name(), packet.toString());
|
log.debug("Known packet: {}:{}", state.name(), packet.toString());
|
||||||
out.add(packet);
|
out.add(packet);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Known packet: {}:{}. But throw exception. See debug log.", state.name(), packet.getClass().getSimpleName());
|
||||||
|
log.debug("Read packet", e);
|
||||||
|
in.skipBytes(in.readableBytes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package mc.core.network.proto_1_12_2.netty;
|
|||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import mc.core.events.SC_ChunkLoadEvent;
|
import mc.core.events.SC_ChunkLoadEvent;
|
||||||
|
import mc.core.events.SC_ChunkUnloadEvent;
|
||||||
import mc.core.events.SC_PlayerMoveEvent;
|
import mc.core.events.SC_PlayerMoveEvent;
|
||||||
import mc.core.network.proto_1_12_2.TeleportManager;
|
import mc.core.network.proto_1_12_2.TeleportManager;
|
||||||
import mc.core.network.proto_1_12_2.packets.ChunkDataPacket;
|
import mc.core.network.proto_1_12_2.packets.ChunkDataPacket;
|
||||||
import mc.core.network.proto_1_12_2.packets.PlayerPositionAndLookPacket;
|
import mc.core.network.proto_1_12_2.packets.PlayerPositionAndLookPacket;
|
||||||
|
import mc.core.network.proto_1_12_2.packets.UnloadChunkPacket;
|
||||||
import mc.core.utils.CompactedCoords;
|
import mc.core.utils.CompactedCoords;
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.chunk.Chunk;
|
||||||
import mc.core.world.chunk.ChunkSection;
|
import mc.core.world.chunk.ChunkSection;
|
||||||
@@ -26,8 +28,6 @@ class PlayerEventListener {
|
|||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void playerChunkLoadHandler(SC_ChunkLoadEvent event) {
|
public void playerChunkLoadHandler(SC_ChunkLoadEvent event) {
|
||||||
log.debug("(SC) playerChunkLoadHandler()");
|
|
||||||
|
|
||||||
for(Integer compressXZ : event.getNeedLoadChunks()) {
|
for(Integer compressXZ : event.getNeedLoadChunks()) {
|
||||||
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
||||||
Chunk chunk = event.getPlayer().getLocation().getWorld().getChunk(xz[0], xz[1]);
|
Chunk chunk = event.getPlayer().getLocation().getWorld().getChunk(xz[0], xz[1]);
|
||||||
@@ -38,9 +38,20 @@ class PlayerEventListener {
|
|||||||
packet.setInitChunk(true);
|
packet.setInitChunk(true);
|
||||||
packet.setChunk(chunk);
|
packet.setChunk(chunk);
|
||||||
|
|
||||||
event.getPlayer().getChannel().write(packet);
|
event.getPlayer().getChannel().writeAndFlush(packet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event.getPlayer().getChannel().flush();
|
@Subscribe
|
||||||
|
public void playerChunkUnloadHandler(SC_ChunkUnloadEvent event) {
|
||||||
|
for(Integer compressXZ : event.getNeedUnloadChunks()) {
|
||||||
|
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
||||||
|
|
||||||
|
UnloadChunkPacket packet = new UnloadChunkPacket();
|
||||||
|
packet.setX(xz[0]);
|
||||||
|
packet.setZ(xz[1]);
|
||||||
|
|
||||||
|
event.getPlayer().getChannel().writeAndFlush(packet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user