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.play.SpawnEntityPacket;
import net.minestom.server.network.packet.server.play.SpawnExperienceOrbPacket;
import net.minestom.server.network.packet.server.play.SpawnPlayerPacket;
public enum EntitySpawnType {
BASE {
@ -24,7 +23,7 @@ public enum EntitySpawnType {
PLAYER {
@Override
public ServerPacket getSpawnPacket(Entity entity) {
return new SpawnPlayerPacket(entity.getEntityId(), entity.getUuid(), entity.getPosition());
return EntitySpawnType.basicEntity(entity);
}
},
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.PlayerProvider;
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.ServerPacket;
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 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 PlayerSettings settings;
private float exp;
@ -1982,8 +1985,8 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
*
* @param packet the packet to add in the queue
*/
public void addPacketToQueue(@NotNull ClientPacket packet) {
this.packets.offer(packet);
public void addPacketToQueue(@NotNull ConnectionState state, @NotNull ClientPacket packet) {
this.packets.offer(new PacketInState(state, packet));
}
@ApiStatus.Internal
@ -1995,7 +1998,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
}
final PacketListenerManager manager = MinecraftServer.getPacketListenerManager();
// 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.
*/
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
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
for (var player : configurationPlayers) {
// 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();
}
}

View File

@ -53,16 +53,25 @@ public class PacketProcessor {
}
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 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) {
case HANDSHAKE, STATUS, LOGIN, CONFIGURATION -> packetListenerManager.processClientPacket(connection.getClientState(), packet, connection);
case PLAY -> {
case HANDSHAKE, STATUS, LOGIN -> packetListenerManager.processClientPacket(state, packet, connection);
case CONFIGURATION, PLAY -> {
final Player player = connection.getPlayer();
assert player != null;
player.addPacketToQueue(packet);
player.addPacketToQueue(state, 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);
}
}