Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MinecraftForge
GitHub Repository: MinecraftForge/MinecraftForge
Path: blob/1.21.x/src/main/java/net/minecraftforge/network/packets/SpawnEntity.java
7316 views
1
/*
2
* Copyright (c) Forge Development LLC and contributors
3
* SPDX-License-Identifier: LGPL-2.1-only
4
*/
5
6
package net.minecraftforge.network.packets;
7
8
import java.util.UUID;
9
10
import org.jetbrains.annotations.ApiStatus;
11
12
import io.netty.buffer.Unpooled;
13
import net.minecraft.client.multiplayer.ClientLevel;
14
import net.minecraft.core.registries.BuiltInRegistries;
15
import net.minecraft.network.FriendlyByteBuf;
16
import net.minecraft.network.RegistryFriendlyByteBuf;
17
import net.minecraft.network.codec.StreamCodec;
18
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
19
import net.minecraft.util.Mth;
20
import net.minecraft.world.entity.Entity;
21
import net.minecraft.world.entity.EntityType;
22
import net.minecraft.world.phys.Vec3;
23
import net.minecraftforge.common.util.LogicalSidedProvider;
24
import net.minecraftforge.entity.IEntityAdditionalSpawnData;
25
import net.minecraftforge.event.network.CustomPayloadEvent;
26
27
/**
28
* Used to spawn a custom entity without the same restrictions as
29
* {@link ClientboundAddEntityPacket}
30
* <p>
31
* To customize how your entity is created clientside (instead of using the default factory provided to the
32
* {@link EntityType})
33
* see {@link EntityType.Builder#setCustomClientFactory}.
34
*/
35
// TODO: Re-write this packet into something simpler. This is literally just ClientboundAddEntityPacket with an extra byte[]
36
public class SpawnEntity {
37
public static final StreamCodec<RegistryFriendlyByteBuf, SpawnEntity> STREAM_CODEC = StreamCodec.ofMember(SpawnEntity::encode, SpawnEntity::decode);
38
private final Entity entity;
39
private final int typeId;
40
private final int entityId;
41
private final UUID uuid;
42
private final double posX, posY, posZ;
43
private final byte pitch, yaw, headYaw;
44
private final int velX, velY, velZ;
45
private final FriendlyByteBuf buf;
46
47
@ApiStatus.Internal
48
public SpawnEntity(Entity e) {
49
this.entity = e;
50
this.typeId = BuiltInRegistries.ENTITY_TYPE.getId(e.getType()); //TODO: Codecs
51
this.entityId = e.getId();
52
this.uuid = e.getUUID();
53
this.posX = e.getX();
54
this.posY = e.getY();
55
this.posZ = e.getZ();
56
this.pitch = (byte) Mth.floor(e.getXRot() * 256.0F / 360.0F);
57
this.yaw = (byte) Mth.floor(e.getYRot() * 256.0F / 360.0F);
58
this.headYaw = (byte) (e.getYHeadRot() * 256.0F / 360.0F);
59
Vec3 vec3d = e.getDeltaMovement();
60
double d1 = Mth.clamp(vec3d.x, -3.9D, 3.9D);
61
double d2 = Mth.clamp(vec3d.y, -3.9D, 3.9D);
62
double d3 = Mth.clamp(vec3d.z, -3.9D, 3.9D);
63
this.velX = (int) (d1 * 8000.0D);
64
this.velY = (int) (d2 * 8000.0D);
65
this.velZ = (int) (d3 * 8000.0D);
66
this.buf = null;
67
}
68
69
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) {
70
this.entity = null;
71
this.typeId = typeId;
72
this.entityId = entityId;
73
this.uuid = uuid;
74
this.posX = posX;
75
this.posY = posY;
76
this.posZ = posZ;
77
this.pitch = pitch;
78
this.yaw = yaw;
79
this.headYaw = headYaw;
80
this.velX = velX;
81
this.velY = velY;
82
this.velZ = velZ;
83
this.buf = buf;
84
}
85
86
public static void encode(SpawnEntity msg, FriendlyByteBuf buf) {
87
buf.writeVarInt(msg.typeId);
88
buf.writeInt(msg.entityId);
89
buf.writeLong(msg.uuid.getMostSignificantBits());
90
buf.writeLong(msg.uuid.getLeastSignificantBits());
91
buf.writeDouble(msg.posX);
92
buf.writeDouble(msg.posY);
93
buf.writeDouble(msg.posZ);
94
buf.writeByte(msg.pitch);
95
buf.writeByte(msg.yaw);
96
buf.writeByte(msg.headYaw);
97
buf.writeShort(msg.velX);
98
buf.writeShort(msg.velY);
99
buf.writeShort(msg.velZ);
100
if (msg.entity instanceof IEntityAdditionalSpawnData entityAdditionalSpawnData) {
101
final FriendlyByteBuf spawnDataBuffer = new FriendlyByteBuf(Unpooled.buffer());
102
103
entityAdditionalSpawnData.writeSpawnData(spawnDataBuffer);
104
105
buf.writeVarInt(spawnDataBuffer.readableBytes());
106
buf.writeBytes(spawnDataBuffer);
107
108
spawnDataBuffer.release();
109
} else {
110
buf.writeVarInt(0);
111
}
112
}
113
114
public static SpawnEntity decode(FriendlyByteBuf buf) {
115
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));
116
}
117
118
private static FriendlyByteBuf readSpawnDataPacket(FriendlyByteBuf buf) {
119
final int count = buf.readVarInt();
120
if (count > 0) {
121
final FriendlyByteBuf spawnDataBuffer = new FriendlyByteBuf(Unpooled.buffer());
122
spawnDataBuffer.writeBytes(buf, count);
123
return spawnDataBuffer;
124
}
125
126
return new FriendlyByteBuf(Unpooled.buffer());
127
}
128
129
public static void handle(SpawnEntity msg, CustomPayloadEvent.Context ctx) {
130
try {
131
EntityType<?> type = BuiltInRegistries.ENTITY_TYPE.byId(msg.typeId);
132
var world = LogicalSidedProvider.CLIENTWORLD.get(ctx.isClientSide());
133
Entity e = world.map(w -> type.customClientSpawn(msg, w)).orElse(null);
134
if (e == null)
135
return;
136
137
/*
138
* Sets the postiion on the client, Mirrors what
139
* Entity#recreateFromPacket and LivingEntity#recreateFromPacket does.
140
*/
141
e.syncPacketPositionCodec(msg.posX, msg.posY, msg.posZ);
142
e.absSnapTo(msg.posX, msg.posY, msg.posZ, (msg.yaw * 360) / 256.0F, (msg.pitch * 360) / 256.0F);
143
e.setYHeadRot((msg.headYaw * 360) / 256.0F);
144
e.setYBodyRot((msg.headYaw * 360) / 256.0F);
145
146
e.setId(msg.entityId);
147
e.setUUID(msg.uuid);
148
if (world.orElse(null) instanceof ClientLevel cworld)
149
cworld.addEntity(e);
150
//e.lerpMotion(msg.velX / 8000.0, msg.velY / 8000.0, msg.velZ / 8000.0);
151
if (e instanceof IEntityAdditionalSpawnData entityAdditionalSpawnData)
152
entityAdditionalSpawnData.readSpawnData(msg.buf);
153
} finally {
154
msg.buf.release();
155
}
156
}
157
158
public Entity getEntity() {
159
return entity;
160
}
161
162
public int getTypeId() {
163
return typeId;
164
}
165
166
public int getEntityId() {
167
return entityId;
168
}
169
170
public UUID getUuid() {
171
return uuid;
172
}
173
174
public double getPosX() {
175
return posX;
176
}
177
178
public double getPosY() {
179
return posY;
180
}
181
182
public double getPosZ() {
183
return posZ;
184
}
185
186
public byte getPitch() {
187
return pitch;
188
}
189
190
public byte getYaw() {
191
return yaw;
192
}
193
194
public byte getHeadYaw() {
195
return headYaw;
196
}
197
198
public int getVelX() {
199
return velX;
200
}
201
202
public int getVelY() {
203
return velY;
204
}
205
206
public int getVelZ() {
207
return velZ;
208
}
209
210
public FriendlyByteBuf getAdditionalData() {
211
return buf;
212
}
213
}
214