diff --git a/patches/minecraft/net/minecraft/world/entity/Entity.java.patch b/patches/minecraft/net/minecraft/world/entity/Entity.java.patch index d4bf822e4d..aa22dcf613 100644 --- a/patches/minecraft/net/minecraft/world/entity/Entity.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/Entity.java.patch @@ -505,6 +505,16 @@ return this.fluidHeight.getDouble(p_204037_); } +@@ -3106,7 +_,9 @@ + return this.getBbHeight() + 0.5F; + } + ++ private boolean hasExtraSpawnData = this instanceof net.minecraftforge.entity.IEntityAdditionalSpawnData; + public Packet getAddEntityPacket() { ++ if (hasExtraSpawnData) return net.minecraftforge.common.ForgeHooks.getEntitySpawnPacket(this); + return new ClientboundAddEntityPacket(this); + } + @@ -3222,6 +_,7 @@ this.levelCallback.onMove(); diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index e8ea1ce802..609be77415 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -30,6 +30,7 @@ import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Lifecycle; +import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; @@ -42,6 +43,7 @@ import net.minecraft.core.HolderSet; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.Registries; import net.minecraft.network.Connection; +import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; @@ -96,6 +98,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.network.protocol.Packet; import net.minecraft.network.syncher.EntityDataSerializer; +import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; import net.minecraft.world.item.alchemy.Potion; @@ -116,6 +119,7 @@ import net.minecraftforge.common.util.BrainBuilder; import net.minecraftforge.common.util.Lazy; import net.minecraftforge.common.util.MavenVersionStringHelper; import net.minecraftforge.common.util.MutableHashedLinkedMap; +import net.minecraftforge.entity.IEntityAdditionalSpawnData; import net.minecraftforge.event.AnvilUpdateEvent; import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; import net.minecraftforge.event.DifficultyChangeEvent; @@ -166,7 +170,10 @@ import net.minecraftforge.fml.util.thread.EffectiveSide; import net.minecraftforge.network.ConnectionType; import net.minecraftforge.network.ICustomPacket; import net.minecraftforge.network.NetworkContext; +import net.minecraftforge.network.NetworkDirection; +import net.minecraftforge.network.NetworkInitialization; import net.minecraftforge.network.NetworkRegistry; +import net.minecraftforge.network.packets.SpawnEntity; import net.minecraftforge.resource.ResourcePackLoader; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistry; @@ -1251,4 +1258,16 @@ public class ForgeHooks { LOGGER.info("Connected to a modded server."); } + @ApiStatus.Internal + public static Packet getEntitySpawnPacket(Entity entity) { + if (!(entity instanceof IEntityAdditionalSpawnData add)) + throw new IllegalArgumentException(entity.getClass() + " is not an instance of " + IEntityAdditionalSpawnData.class); + + var play = NetworkInitialization.PLAY; + var msg = new SpawnEntity(entity); + var data = play.toBuffer(msg); + @SuppressWarnings("unchecked") + var pkt = (Packet)NetworkDirection.PLAY_TO_CLIENT.buildPacket(data, play.getName()).getThis(); + return pkt; + } } \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/network/Channel.java b/src/main/java/net/minecraftforge/network/Channel.java index 5865d136f9..5752e54636 100644 --- a/src/main/java/net/minecraftforge/network/Channel.java +++ b/src/main/java/net/minecraftforge/network/Channel.java @@ -38,7 +38,7 @@ public abstract class Channel { return NetworkContext.get(connection).getRemoteChannels().contains(getName()); } - protected abstract FriendlyByteBuf toBuffer(MSG message); + public abstract FriendlyByteBuf toBuffer(MSG message); // Package private so we can call from ourselves. Packet toVanillaPacket(Connection connection, MSG message) { diff --git a/src/main/java/net/minecraftforge/network/EventNetworkChannel.java b/src/main/java/net/minecraftforge/network/EventNetworkChannel.java index e9bdcd9bec..20f3a5d4f6 100644 --- a/src/main/java/net/minecraftforge/network/EventNetworkChannel.java +++ b/src/main/java/net/minecraftforge/network/EventNetworkChannel.java @@ -42,7 +42,7 @@ public class EventNetworkChannel extends Channel { } @Override - protected FriendlyByteBuf toBuffer(FriendlyByteBuf message) { + public FriendlyByteBuf toBuffer(FriendlyByteBuf message) { return message; } } diff --git a/src/main/java/net/minecraftforge/network/NetworkInitialization.java b/src/main/java/net/minecraftforge/network/NetworkInitialization.java index 6370890c8c..a71c7cdcda 100644 --- a/src/main/java/net/minecraftforge/network/NetworkInitialization.java +++ b/src/main/java/net/minecraftforge/network/NetworkInitialization.java @@ -94,16 +94,16 @@ public class NetworkInitialization { .consumerNetworkThread(CONTEXT, ForgePacketHandler::handleModMismatchData) .add() - .messageBuilder(SpawnEntity.class) + .messageBuilder(SpawnEntity.class, NetworkDirection.PLAY_TO_CLIENT) .decoder(SpawnEntity::decode) .encoder(SpawnEntity::encode) - .consumerNetworkThread(SpawnEntity::handle) + .consumerMainThread(SpawnEntity::handle) .add() .messageBuilder(OpenContainer.class) .decoder(OpenContainer::decode) .encoder(OpenContainer::encode) - .consumerNetworkThread(OpenContainer::handle) + .consumerMainThread(OpenContainer::handle) .add(); public static void init() { diff --git a/src/main/java/net/minecraftforge/network/SimpleChannel.java b/src/main/java/net/minecraftforge/network/SimpleChannel.java index e08602d8b7..fa86891a67 100644 --- a/src/main/java/net/minecraftforge/network/SimpleChannel.java +++ b/src/main/java/net/minecraftforge/network/SimpleChannel.java @@ -334,7 +334,7 @@ public class SimpleChannel extends Channel { @SuppressWarnings("unchecked") @Override - protected FriendlyByteBuf toBuffer(Object message) { + public FriendlyByteBuf toBuffer(Object message) { var msg = byType.get(message.getClass()); if (msg == null) { diff --git a/src/main/java/net/minecraftforge/network/packets/OpenContainer.java b/src/main/java/net/minecraftforge/network/packets/OpenContainer.java index 4ba98547ae..be430e2695 100644 --- a/src/main/java/net/minecraftforge/network/packets/OpenContainer.java +++ b/src/main/java/net/minecraftforge/network/packets/OpenContainer.java @@ -10,8 +10,6 @@ import org.jetbrains.annotations.ApiStatus; import io.netty.buffer.Unpooled; import net.minecraft.client.Minecraft; 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.core.registries.BuiltInRegistries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; @@ -55,23 +53,20 @@ public class OpenContainer { @SuppressWarnings("unchecked") public static void handle(OpenContainer msg, CustomPayloadEvent.Context ctx) { - ctx.enqueueWork(() -> { - try { - var mc = Minecraft.getInstance(); - var inv = mc.player.getInventory(); - MenuScreens.getScreenFactory(msg.getType(), mc, msg.getWindowId(), msg.getName()).ifPresent(f -> { - AbstractContainerMenu c = msg.getType().create(msg.getWindowId(), inv, msg.getAdditionalData()); + try { + var mc = Minecraft.getInstance(); + var inv = mc.player.getInventory(); + var factory = MenuScreens.getScreenFactory(msg.getType(), mc, msg.getWindowId(), msg.getName()); + factory.ifPresent(f -> { + var c = msg.getType().create(msg.getWindowId(), inv, msg.getAdditionalData()); - Screen s = ((MenuScreens.ScreenConstructor)f).create(c, inv, msg.getName()); - mc.player.containerMenu = ((MenuAccess)s).getMenu(); - mc.setScreen(s); - }); - } finally { - msg.getAdditionalData().release(); - } - - }); - ctx.setPacketHandled(true); + var s = ((MenuScreens.ScreenConstructor)f).create(c, inv, msg.getName()); + mc.player.containerMenu = s.getMenu(); + mc.setScreen(s); + }); + } finally { + msg.getAdditionalData().release(); + } } @SuppressWarnings("deprecation") diff --git a/src/main/java/net/minecraftforge/network/packets/SpawnEntity.java b/src/main/java/net/minecraftforge/network/packets/SpawnEntity.java index c6e13514f5..5a56501ce9 100644 --- a/src/main/java/net/minecraftforge/network/packets/SpawnEntity.java +++ b/src/main/java/net/minecraftforge/network/packets/SpawnEntity.java @@ -8,6 +8,8 @@ package net.minecraftforge.network.packets; import java.util.Optional; import java.util.UUID; +import org.jetbrains.annotations.ApiStatus; + import io.netty.buffer.Unpooled; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.registries.BuiltInRegistries; @@ -30,6 +32,7 @@ import net.minecraftforge.event.network.CustomPayloadEvent; * {@link EntityType}) * see {@link EntityType.Builder#setCustomClientFactory}. */ +// TODO: Re-write this packet into something simpler. This is literally just ClientboundAddEntityPacket with an extra byte[] public class SpawnEntity { private final Entity entity; private final int typeId; @@ -41,7 +44,8 @@ public class SpawnEntity { private final FriendlyByteBuf buf; @SuppressWarnings("deprecation") - SpawnEntity(Entity e) { + @ApiStatus.Internal + public SpawnEntity(Entity e) { this.entity = e; this.typeId = BuiltInRegistries.ENTITY_TYPE.getId(e.getType()); //TODO: Codecs this.entityId = e.getId(); @@ -123,36 +127,33 @@ public class SpawnEntity { } public static void handle(SpawnEntity msg, CustomPayloadEvent.Context ctx) { - ctx.enqueueWork(() -> { - try { - @SuppressWarnings("deprecation") - EntityType type = BuiltInRegistries.ENTITY_TYPE.byId(msg.typeId); - Optional world = LogicalSidedProvider.CLIENTWORLD.get(ctx.getDirection().getReceptionSide()); - Entity e = world.map(w -> type.customClientSpawn(msg, w)).orElse(null); - if (e == null) - return; + try { + @SuppressWarnings("deprecation") + EntityType type = BuiltInRegistries.ENTITY_TYPE.byId(msg.typeId); + Optional world = LogicalSidedProvider.CLIENTWORLD.get(ctx.getDirection().getReceptionSide()); + Entity e = world.map(w -> type.customClientSpawn(msg, w)).orElse(null); + if (e == null) + 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); + /* + * 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); - if (world.orElse(null) instanceof ClientLevel cworld) - cworld.addEntity(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 { - msg.buf.release(); - } - }); - ctx.setPacketHandled(true); + e.setId(msg.entityId); + e.setUUID(msg.uuid); + if (world.orElse(null) instanceof ClientLevel cworld) + cworld.addEntity(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 { + msg.buf.release(); + } } public Entity getEntity() {