Fixed teleportation & improved first chunk loading

This commit is contained in:
TheMode 2019-08-31 12:10:46 +02:00
parent 666f433ae7
commit f43bf11e66
8 changed files with 64 additions and 73 deletions

View File

@ -4,6 +4,7 @@ import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.PacketWriterUtils; import fr.themode.minestom.net.PacketWriterUtils;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
public interface Viewable { public interface Viewable {
@ -19,60 +20,31 @@ public interface Viewable {
} }
default void sendPacketToViewers(ServerPacket packet) { default void sendPacketToViewers(ServerPacket packet) {
if (getViewers().isEmpty()) PacketWriterUtils.writeAndSend(getViewers(), packet);
return;
PacketWriterUtils.writeCallbackPacket(packet, buffer -> {
int size = getViewers().size();
if (size == 0)
return;
buffer.getData().retain(size).markReaderIndex();
for (Player viewer : getViewers()) {
viewer.getPlayerConnection().writeUnencodedPacket(buffer);
buffer.getData().resetReaderIndex();
}
});
} }
default void sendPacketsToViewers(ServerPacket... packets) { default void sendPacketsToViewers(ServerPacket... packets) {
if (getViewers().isEmpty())
return;
for (ServerPacket packet : packets) { for (ServerPacket packet : packets) {
PacketWriterUtils.writeCallbackPacket(packet, buffer -> { PacketWriterUtils.writeAndSend(getViewers(), packet);
int size = getViewers().size();
if (size == 0)
return;
buffer.getData().retain(size).markReaderIndex();
for (Player viewer : getViewers()) {
viewer.getPlayerConnection().writeUnencodedPacket(buffer);
buffer.getData().resetReaderIndex();
}
});
} }
} }
default void sendPacketToViewersAndSelf(ServerPacket packet) { default void sendPacketToViewersAndSelf(ServerPacket packet) {
if (this instanceof Player) { if (this instanceof Player) {
UNSAFE_sendPacketToViewersAndSelf(packet); if (getViewers().isEmpty()) {
((Player) this).getPlayerConnection().sendPacket(packet);
} else {
UNSAFE_sendPacketToViewersAndSelf(packet);
}
} else { } else {
sendPacketToViewers(packet); sendPacketToViewers(packet);
} }
} }
private void UNSAFE_sendPacketToViewersAndSelf(ServerPacket packet) { private void UNSAFE_sendPacketToViewersAndSelf(ServerPacket packet) {
PacketWriterUtils.writeCallbackPacket(packet, buffer -> { Set<Player> recipients = new HashSet<>(getViewers());
int size = getViewers().size(); recipients.add((Player) this);
buffer.getData().retain(size + 1).markReaderIndex(); PacketWriterUtils.writeAndSend(recipients, packet);
((Player) this).getPlayerConnection().writeUnencodedPacket(buffer);
buffer.getData().resetReaderIndex();
if (size != 0) {
for (Player viewer : getViewers()) {
buffer.getData().resetReaderIndex();
viewer.getPlayerConnection().writeUnencodedPacket(buffer);
}
}
});
} }
} }

View File

