Fix Forge's packet handling on play messages. (#8875)

This commit is contained in:
Marc Hermans authored and GitHub committed 2022-07-22 12:08:29 -07:00
1 parent 18f5bdb7ca
commit d988b4a811
1 file changed
+88 -64
@@ -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})
* <p>
* 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<NetworkEvent.Context> 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<Level> world = LogicalSidedProvider.CLIENTWORLD.get(ctx.get().getDirection().getReceptionSide());
Entity e = world.map(w -> type.customClientSpawn(msg, w)).orElse(null);
if (e == null)
{
return;
}
Optional<Level> 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<NetworkEvent.Context> 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<AbstractContainerMenu, ?>)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<AbstractContainerMenu, ?>) 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;
}
}