mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-27 19:47:44 +01:00
Fixed teleportation & improved first chunk loading
This commit is contained in:
parent
666f433ae7
commit
f43bf11e66
@ -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) {
|
||||||
|
if (getViewers().isEmpty()) {
|
||||||
|
((Player) this).getPlayerConnection().sendPacket(packet);
|
||||||
|
} else {
|
||||||
UNSAFE_sendPacketToViewersAndSelf(packet);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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,10 +246,11 @@ 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
update();
|
update();
|
||||||
@ -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,6 +638,8 @@ public abstract class Entity implements Viewable, DataContainer {
|
|||||||
entityTeleportPacket.position = getPosition();
|
entityTeleportPacket.position = getPosition();
|
||||||
entityTeleportPacket.onGround = isOnGround();
|
entityTeleportPacket.onGround = isOnGround();
|
||||||
sendPacketToViewers(entityTeleportPacket);
|
sendPacketToViewers(entityTeleportPacket);
|
||||||
|
|
||||||
|
if (!passengers.isEmpty())
|
||||||
sendPacketToViewers(getPassengersPacket());
|
sendPacketToViewers(getPassengersPacket());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
if (isLast) {
|
||||||
|
// This is the last chunk to be loaded, spawn player
|
||||||
playerCache.spawned = true;
|
playerCache.spawned = true;
|
||||||
playerCache.setInstance(spawningInstance);
|
playerCache.setInstance(spawningInstance);
|
||||||
PlayerSpawnEvent spawnEvent = new PlayerSpawnEvent();
|
PlayerSpawnEvent spawnEvent = new PlayerSpawnEvent();
|
||||||
playerCache.callEvent(PlayerSpawnEvent.class, spawnEvent);
|
playerCache.callEvent(PlayerSpawnEvent.class, spawnEvent);
|
||||||
playerCache.updateViewPosition(chunk);
|
playerCache.updateViewPosition(chunk);
|
||||||
} : null;
|
} 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);
|
||||||
|
@ -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();
|
||||||
|
@ -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());
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user