Path: blob/1.21.x/src/main/java/net/minecraftforge/network/packets/SpawnEntity.java
7316 views
/*1* Copyright (c) Forge Development LLC and contributors2* SPDX-License-Identifier: LGPL-2.1-only3*/45package net.minecraftforge.network.packets;67import java.util.UUID;89import org.jetbrains.annotations.ApiStatus;1011import io.netty.buffer.Unpooled;12import net.minecraft.client.multiplayer.ClientLevel;13import net.minecraft.core.registries.BuiltInRegistries;14import net.minecraft.network.FriendlyByteBuf;15import net.minecraft.network.RegistryFriendlyByteBuf;16import net.minecraft.network.codec.StreamCodec;17import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;18import net.minecraft.util.Mth;19import net.minecraft.world.entity.Entity;20import net.minecraft.world.entity.EntityType;21import net.minecraft.world.phys.Vec3;22import net.minecraftforge.common.util.LogicalSidedProvider;23import net.minecraftforge.entity.IEntityAdditionalSpawnData;24import net.minecraftforge.event.network.CustomPayloadEvent;2526/**27* Used to spawn a custom entity without the same restrictions as28* {@link ClientboundAddEntityPacket}29* <p>30* To customize how your entity is created clientside (instead of using the default factory provided to the31* {@link EntityType})32* see {@link EntityType.Builder#setCustomClientFactory}.33*/34// TODO: Re-write this packet into something simpler. This is literally just ClientboundAddEntityPacket with an extra byte[]35public class SpawnEntity {36public static final StreamCodec<RegistryFriendlyByteBuf, SpawnEntity> STREAM_CODEC = StreamCodec.ofMember(SpawnEntity::encode, SpawnEntity::decode);37private final Entity entity;38private final int typeId;39private final int entityId;40private final UUID uuid;41private final double posX, posY, posZ;42private final byte pitch, yaw, headYaw;43private final int velX, velY, velZ;44private final FriendlyByteBuf buf;4546@ApiStatus.Internal47public SpawnEntity(Entity e) {48this.entity = e;49this.typeId = BuiltInRegistries.ENTITY_TYPE.getId(e.getType()); //TODO: Codecs50this.entityId = e.getId();51this.uuid = e.getUUID();52this.posX = e.getX();53this.posY = e.getY();54this.posZ = e.getZ();55this.pitch = (byte) Mth.floor(e.getXRot() * 256.0F / 360.0F);56this.yaw = (byte) Mth.floor(e.getYRot() * 256.0F / 360.0F);57this.headYaw = (byte) (e.getYHeadRot() * 256.0F / 360.0F);58Vec3 vec3d = e.getDeltaMovement();59double d1 = Mth.clamp(vec3d.x, -3.9D, 3.9D);60double d2 = Mth.clamp(vec3d.y, -3.9D, 3.9D);61double d3 = Mth.clamp(vec3d.z, -3.9D, 3.9D);62this.velX = (int) (d1 * 8000.0D);63this.velY = (int) (d2 * 8000.0D);64this.velZ = (int) (d3 * 8000.0D);65this.buf = null;66}6768private 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) {69this.entity = null;70this.typeId = typeId;71this.entityId = entityId;72this.uuid = uuid;73this.posX = posX;74this.posY = posY;75this.posZ = posZ;76this.pitch = pitch;77this.yaw = yaw;78this.headYaw = headYaw;79this.velX = velX;80this.velY = velY;81this.velZ = velZ;82this.buf = buf;83}8485public static void encode(SpawnEntity msg, FriendlyByteBuf buf) {86buf.writeVarInt(msg.typeId);87buf.writeInt(msg.entityId);88buf.writeLong(msg.uuid.getMostSignificantBits());89buf.writeLong(msg.uuid.getLeastSignificantBits());90buf.writeDouble(msg.posX);91buf.writeDouble(msg.posY);92buf.writeDouble(msg.posZ);93buf.writeByte(msg.pitch);94buf.writeByte(msg.yaw);95buf.writeByte(msg.headYaw);96buf.writeShort(msg.velX);97buf.writeShort(msg.velY);98buf.writeShort(msg.velZ);99if (msg.entity instanceof IEntityAdditionalSpawnData entityAdditionalSpawnData) {100final FriendlyByteBuf spawnDataBuffer = new FriendlyByteBuf(Unpooled.buffer());101102entityAdditionalSpawnData.writeSpawnData(spawnDataBuffer);103104buf.writeVarInt(spawnDataBuffer.readableBytes());105buf.writeBytes(spawnDataBuffer);106107spawnDataBuffer.release();108} else {109buf.writeVarInt(0);110}111}112113public static SpawnEntity decode(FriendlyByteBuf buf) {114return 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));115}116117private static FriendlyByteBuf readSpawnDataPacket(FriendlyByteBuf buf) {118final int count = buf.readVarInt();119if (count > 0) {120final FriendlyByteBuf spawnDataBuffer = new FriendlyByteBuf(Unpooled.buffer());121spawnDataBuffer.writeBytes(buf, count);122return spawnDataBuffer;123}124125return new FriendlyByteBuf(Unpooled.buffer());126}127128public static void handle(SpawnEntity msg, CustomPayloadEvent.Context ctx) {129try {130EntityType<?> type = BuiltInRegistries.ENTITY_TYPE.byId(msg.typeId);131var world = LogicalSidedProvider.CLIENTWORLD.get(ctx.isClientSide());132Entity e = world.map(w -> type.customClientSpawn(msg, w)).orElse(null);133if (e == null)134return;135136/*137* Sets the postiion on the client, Mirrors what138* Entity#recreateFromPacket and LivingEntity#recreateFromPacket does.139*/140e.syncPacketPositionCodec(msg.posX, msg.posY, msg.posZ);141e.absSnapTo(msg.posX, msg.posY, msg.posZ, (msg.yaw * 360) / 256.0F, (msg.pitch * 360) / 256.0F);142e.setYHeadRot((msg.headYaw * 360) / 256.0F);143e.setYBodyRot((msg.headYaw * 360) / 256.0F);144145e.setId(msg.entityId);146e.setUUID(msg.uuid);147if (world.orElse(null) instanceof ClientLevel cworld)148cworld.addEntity(e);149//e.lerpMotion(msg.velX / 8000.0, msg.velY / 8000.0, msg.velZ / 8000.0);150if (e instanceof IEntityAdditionalSpawnData entityAdditionalSpawnData)151entityAdditionalSpawnData.readSpawnData(msg.buf);152} finally {153msg.buf.release();154}155}156157public Entity getEntity() {158return entity;159}160161public int getTypeId() {162return typeId;163}164165public int getEntityId() {166return entityId;167}168169public UUID getUuid() {170return uuid;171}172173public double getPosX() {174return posX;175}176177public double getPosY() {178return posY;179}180181public double getPosZ() {182return posZ;183}184185public byte getPitch() {186return pitch;187}188189public byte getYaw() {190return yaw;191}192193public byte getHeadYaw() {194return headYaw;195}196197public int getVelX() {198return velX;199}200201public int getVelY() {202return velY;203}204205public int getVelZ() {206return velZ;207}208209public FriendlyByteBuf getAdditionalData() {210return buf;211}212}213214