feat: player spawning fixes

(cherry picked from commit 50b868229a)
This commit is contained in:
mworzala 2023-11-28 10:30:59 -05:00 committed by Matt Worzala
parent d4754c1f1d
commit 814f739116
7 changed files with 28 additions and 55 deletions

View File

@ -6,7 +6,6 @@ import net.minestom.server.entity.metadata.other.ExperienceOrbMeta;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.play.SpawnEntityPacket; import net.minestom.server.network.packet.server.play.SpawnEntityPacket;
import net.minestom.server.network.packet.server.play.SpawnExperienceOrbPacket; import net.minestom.server.network.packet.server.play.SpawnExperienceOrbPacket;
import net.minestom.server.network.packet.server.play.SpawnPlayerPacket;
public enum EntitySpawnType { public enum EntitySpawnType {
BASE { BASE {
@ -24,7 +23,7 @@ public enum EntitySpawnType {
PLAYER { PLAYER {
@Override @Override
public ServerPacket getSpawnPacket(Entity entity) { public ServerPacket getSpawnPacket(Entity entity) {
return new SpawnPlayerPacket(entity.getEntityId(), entity.getUuid(), entity.getPosition()); return EntitySpawnType.basicEntity(entity);
} }
}, },
EXPERIENCE_ORB { EXPERIENCE_ORB {

View File

@ -58,6 +58,7 @@ import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.ConnectionState; import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.PlayerProvider; import net.minestom.server.network.PlayerProvider;
import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.server.CachedPacket;
import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.SendablePacket;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -162,7 +163,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
private final AtomicInteger teleportId = new AtomicInteger(); private final AtomicInteger teleportId = new AtomicInteger();
private int receivedTeleportId; private int receivedTeleportId;
private final MessagePassingQueue<ClientPacket> packets = new MpscUnboundedXaddArrayQueue<>(32); private record PacketInState(ConnectionState state, ClientPacket packet) {}
private final MessagePassingQueue<PacketInState> packets = new MpscUnboundedXaddArrayQueue<>(32);
private final boolean levelFlat; private final boolean levelFlat;
private final PlayerSettings settings; private final PlayerSettings settings;
private float exp; private float exp;
@ -1982,8 +1985,8 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
* *
* @param packet the packet to add in the queue * @param packet the packet to add in the queue
*/ */
public void addPacketToQueue(@NotNull ClientPacket packet) { public void addPacketToQueue(@NotNull ConnectionState state, @NotNull ClientPacket packet) {
this.packets.offer(packet); this.packets.offer(new PacketInState(state, packet));
} }
@ApiStatus.Internal @ApiStatus.Internal
@ -1995,7 +1998,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
} }
final PacketListenerManager manager = MinecraftServer.getPacketListenerManager(); final PacketListenerManager manager = MinecraftServer.getPacketListenerManager();
// This method is NOT thread-safe // This method is NOT thread-safe
this.packets.drain(packet -> manager.processClientPacket(playerConnection.getClientState(), packet, playerConnection), ServerFlag.PACKET_PER_TICK); this.packets.drain(packet -> manager.processClientPacket(packet.state, packet.packet, playerConnection), ServerFlag.PACKET_PER_TICK);
} }
/** /**

View File

@ -206,6 +206,7 @@ public class FakePlayerController {
* @param clientPlayPacket The packet to add in the queue. * @param clientPlayPacket The packet to add in the queue.
*/ */
private void addToQueue(ClientPacket clientPlayPacket) { private void addToQueue(ClientPacket clientPlayPacket) {
this.fakePlayer.addPacketToQueue(clientPlayPacket); //todo fix me
// this.fakePlayer.addPacketToQueue(clientPlayPacket);
} }
} }

View File

@ -130,12 +130,6 @@ public final class PacketListenerManager {
// Packet is likely invalid // Packet is likely invalid
MinecraftServer.getExceptionManager().handleException(e); MinecraftServer.getExceptionManager().handleException(e);
} }
// If the packet intends to switch state, do it now.
var nextState = packet.nextState();
if (nextState != null && state != nextState) {
connection.setClientState(nextState);
}
} }
/** /**

View File

@ -292,6 +292,10 @@ public final class ConnectionManager {
// Interpret packets for configuration players // Interpret packets for configuration players
for (var player : configurationPlayers) { for (var player : configurationPlayers) {
// System.out.println("CONFIG INTERPRET: " + player.getUsername()); // System.out.println("CONFIG INTERPRET: " + player.getUsername());
//todo we are required to do this because when we wait for the config ack packet we are not in an instance so not ticking.
// but then once we switch to config the packets must be eval-ed immediately because we are in an instance. What if we change
// the protocol state swap to happen immediately when the packet is read, not when its processed?
player.interpretPacketQueue(); player.interpretPacketQueue();
} }
} }

View File

@ -53,16 +53,25 @@ public class PacketProcessor {
} }
public ClientPacket process(@NotNull PlayerConnection connection, int packetId, ByteBuffer body) { public ClientPacket process(@NotNull PlayerConnection connection, int packetId, ByteBuffer body) {
System.out.println("READ: " + connection.getClientState() + " " + packetId); // System.out.println("READ: " + connection.getClientState() + " " + packetId);
final ClientPacket packet = create(connection.getClientState(), packetId, body); final ClientPacket packet = create(connection.getClientState(), packetId, body);
final ConnectionState state = connection.getClientState(); final ConnectionState state = connection.getClientState();
System.out.println("READ2: " + state + " " + packet.getClass().getSimpleName()); // System.out.println("READ2: " + state + " " + packet.getClass().getSimpleName());
// If the packet intends to switch state, do it now.
// Since packets are processed next tick for players, we have to switch immediately.
// TODO HOWEVER THIS WILL NOT ACTUALLY WORK BECAUSE WHEN WE QUEUE THE PACKET IT HAS THE WRONG LISTENER.
var nextState = packet.nextState();
if (nextState != null && state != nextState) {
connection.setClientState(nextState);
}
switch (state) { switch (state) {
case HANDSHAKE, STATUS, LOGIN, CONFIGURATION -> packetListenerManager.processClientPacket(connection.getClientState(), packet, connection); case HANDSHAKE, STATUS, LOGIN -> packetListenerManager.processClientPacket(state, packet, connection);
case PLAY -> { case CONFIGURATION, PLAY -> {
final Player player = connection.getPlayer(); final Player player = connection.getPlayer();
assert player != null; assert player != null;
player.addPacketToQueue(packet); player.addPacketToQueue(state, packet);
} }
} }
return packet; return packet;

View File

@ -1,37 +0,0 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
import static net.minestom.server.network.NetworkBuffer.*;
public record SpawnPlayerPacket(int entityId, @NotNull UUID playerUuid,
@NotNull Pos position) implements ServerPacket {
public SpawnPlayerPacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.read(UUID),
new Pos(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE),
(reader.read(BYTE) * 360f) / 256f, (reader.read(BYTE) * 360f) / 256f));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(VAR_INT, entityId);
writer.write(UUID, playerUuid);
writer.write(DOUBLE, position.x());
writer.write(DOUBLE, position.y());
writer.write(DOUBLE, position.z());
writer.write(BYTE, (byte) (position.yaw() * 256f / 360f));
writer.write(BYTE, (byte) (position.pitch() * 256f / 360f));
}
@Override
public int getId(@NotNull ConnectionState state) {
throw new UnsupportedOperationException("SpawnPlayerPacket is not supported in " + state);
}
}