diff --git a/src/main/java/net/minecraftforge/network/PlayMessages.java b/src/main/java/net/minecraftforge/network/PlayMessages.java index c9fa73809d..a7a269a8d5 100644 --- a/src/main/java/net/minecraftforge/network/PlayMessages.java +++ b/src/main/java/net/minecraftforge/network/PlayMessages.java @@ -7,26 +7,24 @@ package net.minecraftforge.network; import io.netty.buffer.Unpooled; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.inventory.MenuAccess; import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.MenuAccess; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.Registry; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.Vec3; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.util.LogicalSidedProvider; -import net.minecraft.core.Registry; -import net.minecraft.network.chat.Component; import net.minecraftforge.entity.IEntityAdditionalSpawnData; -import net.minecraftforge.network.NetworkEvent; -import java.util.Locale; import java.util.Optional; import java.util.UUID; import java.util.function.Supplier; @@ -36,8 +34,9 @@ public class PlayMessages /** * Used to spawn a custom entity without the same restrictions as * {@link ClientboundAddEntityPacket} - * - * To customize how your entity is created clientside (instead of using the default factory provided to the {@link EntityType}) + *

+ * To customize how your entity is created clientside (instead of using the default factory provided to the + * {@link EntityType}) * see {@link EntityType.Builder#setCustomClientFactory}. */ public static class SpawnEntity @@ -67,14 +66,13 @@ public class PlayMessages double d1 = Mth.clamp(vec3d.x, -3.9D, 3.9D); double d2 = Mth.clamp(vec3d.y, -3.9D, 3.9D); double d3 = Mth.clamp(vec3d.z, -3.9D, 3.9D); - this.velX = (int)(d1 * 8000.0D); - this.velY = (int)(d2 * 8000.0D); - this.velZ = (int)(d3 * 8000.0D); + this.velX = (int) (d1 * 8000.0D); + this.velY = (int) (d2 * 8000.0D); + this.velZ = (int) (d3 * 8000.0D); this.buf = null; } - private SpawnEntity(int typeId, int entityId, UUID uuid, double posX, double posY, double posZ, - byte pitch, byte yaw, byte headYaw, int velX, int velY, int velZ, FriendlyByteBuf buf) + private SpawnEntity(int typeId, int entityId, UUID uuid, double posX, double posY, double posZ, byte pitch, byte yaw, byte headYaw, int velX, int velY, int velZ, FriendlyByteBuf buf) { this.entity = null; this.typeId = typeId; @@ -107,57 +105,73 @@ public class PlayMessages buf.writeShort(msg.velX); buf.writeShort(msg.velY); buf.writeShort(msg.velZ); - if (msg.entity instanceof IEntityAdditionalSpawnData) + if (msg.entity instanceof IEntityAdditionalSpawnData entityAdditionalSpawnData) { - ((IEntityAdditionalSpawnData) msg.entity).writeSpawnData(buf); + final FriendlyByteBuf spawnDataBuffer = new FriendlyByteBuf(Unpooled.buffer()); + + entityAdditionalSpawnData.writeSpawnData(spawnDataBuffer); + + buf.writeVarInt(spawnDataBuffer.readableBytes()); + buf.writeBytes(spawnDataBuffer); + + spawnDataBuffer.release(); + } else + { + buf.writeVarInt(0); } } public static SpawnEntity decode(FriendlyByteBuf buf) { - return new SpawnEntity( - buf.readVarInt(), - buf.readInt(), - new UUID(buf.readLong(), buf.readLong()), - buf.readDouble(), buf.readDouble(), buf.readDouble(), - buf.readByte(), buf.readByte(), buf.readByte(), - buf.readShort(), buf.readShort(), buf.readShort(), - buf - ); + return new SpawnEntity(buf.readVarInt(), buf.readInt(), new UUID(buf.readLong(), buf.readLong()), buf.readDouble(), buf.readDouble(), buf.readDouble(), buf.readByte(), buf.readByte(), buf.readByte(), buf.readShort(), buf.readShort(), buf.readShort(), readSpawnDataPacket(buf)); + } + + private static FriendlyByteBuf readSpawnDataPacket(FriendlyByteBuf buf) + { + final int count = buf.readVarInt(); + if (count > 0) + { + final FriendlyByteBuf spawnDataBuffer = new FriendlyByteBuf(Unpooled.buffer()); + spawnDataBuffer.writeBytes(buf, count); + return spawnDataBuffer; + } + + return new FriendlyByteBuf(Unpooled.buffer()); } public static void handle(SpawnEntity msg, Supplier ctx) { ctx.get().enqueueWork(() -> { - EntityType type = Registry.ENTITY_TYPE.byId(msg.typeId); - if (type == null) + try { - throw new RuntimeException(String.format(Locale.ENGLISH, "Could not spawn entity (id %d) with unknown type at (%f, %f, %f)", msg.entityId, msg.posX, msg.posY, msg.posZ)); - } + EntityType type = Registry.ENTITY_TYPE.byId(msg.typeId); + Optional world = LogicalSidedProvider.CLIENTWORLD.get(ctx.get().getDirection().getReceptionSide()); + Entity e = world.map(w -> type.customClientSpawn(msg, w)).orElse(null); + if (e == null) + { + return; + } - Optional world = LogicalSidedProvider.CLIENTWORLD.get(ctx.get().getDirection().getReceptionSide()); - Entity e = world.map(w->type.customClientSpawn(msg, w)).orElse(null); - if (e == null) + /* + * Sets the postiion on the client, Mirrors what + * Entity#recreateFromPacket and LivingEntity#recreateFromPacket does. + */ + e.syncPacketPositionCodec(msg.posX, msg.posY, msg.posZ); + e.absMoveTo(msg.posX, msg.posY, msg.posZ, (msg.yaw * 360) / 256.0F, (msg.pitch * 360) / 256.0F); + e.setYHeadRot((msg.headYaw * 360) / 256.0F); + e.setYBodyRot((msg.headYaw * 360) / 256.0F); + + e.setId(msg.entityId); + e.setUUID(msg.uuid); + world.filter(ClientLevel.class::isInstance).ifPresent(w -> ((ClientLevel) w).putNonPlayerEntity(msg.entityId, e)); + e.lerpMotion(msg.velX / 8000.0, msg.velY / 8000.0, msg.velZ / 8000.0); + if (e instanceof IEntityAdditionalSpawnData entityAdditionalSpawnData) + { + entityAdditionalSpawnData.readSpawnData(msg.buf); + } + } finally { - return; - } - - /* - * Sets the postiion on the client, Mirrors what - * Entity#recreateFromPacket and LivingEntity#recreateFromPacket does. - */ - e.syncPacketPositionCodec(msg.posX, msg.posY, msg.posZ); - e.absMoveTo(msg.posX, msg.posY, msg.posZ, (msg.yaw * 360) / 256.0F, (msg.pitch * 360) / 256.0F); - e.setYHeadRot((msg.headYaw * 360) / 256.0F); - e.setYBodyRot((msg.headYaw * 360) / 256.0F); - - e.setId(msg.entityId); - e.setUUID(msg.uuid); - world.filter(ClientLevel.class::isInstance).ifPresent(w->((ClientLevel)w).putNonPlayerEntity(msg.entityId, e)); - e.lerpMotion(msg.velX / 8000.0, msg.velY / 8000.0, msg.velZ / 8000.0); - if (e instanceof IEntityAdditionalSpawnData) - { - ((IEntityAdditionalSpawnData) e).readSpawnData(msg.buf); + msg.buf.release(); } }); ctx.get().setPacketHandled(true); @@ -270,31 +284,41 @@ public class PlayMessages public static void handle(OpenContainer msg, Supplier ctx) { ctx.get().enqueueWork(() -> { - MenuScreens.getScreenFactory(msg.getType(), Minecraft.getInstance(), msg.getWindowId(), msg.getName()) - .ifPresent(f -> { - AbstractContainerMenu c = msg.getType().create(msg.getWindowId(), Minecraft.getInstance().player.getInventory(), msg.getAdditionalData()); - @SuppressWarnings("unchecked") - Screen s = ((MenuScreens.ScreenConstructor)f).create(c, Minecraft.getInstance().player.getInventory(), msg.getName()); - Minecraft.getInstance().player.containerMenu = ((MenuAccess)s).getMenu(); - Minecraft.getInstance().setScreen(s); - }); + try + { + MenuScreens.getScreenFactory(msg.getType(), Minecraft.getInstance(), msg.getWindowId(), msg.getName()).ifPresent(f -> { + AbstractContainerMenu c = msg.getType().create(msg.getWindowId(), Minecraft.getInstance().player.getInventory(), msg.getAdditionalData()); + + @SuppressWarnings("unchecked") Screen s = ((MenuScreens.ScreenConstructor) f).create(c, Minecraft.getInstance().player.getInventory(), msg.getName()); + Minecraft.getInstance().player.containerMenu = ((MenuAccess) s).getMenu(); + Minecraft.getInstance().setScreen(s); + }); + } finally + { + msg.getAdditionalData().release(); + } + }); ctx.get().setPacketHandled(true); } - public final MenuType getType() { + public final MenuType getType() + { return Registry.MENU.byId(this.id); } - public int getWindowId() { + public int getWindowId() + { return windowId; } - public Component getName() { + public Component getName() + { return name; } - public FriendlyByteBuf getAdditionalData() { + public FriendlyByteBuf getAdditionalData() + { return additionalData; } }