Merge branch 'proto_1.12.2' into h2-playermanager
# Conflicts: # core/src/main/java/mc/core/EntityLocation.java # core/src/main/java/mc/core/Location.java # core/src/test/java/mc/core/TestEntityLocation.java # core/src/test/java/mc/core/TestLocation.java
This commit is contained in:
@@ -35,15 +35,14 @@ subprojects {
|
|||||||
exclude group: 'commons-logging'
|
exclude group: 'commons-logging'
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Components */
|
/* Lombok */
|
||||||
compile (group: 'org.projectlombok', name: 'lombok', version: '1.16.16')
|
compile (group: 'org.projectlombok', name: 'lombok', version: '1.16.16')
|
||||||
|
|
||||||
/* JUnit */
|
/* Testing */
|
||||||
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)
|
testCompile (group: 'org.slf4j', name: 'slf4j-simple', version: slf4j_version)
|
||||||
/* Mockito */
|
|
||||||
testCompile (group: 'org.mockito', name: 'mockito-core', version: '1.9.5')
|
testCompile (group: 'org.mockito', name: 'mockito-core', version: '1.9.5')
|
||||||
|
testCompile (group: 'org.springframework', name: 'spring-test', version: spring_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
task copyDep(type: Copy) {
|
task copyDep(type: Copy) {
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ public class CoreEventListener {
|
|||||||
log.trace("(GameLoop) playerMoveEventHandler()");
|
log.trace("(GameLoop) playerMoveEventHandler()");
|
||||||
|
|
||||||
Chunk chunk;
|
Chunk chunk;
|
||||||
chunk = event.getOldLocation().getChunk(); // Old chunk
|
chunk = event.getPlayer().getWorld().getChunk(event.getOldLocation()); // Old chunk
|
||||||
int ccX = chunk.getX();
|
int ccX = chunk.getX();
|
||||||
int ccZ = chunk.getZ();
|
int ccZ = chunk.getZ();
|
||||||
chunk = event.getNewLocation().getChunk(); // Next chunk
|
chunk = event.getPlayer().getWorld().getChunk(event.getNewLocation()); // Next chunk
|
||||||
int ncX = chunk.getX();
|
int ncX = chunk.getX();
|
||||||
int ncZ = chunk.getZ();
|
int ncZ = chunk.getZ();
|
||||||
|
|
||||||
@@ -71,7 +71,11 @@ public class CoreEventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event.getPlayer().getLocation().setXYZ(event.getNewLocation());
|
event.getPlayer().getLocation().setXYZ(
|
||||||
|
event.getNewLocation().getX(),
|
||||||
|
event.getNewLocation().getY(),
|
||||||
|
event.getNewLocation().getZ()
|
||||||
|
);
|
||||||
|
|
||||||
// TODO отсылать клиенту только(!) для корректировки позиции
|
// TODO отсылать клиенту только(!) для корректировки позиции
|
||||||
// SC_PlayerMoveEvent nextEvent = new SC_PlayerMoveEvent(event.getPlayer());
|
// SC_PlayerMoveEvent nextEvent = new SC_PlayerMoveEvent(event.getPlayer());
|
||||||
|
|||||||
@@ -1,23 +1,29 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2018-08-08
|
|
||||||
*/
|
|
||||||
package mc.core;
|
package mc.core;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Data;
|
||||||
import mc.core.world.World;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.Objects;
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
public class EntityLocation extends Location implements Cloneable {
|
@Data
|
||||||
@Getter
|
public class EntityLocation implements Cloneable {
|
||||||
@Setter
|
private double x, y, z;
|
||||||
private float yaw, pitch;
|
private float yaw, pitch;
|
||||||
|
|
||||||
public EntityLocation(double x, double y, double z, float yaw, float pitch, World world) {
|
public static EntityLocation ZERO() {
|
||||||
super(x, y, z, world);
|
return new EntityLocation(0d,0d,0d,0f,0f);
|
||||||
setYawPitch(yaw, pitch);
|
}
|
||||||
|
|
||||||
|
public void set(EntityLocation location) {
|
||||||
|
setXYZ(location.x, location.y, location.z);
|
||||||
|
setYawPitch(location.yaw, location.pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXYZ(double x, double y, double z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setYawPitch(float yaw, float pitch) {
|
public void setYawPitch(float yaw, float pitch) {
|
||||||
@@ -25,27 +31,25 @@ public class EntityLocation extends Location implements Cloneable {
|
|||||||
this.pitch = pitch;
|
this.pitch = pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setYawPitch(EntityLocation entityLocation) {
|
public int getBlockX() {
|
||||||
setYawPitch(entityLocation.yaw, entityLocation.pitch);
|
return Double.valueOf(Math.floor(x)).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlockY() {
|
||||||
|
return Double.valueOf(Math.floor(y)).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlockZ() {
|
||||||
|
return Double.valueOf(Math.floor(z)).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityLocation clone() {
|
public EntityLocation clone() {
|
||||||
return (EntityLocation) super.clone();
|
try {
|
||||||
}
|
return (EntityLocation) super.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
@Override
|
e.printStackTrace();
|
||||||
public boolean equals(Object o) {
|
return null;
|
||||||
if (this == o) return true;
|
}
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
if (!super.equals(o)) return false;
|
|
||||||
EntityLocation that = (EntityLocation) o;
|
|
||||||
return Float.compare(that.yaw, yaw) == 0 &&
|
|
||||||
Float.compare(that.pitch, pitch) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(super.hashCode(), yaw, pitch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
57
core/src/main/java/mc/core/ImmutableEntityLocation.java
Normal file
57
core/src/main/java/mc/core/ImmutableEntityLocation.java
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package mc.core;
|
||||||
|
|
||||||
|
public class ImmutableEntityLocation extends EntityLocation {
|
||||||
|
public ImmutableEntityLocation(double x, double y, double z, float yaw, float pitch) {
|
||||||
|
super(x, y, z, yaw, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableEntityLocation(EntityLocation location) {
|
||||||
|
this(
|
||||||
|
location.getX(),
|
||||||
|
location.getY(),
|
||||||
|
location.getZ(),
|
||||||
|
location.getYaw(),
|
||||||
|
location.getPitch()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setX(double x) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setY(double y) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setZ(double z) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setYaw(float yaw) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPitch(float pitch) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(EntityLocation location) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setXYZ(double x, double y, double z) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setYawPitch(float yaw, float pitch) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2018-08-08
|
|
||||||
*/
|
|
||||||
package mc.core;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
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;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class Location implements Cloneable {
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private double x, y, z;
|
|
||||||
private Reference<World> refWorld;
|
|
||||||
|
|
||||||
public Location (double x, double y, double z, World world) {
|
|
||||||
setXYZ(x, y, z);
|
|
||||||
setWorld(world);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setXYZ(double x, double y, double z) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setXYZ(Location location) {
|
|
||||||
setXYZ(location.x, location.y, location.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public World getWorld() {
|
|
||||||
if (refWorld == null) {
|
|
||||||
return null;
|
|
||||||
} else if (refWorld.get() == null) {
|
|
||||||
throw new ResourceUnloadedException("You're trying to get unloaded world");
|
|
||||||
} else {
|
|
||||||
return refWorld.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWorld (World world) {
|
|
||||||
this.refWorld = new WeakReference<>(world);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBlockX() {
|
|
||||||
return Double.valueOf(Math.floor(x)).intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBlockY() {
|
|
||||||
return Double.valueOf(Math.floor(y)).intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBlockZ() {
|
|
||||||
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
|
|
||||||
public Location clone() {
|
|
||||||
try {
|
|
||||||
return (Location) super.clone();
|
|
||||||
} catch (CloneNotSupportedException e) { // такое в нашем случае вообще возможно?
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) return true;
|
|
||||||
if (obj == null || getClass() != obj.getClass()) return false;
|
|
||||||
Location location = (Location) obj;
|
|
||||||
return Double.compare(location.x, x) == 0 &&
|
|
||||||
Double.compare(location.y, y) == 0 &&
|
|
||||||
Double.compare(location.z, z) == 0 &&
|
|
||||||
Objects.equals(refWorld.get(), location.refWorld.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(x, y, z, refWorld.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,8 +12,7 @@ import mc.core.player.Player;
|
|||||||
import mc.core.player.PlayerManager;
|
import mc.core.player.PlayerManager;
|
||||||
import mc.core.text.Text;
|
import mc.core.text.Text;
|
||||||
import mc.core.text.Title;
|
import mc.core.text.Title;
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.World;
|
||||||
import mc.core.world.chunk.ChunkSection;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -53,7 +52,7 @@ public class FakePlayerManager implements PlayerManager {
|
|||||||
private static final NetChannel FAKE_NET_CHANNEL = new FakeNetChannet();
|
private static final NetChannel FAKE_NET_CHANNEL = new FakeNetChannet();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Player createPlayer(String name, EntityLocation defaultLocation) {
|
public Player createPlayer(String name, EntityLocation location, World world) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,20 +5,23 @@
|
|||||||
package mc.core.eventbus.events;
|
package mc.core.eventbus.events;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
|
import mc.core.ImmutableEntityLocation;
|
||||||
import mc.core.eventbus.EventBase;
|
import mc.core.eventbus.EventBase;
|
||||||
import mc.core.player.Player;
|
import mc.core.player.Player;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Getter
|
@Getter
|
||||||
public class CS_PlayerMoveEvent extends EventBase {
|
public class CS_PlayerMoveEvent extends EventBase {
|
||||||
private final Player player;
|
private final Player player;
|
||||||
private final EntityLocation oldLocation; // TODO сомнительное решение
|
private final ImmutableEntityLocation oldLocation;
|
||||||
// вообще нужно будет создать реализацию "иммутабл локейшен" для подобных ситуаций
|
|
||||||
@Setter
|
@Setter
|
||||||
private EntityLocation newLocation;
|
private EntityLocation newLocation;
|
||||||
@Setter
|
@Setter
|
||||||
private boolean recalcChunk = false;
|
private boolean recalcChunk = false;
|
||||||
|
|
||||||
|
public CS_PlayerMoveEvent(Player player, EntityLocation oldLocation) {
|
||||||
|
this.player = player;
|
||||||
|
this.oldLocation = new ImmutableEntityLocation(oldLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import mc.core.Config;
|
|||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
import mc.core.network.BroadcastNetChannel;
|
import mc.core.network.BroadcastNetChannel;
|
||||||
import mc.core.network.NetChannel;
|
import mc.core.network.NetChannel;
|
||||||
|
import mc.core.world.World;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -31,14 +32,13 @@ public class InMemoryPlayerManager implements PlayerManager, Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Player createPlayer(String name, EntityLocation defaultLocation) {
|
public Player createPlayer(String name, EntityLocation location, World world) {
|
||||||
SimplePlayer player = new SimplePlayer();
|
SimplePlayer player = new SimplePlayer();
|
||||||
player.setId(rand.nextInt(10000));
|
player.setId(rand.nextInt(10000));
|
||||||
player.setUUID(UUID.nameUUIDFromBytes(name.getBytes()));
|
player.setUUID(UUID.nameUUIDFromBytes(name.getBytes()));
|
||||||
player.setName(name);
|
player.setName(name);
|
||||||
player.getLocation().setXYZ(defaultLocation);
|
player.getLocation().set(location);
|
||||||
player.getLocation().setYawPitch(defaultLocation);
|
player.setWorld(world);
|
||||||
player.getLocation().setWorld(defaultLocation.getWorld());
|
|
||||||
player.setSettings(new PlayerSettings());
|
player.setSettings(new PlayerSettings());
|
||||||
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package mc.core.player;
|
|||||||
|
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
import mc.core.network.NetChannel;
|
import mc.core.network.NetChannel;
|
||||||
|
import mc.core.world.World;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -23,7 +24,8 @@ public interface Player {
|
|||||||
void setChannel(NetChannel channel);
|
void setChannel(NetChannel channel);
|
||||||
|
|
||||||
EntityLocation getLocation();
|
EntityLocation getLocation();
|
||||||
//TODO надо определиться - нужно ли здесь setLocation() или нет
|
World getWorld();
|
||||||
|
void setWorld(World world);
|
||||||
|
|
||||||
boolean isFlying();
|
boolean isFlying();
|
||||||
void setFlying(boolean value);
|
void setFlying(boolean value);
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ package mc.core.player;
|
|||||||
|
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
import mc.core.network.NetChannel;
|
import mc.core.network.NetChannel;
|
||||||
|
import mc.core.world.World;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface PlayerManager {
|
public interface PlayerManager {
|
||||||
Player createPlayer(String name, EntityLocation defaultLocation);
|
Player createPlayer(String name, EntityLocation location, World world);
|
||||||
void joinServer(Player player);
|
void joinServer(Player player);
|
||||||
void leftServer(Player player);
|
void leftServer(Player player);
|
||||||
Optional<Player> getPlayer(String name);
|
Optional<Player> getPlayer(String name);
|
||||||
|
|||||||
@@ -6,8 +6,12 @@ package mc.core.player;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
|
import mc.core.exception.ResourceUnloadedException;
|
||||||
import mc.core.network.NetChannel;
|
import mc.core.network.NetChannel;
|
||||||
|
import mc.core.world.World;
|
||||||
|
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -19,21 +23,33 @@ public class SimplePlayer implements Player {
|
|||||||
private String name;
|
private String name;
|
||||||
private boolean online = false;
|
private boolean online = false;
|
||||||
private NetChannel channel;
|
private NetChannel channel;
|
||||||
private EntityLocation location = new EntityLocation(0d, 0d, 0d, 0f, 0f, null);
|
private EntityLocation location = EntityLocation.ZERO();
|
||||||
|
private Reference<World> $refWorld;
|
||||||
private boolean flying = false;
|
private boolean flying = false;
|
||||||
private PlayerSettings settings;
|
private PlayerSettings settings;
|
||||||
private List<Integer> loadedChunks = new ArrayList<>();
|
private List<Integer> loadedChunks = new ArrayList<>();
|
||||||
|
|
||||||
public void setLocation(EntityLocation location) {
|
|
||||||
this.location.setXYZ(location);
|
|
||||||
this.location.setYawPitch(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getUuid() {
|
public UUID getUuid() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWorld() {
|
||||||
|
if ($refWorld == null) {
|
||||||
|
return null;
|
||||||
|
} else if ($refWorld.get() == null) {
|
||||||
|
throw new ResourceUnloadedException("You're trying to get unloaded world");
|
||||||
|
} else {
|
||||||
|
return $refWorld.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWorld(World world) {
|
||||||
|
this.$refWorld = new WeakReference<>(world);
|
||||||
|
}
|
||||||
|
|
||||||
public void setUUID(UUID uuid) {
|
public void setUUID(UUID uuid) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,18 +25,4 @@ public class CompactedCoords {
|
|||||||
int i = (int)value;
|
int i = (int)value;
|
||||||
return value < (double)i ? i - 1 : i;
|
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?
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package mc.core.world;
|
package mc.core.world;
|
||||||
|
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
|
import mc.core.world.block.BlockLocation;
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.chunk.Chunk;
|
||||||
|
|
||||||
public interface World {
|
public interface World {
|
||||||
@@ -16,4 +17,12 @@ public interface World {
|
|||||||
|
|
||||||
Chunk getChunk(int x, int z);
|
Chunk getChunk(int x, int z);
|
||||||
void setChunk(int x, int z, Chunk chunkSection);
|
void setChunk(int x, int z, Chunk chunkSection);
|
||||||
|
|
||||||
|
default Chunk getChunk(BlockLocation location) {
|
||||||
|
return getChunk(location.getX() >> 4, location.getZ() >> 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
default Chunk getChunk(EntityLocation location) {
|
||||||
|
return getChunk(location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package mc.core.world.block;
|
|||||||
import com.flowpowered.nbt.Tag;
|
import com.flowpowered.nbt.Tag;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import mc.core.Location;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -12,7 +11,7 @@ import java.util.stream.Stream;
|
|||||||
public abstract class AbstractBlock implements Block {
|
public abstract class AbstractBlock implements Block {
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private Location location;
|
private BlockLocation location;
|
||||||
@Getter
|
@Getter
|
||||||
private int light = 0;
|
private int light = 0;
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package mc.core.world.block;
|
package mc.core.world.block;
|
||||||
|
|
||||||
import mc.core.Location;
|
|
||||||
import mc.core.nbt.Taggable;
|
import mc.core.nbt.Taggable;
|
||||||
|
|
||||||
public interface Block extends Taggable{
|
public interface Block extends Taggable{
|
||||||
int getLight();
|
int getLight();
|
||||||
void setLight(int light);
|
void setLight(int light);
|
||||||
BlockType getBlockType();
|
BlockType getBlockType();
|
||||||
Location getLocation();
|
BlockLocation getLocation();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
package mc.core.world.block;
|
package mc.core.world.block;
|
||||||
|
|
||||||
import mc.core.Location;
|
|
||||||
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 BlockLocation(x, y, z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
30
core/src/main/java/mc/core/world/block/BlockLocation.java
Normal file
30
core/src/main/java/mc/core/world/block/BlockLocation.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package mc.core.world.block;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class BlockLocation implements Cloneable {
|
||||||
|
private int x, y, z;
|
||||||
|
|
||||||
|
public static BlockLocation ZERO() {
|
||||||
|
return new BlockLocation(0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXYZ(int x, int y, int z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockLocation clone() {
|
||||||
|
try {
|
||||||
|
return (BlockLocation) super.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
core/src/test/java/mc/core/SpringConfig.java
Normal file
34
core/src/test/java/mc/core/SpringConfig.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package mc.core;
|
||||||
|
|
||||||
|
import mc.core.world.World;
|
||||||
|
import mc.core.world.chunk.Chunk;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class SpringConfig {
|
||||||
|
@Bean()
|
||||||
|
public World simpleMockWorld() {
|
||||||
|
return mock(World.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public World chunkedMockWorld() {
|
||||||
|
World 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;
|
||||||
|
});
|
||||||
|
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
core/src/test/java/mc/core/TestBlockLocation.java
Normal file
40
core/src/test/java/mc/core/TestBlockLocation.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package mc.core;
|
||||||
|
|
||||||
|
import mc.core.world.block.BlockLocation;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
|
||||||
|
public class TestBlockLocation {
|
||||||
|
private static final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||||
|
private static final int minI = 0, maxI = 10;
|
||||||
|
private int x, y, z;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
x = rnd.nextInt(minI, maxI);
|
||||||
|
y = rnd.nextInt(minI, maxI);
|
||||||
|
z = rnd.nextInt(minI, maxI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
BlockLocation loc1 = new BlockLocation(x, y, z);
|
||||||
|
BlockLocation loc2 = new BlockLocation(x, y, z);
|
||||||
|
assertEquals(loc1, loc2);
|
||||||
|
|
||||||
|
loc2 = new BlockLocation(x+1, y+2, z-3);
|
||||||
|
assertNotEquals(loc1, loc2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClone() {
|
||||||
|
BlockLocation locOrig = new BlockLocation(x, y, z);
|
||||||
|
BlockLocation locClone = locOrig.clone();
|
||||||
|
assertEquals(locOrig, locClone);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package mc.core;
|
package mc.core;
|
||||||
|
|
||||||
import mc.core.world.World;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -8,51 +7,85 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertSame;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
public class TestEntityLocation {
|
public class TestEntityLocation {
|
||||||
private World mockWorld;
|
private static final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||||
|
private static final double minD = 0.0d, maxD = 10.0d;
|
||||||
|
private static final float minF = 0.0f, maxF = 359.9f;
|
||||||
|
private double x, y, z;
|
||||||
|
private float yaw, pitch;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
mockWorld = mock(World.class);
|
x = rnd.nextDouble(minD, maxD);
|
||||||
when(mockWorld.getName()).thenReturn("mock_world");
|
y = rnd.nextDouble(minD, maxD);
|
||||||
}
|
z = rnd.nextDouble(minD, maxD);
|
||||||
|
yaw = rnd.nextFloat() * (maxF - minF) + minF;
|
||||||
@Test
|
pitch = rnd.nextFloat() * (maxF - minF) + minF;
|
||||||
public void cloneTest() {
|
|
||||||
EntityLocation firstLocation = new EntityLocation(10, 20, 30, 40, 50, mockWorld);
|
|
||||||
assertSame("Lost world reference before cloning", mockWorld, firstLocation.getWorld());
|
|
||||||
EntityLocation locationClone = firstLocation.clone();
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEquals() {
|
public void testEquals() {
|
||||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
EntityLocation loc1 = new EntityLocation(x, y, z, yaw, pitch);
|
||||||
final double minD = 0.0d, maxD = 10.0d;
|
EntityLocation loc2 = new EntityLocation(x, y, z, yaw, pitch);
|
||||||
final float minF = 0.0f, maxF = 359.9f;
|
|
||||||
final double x = rnd.nextDouble(minD, maxD);
|
|
||||||
final double y = rnd.nextDouble(minD, maxD);
|
|
||||||
final double z = rnd.nextDouble(minD, maxD);
|
|
||||||
final float yaw = rnd.nextFloat() * (maxF - minF) + minF;
|
|
||||||
final float pitch = rnd.nextFloat() * (maxF - minF) + minF;
|
|
||||||
|
|
||||||
EntityLocation loc1 = new EntityLocation(x, y, z, yaw, pitch, mockWorld);
|
|
||||||
EntityLocation loc2 = new EntityLocation(x, y, z, yaw, pitch, mockWorld);
|
|
||||||
assertEquals(loc1, loc2);
|
assertEquals(loc1, loc2);
|
||||||
|
|
||||||
loc2 = new EntityLocation(x+3, y+1, z+2, yaw, pitch, mockWorld);
|
loc2 = new EntityLocation(x+1, y+2, z-3, yaw, pitch);
|
||||||
assertNotEquals(loc1, loc2);
|
assertNotEquals(loc1, loc2);
|
||||||
loc2 = new EntityLocation(x, y, z, yaw+5, pitch-1, mockWorld);
|
|
||||||
|
loc2 = new EntityLocation(x, y, z, yaw-1, pitch+2);
|
||||||
assertNotEquals(loc1, loc2);
|
assertNotEquals(loc1, loc2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClone() {
|
||||||
|
EntityLocation locOrig = new EntityLocation(x, y, z, yaw, pitch);
|
||||||
|
EntityLocation locClone = locOrig.clone();
|
||||||
|
assertEquals(locOrig, locClone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBlockXZ() {
|
||||||
|
EntityLocation location;
|
||||||
|
|
||||||
|
location = new EntityLocation(0d, 0, 0d, 0f, 0f);
|
||||||
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
35
core/src/test/java/mc/core/TestImmutableEntityLocation.java
Normal file
35
core/src/test/java/mc/core/TestImmutableEntityLocation.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package mc.core;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class TestImmutableEntityLocation {
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetValue() {
|
||||||
|
EntityLocation location = new ImmutableEntityLocation(1d, 2d, 3d, 4f, 5f);
|
||||||
|
|
||||||
|
thrown.expect(UnsupportedOperationException.class);
|
||||||
|
location.setX(1);
|
||||||
|
location.setY(1);
|
||||||
|
location.setZ(1);
|
||||||
|
location.setYaw(1);
|
||||||
|
location.setPitch(1);
|
||||||
|
location.setXYZ(1, 2, 3);
|
||||||
|
location.setYawPitch(1, 2);
|
||||||
|
location.set(EntityLocation.ZERO());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClone() {
|
||||||
|
EntityLocation locOrig = new ImmutableEntityLocation(1d, 2d, 3d, 4f, 5f);
|
||||||
|
EntityLocation locClone = locOrig.clone();
|
||||||
|
|
||||||
|
assertEquals(locOrig, locClone);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
package mc.core;
|
|
||||||
|
|
||||||
import mc.core.world.World;
|
|
||||||
import mc.core.world.chunk.Chunk;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEquals() {
|
|
||||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
|
||||||
final double minD = 0.0d, maxD = 10.0d;
|
|
||||||
final double x = rnd.nextDouble(minD, maxD);
|
|
||||||
final double y = rnd.nextDouble(minD, maxD);
|
|
||||||
final double z = rnd.nextDouble(minD, maxD);
|
|
||||||
|
|
||||||
Location loc1 = new Location(x, y, z, world);
|
|
||||||
Location loc2 = new Location(x, y, z, world);
|
|
||||||
assertEquals(loc1, loc2);
|
|
||||||
|
|
||||||
loc2 = new Location(x+3, y+1, z+2, world);
|
|
||||||
assertNotEquals(loc1, loc2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,61 +2,25 @@ package mc.core.utils;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
public class TestCompactedCoords {
|
public class TestCompactedCoords {
|
||||||
@Test
|
@Test
|
||||||
public void testXZSimple() {
|
public void testXZ() {
|
||||||
for (int z = -100; z <= 100; z++) {
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
for (int x = -100; x <= 100; x++) {
|
|
||||||
int compressXZ = CompactedCoords.compressXZ(x, z);
|
|
||||||
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
|
||||||
|
|
||||||
assertEquals(x, xz[0]);
|
|
||||||
assertEquals(z, xz[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testXZRandom() {
|
|
||||||
Random random = new Random();
|
|
||||||
int x,z;
|
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
do {
|
final int x = random.nextInt(Short.MIN_VALUE, Short.MAX_VALUE);
|
||||||
x = random.nextInt();
|
final int z = random.nextInt(Short.MIN_VALUE, Short.MAX_VALUE);
|
||||||
} while (x < Short.MIN_VALUE || x > Short.MAX_VALUE);
|
|
||||||
|
|
||||||
do {
|
final int compressXZ = CompactedCoords.compressXZ(x, z);
|
||||||
z = random.nextInt();
|
|
||||||
} while (z < Short.MIN_VALUE || z > Short.MAX_VALUE);
|
|
||||||
|
|
||||||
|
|
||||||
int compressXZ = CompactedCoords.compressXZ(x, z);
|
|
||||||
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
int[] xz = CompactedCoords.uncompressXZ(compressXZ);
|
||||||
|
|
||||||
assertEquals(x, xz[0]);
|
assertEquals(x, xz[0]);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package mc.world.flat;
|
package mc.world.flat;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
import mc.core.world.World;
|
import mc.core.world.World;
|
||||||
@@ -18,6 +19,7 @@ public class FlatWorld implements World {
|
|||||||
private final String name = "flat";
|
private final String name = "flat";
|
||||||
@Getter
|
@Getter
|
||||||
private final WorldType worldType = WorldType.FLAT;
|
private final WorldType worldType = WorldType.FLAT;
|
||||||
|
@Setter
|
||||||
private EntityLocation spawn;
|
private EntityLocation spawn;
|
||||||
private ChunkSection chunkSection = new SimpleChunkSection();
|
private ChunkSection chunkSection = new SimpleChunkSection();
|
||||||
|
|
||||||
@@ -25,18 +27,12 @@ public class FlatWorld implements World {
|
|||||||
public EntityLocation getSpawn() {
|
public EntityLocation getSpawn() {
|
||||||
if (this.spawn == null) {
|
if (this.spawn == null) {
|
||||||
log.warn("Spawn is not defined! Set spawn [0, 6, 0]");
|
log.warn("Spawn is not defined! Set spawn [0, 6, 0]");
|
||||||
this.spawn = new EntityLocation(0d, 6d, 0d, 0f, 0f, this);
|
this.spawn = new EntityLocation(0d, 6d, 0d, 0f, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.spawn;
|
return this.spawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSpawn(EntityLocation location) {
|
|
||||||
this.spawn = location;
|
|
||||||
this.spawn.setWorld(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Chunk getChunk(int x, int z) {
|
public Chunk getChunk(int x, int z) {
|
||||||
Chunk chunk = new SimpleChunk(x, z, this);
|
Chunk chunk = new SimpleChunk(x, z, this);
|
||||||
|
|||||||
@@ -9,12 +9,8 @@ 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.Chunk;
|
|
||||||
import mc.core.world.chunk.ChunkSection;
|
import mc.core.world.chunk.ChunkSection;
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
public class SimpleChunkSection implements ChunkSection {
|
public class SimpleChunkSection implements ChunkSection {
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public int getSkyLight(int x, int y, int z) {
|
||||||
@@ -63,10 +59,10 @@ public class SimpleChunkSection implements ChunkSection {
|
|||||||
public Block getBlock(int x, int y, int z) {
|
public Block getBlock(int x, int y, int z) {
|
||||||
BlockFactory blockFactory = new BlockFactory();
|
BlockFactory blockFactory = new BlockFactory();
|
||||||
|
|
||||||
if (y == 0) return blockFactory.create(BlockType.BEDROCK, x, y, z, getWorld());
|
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, getWorld());
|
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, getWorld());
|
else if (y == 3) return blockFactory.create(BlockType.GRASS, x, y, z);
|
||||||
else return blockFactory.create(BlockType.AIR, x, y, z, getWorld());
|
else return blockFactory.create(BlockType.AIR, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,10 +2,14 @@ package mc.core.h2db;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
|
import mc.core.exception.ResourceUnloadedException;
|
||||||
import mc.core.network.NetChannel;
|
import mc.core.network.NetChannel;
|
||||||
import mc.core.player.Player;
|
import mc.core.player.Player;
|
||||||
import mc.core.player.PlayerSettings;
|
import mc.core.player.PlayerSettings;
|
||||||
|
import mc.core.world.World;
|
||||||
|
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -18,6 +22,23 @@ public class H2Player implements Player {
|
|||||||
private List<Integer> loadedChunks;
|
private List<Integer> loadedChunks;
|
||||||
private NetChannel channel;
|
private NetChannel channel;
|
||||||
private EntityLocation location;
|
private EntityLocation location;
|
||||||
|
private Reference<World> $refWorld;
|
||||||
private boolean flying = false;
|
private boolean flying = false;
|
||||||
private PlayerSettings settings;
|
private PlayerSettings settings;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWorld() {
|
||||||
|
if ($refWorld == null) {
|
||||||
|
return null;
|
||||||
|
} else if ($refWorld.get() == null) {
|
||||||
|
throw new ResourceUnloadedException("You're trying to get unloaded world");
|
||||||
|
} else {
|
||||||
|
return $refWorld.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWorld(World world) {
|
||||||
|
this.$refWorld = new WeakReference<>(world);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class H2PlayerSerializer {
|
|||||||
stmt.setDouble(5, player.getLocation().getZ());
|
stmt.setDouble(5, player.getLocation().getZ());
|
||||||
stmt.setFloat(6, player.getLocation().getYaw());
|
stmt.setFloat(6, player.getLocation().getYaw());
|
||||||
stmt.setFloat(7, player.getLocation().getPitch());
|
stmt.setFloat(7, player.getLocation().getPitch());
|
||||||
stmt.setString(8, player.getLocation().getWorld().getName());
|
stmt.setString(8, player.getWorld().getName());
|
||||||
|
|
||||||
return stmt;
|
return stmt;
|
||||||
}, keyHolder);
|
}, keyHolder);
|
||||||
@@ -106,9 +106,9 @@ public class H2PlayerSerializer {
|
|||||||
resultSet.getDouble("location_y"),
|
resultSet.getDouble("location_y"),
|
||||||
resultSet.getDouble("location_z"),
|
resultSet.getDouble("location_z"),
|
||||||
resultSet.getFloat("location_yaw"),
|
resultSet.getFloat("location_yaw"),
|
||||||
resultSet.getFloat("location_pitch"),
|
resultSet.getFloat("location_pitch")
|
||||||
world
|
|
||||||
));
|
));
|
||||||
|
player.setWorld(world);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ public class TestH2Database {
|
|||||||
rnd.nextDouble(minD, maxD),
|
rnd.nextDouble(minD, maxD),
|
||||||
rnd.nextDouble(minD, maxD),
|
rnd.nextDouble(minD, maxD),
|
||||||
rnd.nextFloat() * (maxF - minF) + minF,
|
rnd.nextFloat() * (maxF - minF) + minF,
|
||||||
rnd.nextFloat() * (maxF - minF) + minF,
|
rnd.nextFloat() * (maxF - minF) + minF
|
||||||
mockWorld
|
|
||||||
));
|
));
|
||||||
|
player.setWorld(mockWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -81,7 +81,7 @@ public class TestH2Database {
|
|||||||
assertEquals(player.getLocation().getZ(), resultSet.getDouble("location_z"), 0.01d);
|
assertEquals(player.getLocation().getZ(), resultSet.getDouble("location_z"), 0.01d);
|
||||||
assertEquals(player.getLocation().getYaw(), resultSet.getFloat("location_yaw"), 0.01f);
|
assertEquals(player.getLocation().getYaw(), resultSet.getFloat("location_yaw"), 0.01f);
|
||||||
assertEquals(player.getLocation().getPitch(), resultSet.getFloat("location_pitch"), 0.01f);
|
assertEquals(player.getLocation().getPitch(), resultSet.getFloat("location_pitch"), 0.01f);
|
||||||
assertEquals(player.getLocation().getWorld().getName(), resultSet.getString("location_world"));
|
assertEquals(player.getWorld().getName(), resultSet.getString("location_world"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ public class TestH2Database {
|
|||||||
ps.setDouble(6, player.getLocation().getZ());
|
ps.setDouble(6, player.getLocation().getZ());
|
||||||
ps.setFloat(7, player.getLocation().getYaw());
|
ps.setFloat(7, player.getLocation().getYaw());
|
||||||
ps.setFloat(8, player.getLocation().getPitch());
|
ps.setFloat(8, player.getLocation().getPitch());
|
||||||
ps.setString(9, player.getLocation().getWorld().getName());
|
ps.setString(9, player.getWorld().getName());
|
||||||
});
|
});
|
||||||
assertEquals(1, affectedRows);
|
assertEquals(1, affectedRows);
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ public class TeleportManager {
|
|||||||
public void apply(int teleportId) {
|
public void apply(int teleportId) {
|
||||||
if (teleportMap.containsKey(teleportId)) {
|
if (teleportMap.containsKey(teleportId)) {
|
||||||
TpData data = teleportMap.remove(teleportId);
|
TpData data = teleportMap.remove(teleportId);
|
||||||
data.player.getLocation().setXYZ(data.newLocation);
|
data.player.getLocation().set(data.newLocation);
|
||||||
data.player.getLocation().setYawPitch(data.newLocation);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ import mc.core.network.SCPacket;
|
|||||||
@Setter
|
@Setter
|
||||||
@ToString
|
@ToString
|
||||||
public class PlayerAbilitiesPacket implements SCPacket, CSPacket {
|
public class PlayerAbilitiesPacket implements SCPacket, CSPacket {
|
||||||
|
private static final byte $GOD_MODE_MASK = 0x01,
|
||||||
|
$FLYING_MASK = 0x02,
|
||||||
|
$CAN_FLY_MASK = 0x04,
|
||||||
|
$IDB_MASK = 0x08;
|
||||||
|
|
||||||
private boolean godMode = false;
|
private boolean godMode = false;
|
||||||
private boolean flying = false;
|
private boolean flying = false;
|
||||||
private boolean canFly = false;
|
private boolean canFly = false;
|
||||||
@@ -29,10 +34,10 @@ public class PlayerAbilitiesPacket implements SCPacket, CSPacket {
|
|||||||
@Override
|
@Override
|
||||||
public void writeSelf(NetOutputStream netStream) {
|
public void writeSelf(NetOutputStream netStream) {
|
||||||
byte flag = 0;
|
byte flag = 0;
|
||||||
if (godMode) flag = (byte)(flag | 0x01);
|
if (godMode) flag = (byte)(flag | $GOD_MODE_MASK);
|
||||||
if (flying) flag = (byte)(flag | 0x02);
|
if (flying) flag = (byte)(flag | $FLYING_MASK);
|
||||||
if (canFly) flag = (byte)(flag | 0x04);
|
if (canFly) flag = (byte)(flag | $CAN_FLY_MASK);
|
||||||
if (instantDestroyBlocks) flag = (byte)(flag | 0x08);
|
if (instantDestroyBlocks) flag = (byte)(flag | $IDB_MASK);
|
||||||
|
|
||||||
netStream.writeByte(flag);
|
netStream.writeByte(flag);
|
||||||
netStream.writeFloat(flyingSpeed);
|
netStream.writeFloat(flyingSpeed);
|
||||||
@@ -42,11 +47,10 @@ public class PlayerAbilitiesPacket implements SCPacket, CSPacket {
|
|||||||
@Override
|
@Override
|
||||||
public void readSelf(NetInputStream netStream) {
|
public void readSelf(NetInputStream netStream) {
|
||||||
byte flag = netStream.readByte();
|
byte flag = netStream.readByte();
|
||||||
//FIXME треубет проверки
|
godMode = (flag & $GOD_MODE_MASK) > 0;
|
||||||
godMode = (flag == 0x08);
|
canFly = (flag & $CAN_FLY_MASK) > 0;
|
||||||
canFly = (flag == 0x04);
|
flying = (flag & $FLYING_MASK) > 0;
|
||||||
flying = (flag == 0x02);
|
instantDestroyBlocks = (flag & $IDB_MASK) > 0;
|
||||||
instantDestroyBlocks = (flag == 0x01);
|
|
||||||
|
|
||||||
flyingSpeed = netStream.readFloat();
|
flyingSpeed = netStream.readFloat();
|
||||||
walkingSpeed = netStream.readFloat();
|
walkingSpeed = netStream.readFloat();
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package mc.core.network.proto_1_12_2.packets;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.core.Location;
|
import mc.core.network.proto_1_12_2.serializers.BlockLocationSerializer;
|
||||||
|
import mc.core.world.block.BlockLocation;
|
||||||
import mc.core.network.CSPacket;
|
import mc.core.network.CSPacket;
|
||||||
import mc.core.network.NetInputStream;
|
import mc.core.network.NetInputStream;
|
||||||
import mc.core.network.proto_1_12_2.Direction;
|
import mc.core.network.proto_1_12_2.Direction;
|
||||||
@@ -11,7 +12,7 @@ import mc.core.utils.CompactedCoords;
|
|||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
public class PlayerBlockPlacementPacket implements CSPacket {
|
public class PlayerBlockPlacementPacket implements CSPacket {
|
||||||
private Location location;
|
private BlockLocation location;
|
||||||
private Direction face;
|
private Direction face;
|
||||||
/** true - main hand; false - off hand */
|
/** true - main hand; false - off hand */
|
||||||
private boolean hand;
|
private boolean hand;
|
||||||
@@ -20,8 +21,7 @@ public class PlayerBlockPlacementPacket implements CSPacket {
|
|||||||
@Override
|
@Override
|
||||||
public void readSelf(NetInputStream netStream) {
|
public void readSelf(NetInputStream netStream) {
|
||||||
long compactedCoords = netStream.readLong();
|
long compactedCoords = netStream.readLong();
|
||||||
double[] xyz = CompactedCoords.uncompressXYZ(compactedCoords);
|
location = BlockLocationSerializer.fromLong(compactedCoords);
|
||||||
location = new Location(xyz[0], xyz[1], xyz[2], null);
|
|
||||||
face = Direction.getById(netStream.readVarInt());
|
face = Direction.getById(netStream.readVarInt());
|
||||||
hand = (netStream.readVarInt() == 1);
|
hand = (netStream.readVarInt() == 1);
|
||||||
cursorX = netStream.readFloat();
|
cursorX = netStream.readFloat();
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package mc.core.network.proto_1_12_2.packets;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.core.Location;
|
import mc.core.network.proto_1_12_2.serializers.BlockLocationSerializer;
|
||||||
|
import mc.core.world.block.BlockLocation;
|
||||||
import mc.core.network.CSPacket;
|
import mc.core.network.CSPacket;
|
||||||
import mc.core.network.NetInputStream;
|
import mc.core.network.NetInputStream;
|
||||||
import mc.core.network.proto_1_12_2.Direction;
|
import mc.core.network.proto_1_12_2.Direction;
|
||||||
@@ -42,15 +43,14 @@ public class PlayerDiggingPacket implements CSPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Status status;
|
private Status status;
|
||||||
private Location location;
|
private BlockLocation location;
|
||||||
private Direction face;
|
private Direction face;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSelf(NetInputStream netStream) {
|
public void readSelf(NetInputStream netStream) {
|
||||||
status = Status.getById(netStream.readVarInt());
|
status = Status.getById(netStream.readVarInt());
|
||||||
long compactCoord = netStream.readLong();
|
long compactCoord = netStream.readLong();
|
||||||
double[] xyz = CompactedCoords.uncompressXYZ(compactCoord);
|
location = BlockLocationSerializer.fromLong(compactCoord);
|
||||||
location = new Location(xyz[0], xyz[1], xyz[2], null);
|
|
||||||
face = Direction.getById(netStream.readByte());
|
face = Direction.getById(netStream.readByte());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ public class PlayerPositionAndLookPacket implements SCPacket, CSPacket {
|
|||||||
netStream.readDouble(),
|
netStream.readDouble(),
|
||||||
netStream.readDouble(),
|
netStream.readDouble(),
|
||||||
netStream.readFloat(),
|
netStream.readFloat(),
|
||||||
netStream.readFloat(),
|
netStream.readFloat()
|
||||||
null
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.onGround = netStream.readBoolean();
|
this.onGround = netStream.readBoolean();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
package mc.core.network.proto_1_12_2.packets;
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
import mc.core.Location;
|
import mc.core.world.block.BlockLocation;
|
||||||
import mc.core.network.CSPacket;
|
import mc.core.network.CSPacket;
|
||||||
import mc.core.network.NetInputStream;
|
import mc.core.network.NetInputStream;
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ public class TabCompletePacket implements CSPacket {
|
|||||||
private String text;
|
private String text;
|
||||||
private boolean assumeCommand;
|
private boolean assumeCommand;
|
||||||
private boolean hasPosition;
|
private boolean hasPosition;
|
||||||
private Location location;
|
private BlockLocation location;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSelf(NetInputStream netStream) {
|
public void readSelf(NetInputStream netStream) {
|
||||||
@@ -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 BlockLocation((int)x, (int)y, (int)z); //FIXME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package mc.core.network.proto_1_12_2.serializers;
|
||||||
|
|
||||||
|
import mc.core.world.block.BlockLocation;
|
||||||
|
|
||||||
|
import static com.google.common.math.IntMath.isPowerOfTwo;
|
||||||
|
|
||||||
|
public class BlockLocationSerializer {
|
||||||
|
private static final int[] MULTIPLY_DE_BRUIJN_BIT_POSITION = new int[] {0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
|
||||||
|
private static final int NUM_X_BITS = 1 + log2(smallestEncompassingPowerOfTwo(30000000));
|
||||||
|
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 = 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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* net.minecraft.util.math.MathHelper#log2(int)
|
||||||
|
*/
|
||||||
|
private static int log2(int value) {
|
||||||
|
return log2DeBruijn(value) - (isPowerOfTwo(value) ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* net.minecraft.util.math.MathHelper#log2DeBruijn(int)
|
||||||
|
*/
|
||||||
|
private static int log2DeBruijn(int value) {
|
||||||
|
value = isPowerOfTwo(value) ? value : smallestEncompassingPowerOfTwo(value);
|
||||||
|
return MULTIPLY_DE_BRUIJN_BIT_POSITION[(int)((long)value * 125613361L >> 27) & 31];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* net.minecraft.util.math.MathHelper#smallestEncompassingPowerOfTwo(int)
|
||||||
|
*/
|
||||||
|
private static int smallestEncompassingPowerOfTwo(int value) {
|
||||||
|
int i = value - 1;
|
||||||
|
i = i | i >> 1;
|
||||||
|
i = i | i >> 2;
|
||||||
|
i = i | i >> 4;
|
||||||
|
i = i | i >> 8;
|
||||||
|
i = i | i >> 16;
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long toLong(BlockLocation location) {
|
||||||
|
return ((long)location.getX() & X_MASK) << X_SHIFT |
|
||||||
|
((long)location.getY() & Y_MASK) << Y_SHIFT |
|
||||||
|
((long)location.getZ() & Z_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockLocation fromLong(long value) {
|
||||||
|
BlockLocation location = BlockLocation.ZERO();
|
||||||
|
fromLong(value, location);
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void fromLong(long value, BlockLocation location) {
|
||||||
|
location.setX((int)(value << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS));
|
||||||
|
location.setY((int)(value << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS));
|
||||||
|
location.setZ((int)(value << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
|
import mc.core.network.proto_1_12_2.NetInputStream_p340;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.EOFException;
|
||||||
|
|
||||||
|
public class ByteArrayInputNetStream extends NetInputStream_p340 {
|
||||||
|
private ByteArrayInputStream bais;
|
||||||
|
|
||||||
|
public ByteArrayInputNetStream(byte[] buff) {
|
||||||
|
bais = new ByteArrayInputStream(buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean readBoolean() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte readByte() {
|
||||||
|
return (byte) bais.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readBytes(byte[] buffer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readUnsignedByte() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readUnsignedShort() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short readShort() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readInt() {
|
||||||
|
int ch1 = bais.read();
|
||||||
|
int ch2 = bais.read();
|
||||||
|
int ch3 = bais.read();
|
||||||
|
int ch4 = bais.read();
|
||||||
|
if ((ch1 | ch2 | ch3 | ch4) < 0) return 0;
|
||||||
|
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readLong() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float readFloat() {
|
||||||
|
return Float.intBitsToFloat(readInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double readDouble() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skipBytes(int count) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
|
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class TestByteArrayInputNetStream {
|
||||||
|
private Random rnd = new Random();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadByte() {
|
||||||
|
final byte b0 = (byte) rnd.nextInt();
|
||||||
|
ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream();
|
||||||
|
netStream.writeByte(b0);
|
||||||
|
byte[] buffer = netStream.toByteArray();
|
||||||
|
|
||||||
|
ByteArrayInputNetStream netInputStream = new ByteArrayInputNetStream(buffer);
|
||||||
|
byte b1 = netInputStream.readByte();
|
||||||
|
assertEquals(b0, b1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadInt() {
|
||||||
|
final int i0 = rnd.nextInt();
|
||||||
|
ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream();
|
||||||
|
netStream.writeInt(i0);
|
||||||
|
byte[] buffer = netStream.toByteArray();
|
||||||
|
|
||||||
|
ByteArrayInputNetStream netInputStream = new ByteArrayInputNetStream(buffer);
|
||||||
|
int i1 = netInputStream.readInt();
|
||||||
|
assertEquals(i0, i1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadFloat() {
|
||||||
|
final float f0 = rnd.nextFloat();
|
||||||
|
ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream();
|
||||||
|
netStream.writeFloat(f0);
|
||||||
|
byte[] buffer = netStream.toByteArray();
|
||||||
|
|
||||||
|
ByteArrayInputNetStream netInputStream = new ByteArrayInputNetStream(buffer);
|
||||||
|
float f1 = netInputStream.readFloat();
|
||||||
|
assertEquals(f0, f1, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
|
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class TestPlayerAbilitiesPacket {
|
||||||
|
private Random rnd = new Random();
|
||||||
|
private PlayerAbilitiesPacket packet;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
packet = new PlayerAbilitiesPacket();
|
||||||
|
packet.setGodMode(rnd.nextBoolean());
|
||||||
|
packet.setFlying(rnd.nextBoolean());
|
||||||
|
packet.setCanFly(rnd.nextBoolean());
|
||||||
|
packet.setInstantDestroyBlocks(rnd.nextBoolean());
|
||||||
|
packet.setFlyingSpeed(rnd.nextFloat());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
ByteArrayOutputNetStream netOutputStream = new ByteArrayOutputNetStream();
|
||||||
|
packet.writeSelf(netOutputStream);
|
||||||
|
|
||||||
|
ByteArrayInputNetStream netInputStream = new ByteArrayInputNetStream(netOutputStream.toByteArray());
|
||||||
|
PlayerAbilitiesPacket outPkt = new PlayerAbilitiesPacket();
|
||||||
|
outPkt.readSelf(netInputStream);
|
||||||
|
|
||||||
|
assertEquals("god mode", packet.isGodMode(), outPkt.isGodMode());
|
||||||
|
assertEquals("flying", packet.isFlying(), outPkt.isFlying());
|
||||||
|
assertEquals("can fly", packet.isCanFly(), outPkt.isCanFly());
|
||||||
|
assertEquals("instant destroy block", packet.isInstantDestroyBlocks(), outPkt.isInstantDestroyBlocks());
|
||||||
|
assertEquals("flying speed", packet.getFlyingSpeed(), outPkt.getFlyingSpeed(), 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package mc.core.network.proto_1_12_2.serializers;
|
||||||
|
|
||||||
|
import mc.core.world.block.BlockLocation;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class TestBlockLocationSerializer {
|
||||||
|
private static final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||||
|
private static final int minI = 0, maxI = 10;
|
||||||
|
private int x, y, z;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
x = rnd.nextInt(minI, maxI);
|
||||||
|
y = rnd.nextInt(minI, maxI);
|
||||||
|
z = rnd.nextInt(minI, maxI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
BlockLocation location = new BlockLocation(x, y, z);
|
||||||
|
final long serializedCoords = BlockLocationSerializer.toLong(location);
|
||||||
|
|
||||||
|
BlockLocation deserLoc = BlockLocationSerializer.fromLong(serializedCoords);
|
||||||
|
|
||||||
|
assertEquals(location, deserLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ class PlayerEventListener {
|
|||||||
public void playerChunkLoadHandler(SC_ChunkLoadEvent event) {
|
public void playerChunkLoadHandler(SC_ChunkLoadEvent event) {
|
||||||
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().getWorld().getChunk(xz[0], xz[1]);
|
||||||
|
|
||||||
ChunkDataPacket packet = new ChunkDataPacket();
|
ChunkDataPacket packet = new ChunkDataPacket();
|
||||||
packet.setX(xz[0]);
|
packet.setX(xz[0]);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import mc.core.text.TextColor;
|
|||||||
import mc.core.text.TextStyle;
|
import mc.core.text.TextStyle;
|
||||||
import mc.core.utils.CompactedCoords;
|
import mc.core.utils.CompactedCoords;
|
||||||
import mc.core.world.World;
|
import mc.core.world.World;
|
||||||
|
import mc.core.world.chunk.Chunk;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -50,7 +51,8 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
Player player = playerManager.getPlayer(packet.getPlayerName())
|
Player player = playerManager.getPlayer(packet.getPlayerName())
|
||||||
.orElseGet(() -> playerManager.createPlayer(
|
.orElseGet(() -> playerManager.createPlayer(
|
||||||
packet.getPlayerName(),
|
packet.getPlayerName(),
|
||||||
world.getSpawn()));
|
world.getSpawn(),
|
||||||
|
world));
|
||||||
|
|
||||||
channel.writeAndFlush(new LoginSuccessPacket(
|
channel.writeAndFlush(new LoginSuccessPacket(
|
||||||
player.getUuid(),
|
player.getUuid(),
|
||||||
@@ -83,9 +85,10 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
|
|
||||||
// First Chunk
|
// First Chunk
|
||||||
ChunkDataPacket pkt8 = new ChunkDataPacket();
|
ChunkDataPacket pkt8 = new ChunkDataPacket();
|
||||||
pkt8.setX(player.getLocation().getChunk().getX());
|
Chunk chunk = player.getWorld().getChunk(player.getLocation());
|
||||||
pkt8.setZ(player.getLocation().getChunk().getZ());
|
pkt8.setX(chunk.getX());
|
||||||
pkt8.setChunk(player.getLocation().getChunk());
|
pkt8.setZ(chunk.getZ());
|
||||||
|
pkt8.setChunk(chunk);
|
||||||
pkt8.setInitChunk(true);
|
pkt8.setInitChunk(true);
|
||||||
channel.writeAndFlush(pkt8);
|
channel.writeAndFlush(pkt8);
|
||||||
player.getLoadedChunks().add(CompactedCoords.compressXZ(0, 0));
|
player.getLoadedChunks().add(CompactedCoords.compressXZ(0, 0));
|
||||||
|
|||||||
@@ -55,8 +55,7 @@ public class PlayHandler extends AbstractStateHandler implements PlayStateHandle
|
|||||||
@Handler
|
@Handler
|
||||||
public void onPositionAndLook(Channel channel, PlayerPositionAndLookPacket packet) {
|
public void onPositionAndLook(Channel channel, PlayerPositionAndLookPacket packet) {
|
||||||
Player player = channel.attr(ATTR_PLAYER).get();
|
Player player = channel.attr(ATTR_PLAYER).get();
|
||||||
player.getLocation().setXYZ(packet.getLocation());
|
player.getLocation().set(packet.getLocation());
|
||||||
player.getLocation().setYawPitch(packet.getLocation());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Handler
|
@Handler
|
||||||
@@ -82,8 +81,7 @@ public class PlayHandler extends AbstractStateHandler implements PlayStateHandle
|
|||||||
event.setNewLocation(new EntityLocation(
|
event.setNewLocation(new EntityLocation(
|
||||||
packet.getX(), packet.getY(), packet.getZ(),
|
packet.getX(), packet.getY(), packet.getZ(),
|
||||||
player.getLocation().getYaw(),
|
player.getLocation().getYaw(),
|
||||||
player.getLocation().getPitch(),
|
player.getLocation().getPitch()
|
||||||
player.getLocation().getWorld()
|
|
||||||
));
|
));
|
||||||
EventBusGetter.getInstance().post(event);
|
EventBusGetter.getInstance().post(event);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user