@ -46,7 +46,6 @@ public abstract class Entity implements Viewable, DataContainer {
protected Entity vehicle; protected Entity vehicle;
// Velocity // Velocity
// TODO gravity implementation for entity other than players
protected Vector velocity = new Vector(); // Movement in block per second protected Vector velocity = new Vector(); // Movement in block per second
protected float gravityDragPerTick; protected float gravityDragPerTick;
private int gravityTickCounter; private int gravityTickCounter;
@ -247,8 +246,9 @@ public abstract class Entity implements Viewable, DataContainer {
gravityTickCounter = 0; gravityTickCounter = 0;
} }
if (this instanceof EntityCreature) // Objects are automatically updated client side if (this instanceof EntityCreature) {
teleport(getPosition()); teleport(getPosition());
}
} }
} }
@ -444,7 +444,7 @@ public abstract class Entity implements Viewable, DataContainer {
position.setZ(z); position.setZ(z);
for (Entity passenger : getPassengers()) { for (Entity passenger : getPassengers()) {
passenger.position = getPosition().clone(); passenger.refreshPosition(x, y, z);
} }
Instance instance = getInstance(); Instance instance = getInstance();
@ -455,17 +455,8 @@ public abstract class Entity implements Viewable, DataContainer {
synchronized (instance) { synchronized (instance) {
instance.removeEntityFromChunk(this, lastChunk); instance.removeEntityFromChunk(this, lastChunk);
instance.addEntityToChunk(this, newChunk); instance.addEntityToChunk(this, newChunk);
for (Entity passenger : getPassengers()) {
instance.removeEntityFromChunk(passenger, lastChunk);
instance.addEntityToChunk(passenger, newChunk);
}
} }
updateView(this, lastChunk, newChunk); updateView(this, lastChunk, newChunk);
for (Entity passenger : getPassengers()) {
updateView(passenger, lastChunk, newChunk);
}
} }
} }
} }
@ -647,7 +638,9 @@ public abstract class Entity implements Viewable, DataContainer {
entityTeleportPacket.position = getPosition(); entityTeleportPacket.position = getPosition();
entityTeleportPacket.onGround = isOnGround(); entityTeleportPacket.onGround = isOnGround();
sendPacketToViewers(entityTeleportPacket); sendPacketToViewers(entityTeleportPacket);
sendPacketToViewers(getPassengersPacket());
if (!passengers.isEmpty())
sendPacketToViewers(getPassengersPacket());
} }
private void fillAirTickMetaData(Buffer buffer) { private void fillAirTickMetaData(Buffer buffer) {

View File

@ -13,6 +13,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer; import java.util.function.Consumer;
public class EntityManager { public class EntityManager {
@ -43,18 +44,28 @@ public class EntityManager {
Position position = playerCache.getPosition(); Position position = playerCache.getPosition();
long[] visibleChunks = ChunkUtils.getChunksInRange(position, Main.CHUNK_VIEW_DISTANCE); long[] visibleChunks = ChunkUtils.getChunksInRange(position, Main.CHUNK_VIEW_DISTANCE);
for (int i = 0; i < visibleChunks.length; i++) { int length = visibleChunks.length;
AtomicInteger counter = new AtomicInteger(0);
for (int i = 0; i < length; i++) {
int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunks[i]); int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunks[i]);
int chunkX = chunkPos[0]; int chunkX = chunkPos[0];
int chunkZ = chunkPos[1]; int chunkZ = chunkPos[1];
boolean isLast = i == visibleChunks.length - 1; Consumer<Chunk> callback = (chunk) -> {
Consumer<Chunk> callback = isLast ? chunk -> { boolean isLast = counter.get() == length - 1;
playerCache.spawned = true; if (isLast) {
playerCache.setInstance(spawningInstance); // This is the last chunk to be loaded, spawn player
PlayerSpawnEvent spawnEvent = new PlayerSpawnEvent(); playerCache.spawned = true;
playerCache.callEvent(PlayerSpawnEvent.class, spawnEvent); playerCache.setInstance(spawningInstance);
playerCache.updateViewPosition(chunk); PlayerSpawnEvent spawnEvent = new PlayerSpawnEvent();
} : null; playerCache.callEvent(PlayerSpawnEvent.class, spawnEvent);
playerCache.updateViewPosition(chunk);
} else {
// Increment the counter of current loaded chunks
counter.incrementAndGet();
}
};
// WARNING: if auto load is disabled and no chunks are loaded beforehand, player will be stuck. // WARNING: if auto load is disabled and no chunks are loaded beforehand, player will be stuck.
spawningInstance.loadChunk(chunkX, chunkZ, callback); spawningInstance.loadChunk(chunkX, chunkZ, callback);

View File

@ -115,7 +115,7 @@ public class Player extends LivingEntity {
sendMessage("You attacked an entity!"); sendMessage("You attacked an entity!");
} else if (entity instanceof Player) { } else if (entity instanceof Player) {
Player player = (Player) entity; Player player = (Player) entity;
Vector velocity = getPosition().clone().getDirection().multiply(6); Vector velocity = getPosition().clone().getDirection().multiply(4);
velocity.setY(3.5f); velocity.setY(3.5f);
player.setVelocity(velocity, 150); player.setVelocity(velocity, 150);
player.damage(2); player.damage(2);
@ -155,7 +155,7 @@ public class Player extends LivingEntity {
setEventCallback(PlayerSpawnEvent.class, event -> { setEventCallback(PlayerSpawnEvent.class, event -> {
System.out.println("SPAWN"); System.out.println("SPAWN");
setGameMode(GameMode.SURVIVAL); setGameMode(GameMode.CREATIVE);
teleport(new Position(0, 66, 0)); teleport(new Position(0, 66, 0));
/*ChickenCreature chickenCreature = new ChickenCreature(); /*ChickenCreature chickenCreature = new ChickenCreature();
@ -330,6 +330,8 @@ public class Player extends LivingEntity {
@Override @Override
public void addViewer(Player player) { public void addViewer(Player player) {
if (player == this)
return;
super.addViewer(player); super.addViewer(player);
PlayerConnection connection = player.getPlayerConnection(); PlayerConnection connection = player.getPlayerConnection();
String property = "eyJ0aW1lc3RhbXAiOjE1NjU0ODMwODQwOTYsInByb2ZpbGVJZCI6ImFiNzBlY2I0MjM0NjRjMTRhNTJkN2EwOTE1MDdjMjRlIiwicHJvZmlsZU5hbWUiOiJUaGVNb2RlOTExIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RkOTE2NzJiNTE0MmJhN2Y3MjA2ZTRjN2IwOTBkNzhlM2Y1ZDc2NDdiNWFmZDIyNjFhZDk4OGM0MWI2ZjcwYTEifX19"; String property = "eyJ0aW1lc3RhbXAiOjE1NjU0ODMwODQwOTYsInByb2ZpbGVJZCI6ImFiNzBlY2I0MjM0NjRjMTRhNTJkN2EwOTE1MDdjMjRlIiwicHJvZmlsZU5hbWUiOiJUaGVNb2RlOTExIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RkOTE2NzJiNTE0MmJhN2Y3MjA2ZTRjN2IwOTBkNzhlM2Y1ZDc2NDdiNWFmZDIyNjFhZDk4OGM0MWI2ZjcwYTEifX19";
@ -355,6 +357,8 @@ public class Player extends LivingEntity {
@Override @Override
public void removeViewer(Player player) { public void removeViewer(Player player) {
if (player == this)
return;
super.removeViewer(player); super.removeViewer(player);
PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.REMOVE_PLAYER); PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.REMOVE_PLAYER);
playerInfoPacket.playerInfos.add(new PlayerInfoPacket.RemovePlayer(getUuid())); playerInfoPacket.playerInfos.add(new PlayerInfoPacket.RemovePlayer(getUuid()));
@ -523,7 +527,7 @@ public class Player extends LivingEntity {
int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunks[index]); int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunks[index]);
instance.loadOptionalChunk(chunkPos[0], chunkPos[1], chunk -> { instance.loadOptionalChunk(chunkPos[0], chunkPos[1], chunk -> {
if (chunk == null) { if (chunk == null) {
return; // Cannot load chunk (auto load not enabled) return; // Cannot load chunk (auto load is not enabled)
} }
instance.sendChunk(this, chunk); instance.sendChunk(this, chunk);
if (isFar && isLast) { if (isFar && isLast) {
@ -536,8 +540,6 @@ public class Player extends LivingEntity {
@Override @Override
public void teleport(Position position, Runnable callback) { public void teleport(Position position, Runnable callback) {
super.teleport(position, () -> { super.teleport(position, () -> {
if (!instance.hasEnabledAutoChunkLoad() && ChunkUtils.isChunkUnloaded(instance, position.getX(), position.getZ()))
return;
updatePlayerPosition(); updatePlayerPosition();
if (callback != null) if (callback != null)
callback.run(); callback.run();

View File

@ -42,7 +42,6 @@ public class PlayerPositionListener {
} }
private static void processMovement(Player player, float x, float y, float z, Runnable runnable) { private static void processMovement(Player player, float x, float y, float z, Runnable runnable) {
//System.out.println("MOVEMENT PACKET " + Math.round(x) + ":" + Math.round(y) + ":" + Math.round(z));
boolean chunkTest = ChunkUtils.isChunkUnloaded(player.getInstance(), x, z); boolean chunkTest = ChunkUtils.isChunkUnloaded(player.getInstance(), x, z);
if (chunkTest) { if (chunkTest) {
player.teleport(player.getPosition()); player.teleport(player.getPosition());

View File

@ -3,9 +3,11 @@ package fr.themode.minestom.net;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.adamaq01.ozao.net.packet.Packet; import fr.adamaq01.ozao.net.packet.Packet;
import fr.themode.minestom.Main; import fr.themode.minestom.Main;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.PacketUtils; import fr.themode.minestom.utils.PacketUtils;
import java.util.Collection;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -21,4 +23,21 @@ public class PacketWriterUtils {
}); });
} }
public static void writeAndSend(Collection<Player> players, ServerPacket serverPacket) {
batchesPool.execute(() -> {
Packet p = PacketUtils.writePacket(serverPacket);
Buffer encoded = PacketUtils.encode(p);
int size = players.size();
if (size == 0)
return;
encoded.getData().retain(size).markReaderIndex();
for (Player player : players) {
player.getPlayerConnection().writeUnencodedPacket(encoded);
encoded.getData().resetReaderIndex();
}
});
}
} }

View File

@ -29,6 +29,7 @@ public class PacketUtils {
public static Buffer encode(Packet packet) { public static Buffer encode(Packet packet) {
Buffer buffer = Buffer.create(); Buffer buffer = Buffer.create();
Buffer idAndPayload = Buffer.create(); Buffer idAndPayload = Buffer.create();
writeVarInt(idAndPayload, packet.get(PACKET_ID_IDENTIFIER)); writeVarInt(idAndPayload, packet.get(PACKET_ID_IDENTIFIER));
idAndPayload.putBuffer(packet.getPayload()); idAndPayload.putBuffer(packet.getPayload());
writeVarInt(buffer, idAndPayload.length()); writeVarInt(buffer, idAndPayload.length());

View File

@ -5,7 +5,6 @@ import fr.themode.minestom.chat.Chat;
import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.item.ItemStack;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.UUID;
public class Utils { public class Utils {
@ -132,11 +131,6 @@ public class Utils {
return SerializerUtils.longToBlockPosition(buffer.getLong()); return SerializerUtils.longToBlockPosition(buffer.getLong());
} }
public static void writeUuid(Buffer buffer, UUID uuid) {
buffer.putLong(uuid.getMostSignificantBits());
buffer.putLong(uuid.getLeastSignificantBits());
}
public static void writeItemStack(Buffer buffer, ItemStack itemStack) { public static void writeItemStack(Buffer buffer, ItemStack itemStack) {
if (itemStack == null) { if (itemStack == null) {
buffer.putBoolean(false); buffer.putBoolean(false);