1919
2020import com .viaversion .viabackwards .api .rewriters .EntityRewriter ;
2121import com .viaversion .viabackwards .protocol .v26_3to26_2 .Protocol26_3To26_2 ;
22+ import com .viaversion .viabackwards .protocol .v26_3to26_2 .storage .CushionData ;
2223import com .viaversion .viabackwards .protocol .v26_3to26_2 .storage .ProtocolStorables26_3 ;
24+ import com .viaversion .viaversion .api .connection .UserConnection ;
25+ import com .viaversion .viaversion .api .minecraft .Vector3d ;
2326import com .viaversion .viaversion .api .minecraft .entities .EntityType ;
2427import com .viaversion .viaversion .api .minecraft .entities .EntityTypes26_3 ;
2528import com .viaversion .viaversion .api .data .entity .TrackedEntity ;
3437import com .viaversion .viaversion .protocols .v26_2to26_3 .packet .ClientboundPacket26_3 ;
3538import com .viaversion .viaversion .protocols .v26_2to26_3 .packet .ClientboundPackets26_3 ;
3639import com .viaversion .viaversion .protocols .v26_2to26_3 .packet .ServerboundPackets26_3 ;
40+ import com .viaversion .viaversion .rewriter .entitydata .EntityDataHandlerEvent ;
41+ import com .viaversion .viaversion .util .Copyable ;
3742import java .util .ArrayList ;
3843import java .util .List ;
44+ import java .util .UUID ;
45+ import org .checkerframework .checker .nullness .qual .Nullable ;
3946
4047public final class EntityPacketRewriter26_3 extends EntityRewriter <ClientboundPacket26_3 , Protocol26_3To26_2 > {
4148
4249 private static final EntityDataTypes26_1 MAPPED_DATA_TYPES = VersionedTypes .V26_2 .entityDataTypes ;
4350 private static final int NO_SWING_ANIMATION = 0 ;
4451 private static final int CHANGE_DESTROY_DIRECTION_ACTION = 1 ;
4552 private static final int WHITE_CARPET_BLOCK_STATE = 12896 ;
53+ private static final int RELATIVE_X = 1 ;
54+ private static final int RELATIVE_Y = 1 << 1 ;
55+ private static final int RELATIVE_Z = 1 << 2 ;
4656
4757 public EntityPacketRewriter26_3 (final Protocol26_3To26_2 protocol ) {
4858 super (protocol , MAPPED_DATA_TYPES .optionalComponentType , MAPPED_DATA_TYPES .booleanType );
@@ -51,20 +61,22 @@ public EntityPacketRewriter26_3(final Protocol26_3To26_2 protocol) {
5161 @ Override
5262 public void registerPackets () {
5363 protocol .registerClientbound (ClientboundPackets26_3 .MOVE_ENTITY_POS , wrapper -> {
54- wrapper .passthrough (Types .VAR_INT ); // Entity ID
64+ final int entityId = wrapper .passthrough (Types .VAR_INT );
5565
5666 final int properties = wrapper .read (Types .VAR_INT );
5767 final boolean onGround = (properties & 1 ) != 0 ;
5868 handleMovePos (wrapper , properties );
69+ trackCushionMovement (wrapper , entityId );
5970 wrapper .write (Types .BOOLEAN , onGround );
6071 });
6172
6273 protocol .registerClientbound (ClientboundPackets26_3 .MOVE_ENTITY_POS_ROT , wrapper -> {
63- wrapper .passthrough (Types .VAR_INT ); // Entity ID
74+ final int entityId = wrapper .passthrough (Types .VAR_INT );
6475
6576 final int properties = wrapper .read (Types .VAR_INT );
6677 final boolean onGround = (properties & 1 ) != 0 ;
6778 handleMovePos (wrapper , properties );
79+ trackCushionMovement (wrapper , entityId );
6880
6981 wrapper .passthrough (Types .BYTE ); // Y rot
7082 wrapper .passthrough (Types .BYTE ); // X rot
@@ -81,16 +93,17 @@ public void registerPackets() {
8193 });
8294
8395 protocol .registerClientbound (ClientboundPackets26_3 .ENTITY_POSITION_SYNC , wrapper -> {
84- wrapper .passthrough (Types .VAR_INT ); // Entity ID
96+ final int entityId = wrapper .passthrough (Types .VAR_INT );
8597
8698 final int pathType = wrapper .read (Types .VAR_INT );
8799 if (pathType == 0 ) { // Linear
88- wrapper .passthrough (Types .DOUBLE ); // X
89- wrapper .passthrough (Types .DOUBLE ); // Y
90- wrapper .passthrough (Types .DOUBLE ); // Z
100+ final double x = wrapper .passthrough (Types .DOUBLE );
101+ final double y = wrapper .passthrough (Types .DOUBLE );
102+ final double z = wrapper .passthrough (Types .DOUBLE );
91103 wrapper .write (Types .DOUBLE , 0D ); // Delta x
92104 wrapper .write (Types .DOUBLE , 0D ); // Delta y
93105 wrapper .write (Types .DOUBLE , 0D ); // Delta z
106+ trackCushionPosition (wrapper , entityId , x , y , z );
94107 return ;
95108 }
96109
@@ -116,6 +129,7 @@ public void registerPackets() {
116129 wrapper .write (Types .DOUBLE , x );
117130 wrapper .write (Types .DOUBLE , y );
118131 wrapper .write (Types .DOUBLE , z );
132+ trackCushionPosition (wrapper , entityId , x , y , z );
119133 if (steps > 1 && tickOffset > 0 ) {
120134 wrapper .write (Types .DOUBLE , (x - previousX ) / tickOffset ); // Delta x
121135 wrapper .write (Types .DOUBLE , (y - previousY ) / tickOffset ); // Delta y
@@ -127,6 +141,28 @@ public void registerPackets() {
127141 }
128142 });
129143
144+ protocol .registerClientbound (ClientboundPackets26_3 .TELEPORT_ENTITY , wrapper -> {
145+ final int entityId = wrapper .passthrough (Types .VAR_INT );
146+ final CushionData cushionData = cushionData (wrapper , entityId );
147+ if (cushionData == null ) {
148+ return ;
149+ }
150+
151+ final double x = wrapper .passthrough (Types .DOUBLE );
152+ final double y = wrapper .passthrough (Types .DOUBLE );
153+ final double z = wrapper .passthrough (Types .DOUBLE );
154+ wrapper .passthrough (Types .DOUBLE ); // Delta x
155+ wrapper .passthrough (Types .DOUBLE ); // Delta y
156+ wrapper .passthrough (Types .DOUBLE ); // Delta z
157+ wrapper .passthrough (Types .FLOAT ); // Y rot
158+ wrapper .passthrough (Types .FLOAT ); // X rot
159+ final int relatives = wrapper .passthrough (Types .INT );
160+ final double newX = (relatives & RELATIVE_X ) != 0 ? cushionData .x () + x : x ;
161+ final double newY = (relatives & RELATIVE_Y ) != 0 ? cushionData .y () + y : y ;
162+ final double newZ = (relatives & RELATIVE_Z ) != 0 ? cushionData .z () + z : z ;
163+ cushionData .setPosition (newX , newY , newZ );
164+ });
165+
130166 protocol .appendClientbound (ClientboundPackets26_3 .LOGIN , wrapper -> {
131167 wrapper .rewindReader (1 );
132168 handleGamemodes (wrapper );
@@ -204,13 +240,19 @@ public void registerPackets() {
204240 return ;
205241 }
206242
207- // Set falling block data to white carpet block state
243+ // Set falling block data to white carpet block state, the actual color follows in the entity data
208244 wrapper .set (Types .VAR_INT , 2 , WHITE_CARPET_BLOCK_STATE );
245+ final UUID uuid = wrapper .get (Types .UUID , 0 );
246+ final double x = wrapper .get (Types .DOUBLE , 0 );
247+ final double y = wrapper .get (Types .DOUBLE , 1 );
248+ final double z = wrapper .get (Types .DOUBLE , 2 );
249+ final CushionData cushionData = new CushionData (uuid , x , y , z );
250+ cushionData .entityData ().add (new EntityData (5 , MAPPED_DATA_TYPES .booleanType , true )); // No gravity
251+ entity .put (cushionData );
209252
210253 wrapper .send (Protocol26_3To26_2 .class );
211254 wrapper .cancel ();
212255
213- // Send no gravity entity data
214256 final List <EntityData > entityDataList = new ArrayList <>();
215257 entityDataList .add (new EntityData (5 , MAPPED_DATA_TYPES .booleanType , true )); // No gravity
216258
@@ -221,6 +263,91 @@ public void registerPackets() {
221263 });
222264 }
223265
266+ private void updateCushionColor (final EntityDataHandlerEvent event , final int color ) {
267+ final CushionData cushionData = event .trackedEntity ().get (CushionData .class );
268+ if (cushionData == null || cushionData .color () == color ) {
269+ return ;
270+ }
271+
272+ cushionData .setColor (color );
273+
274+ final ProtocolStorables26_3 storables = event .user ().storables (protocol );
275+ final boolean isBundling = storables .bundleStateTracker ().isBundling ();
276+ if (!isBundling ) {
277+ final PacketWrapper bundleStart = PacketWrapper .create (ClientboundPackets26_1 .BUNDLE_DELIMITER , event .user ());
278+ bundleStart .send (Protocol26_3To26_2 .class );
279+ }
280+
281+ // Falling blocks can't change their block state after spawning, so respawn it with the colored carpet
282+ final PacketWrapper removeEntityPacket = PacketWrapper .create (ClientboundPackets26_1 .REMOVE_ENTITIES , event .user ());
283+ removeEntityPacket .write (Types .VAR_INT_ARRAY_PRIMITIVE , new int []{event .entityId ()});
284+ removeEntityPacket .send (Protocol26_3To26_2 .class );
285+
286+ final PacketWrapper addEntityPacket = PacketWrapper .create (ClientboundPackets26_1 .ADD_ENTITY , event .user ());
287+ addEntityPacket .write (Types .VAR_INT , event .entityId ());
288+ addEntityPacket .write (Types .UUID , cushionData .uuid ());
289+ addEntityPacket .write (Types .VAR_INT , newEntityId (fallingBlockType ().getId ()));
290+ addEntityPacket .write (Types .DOUBLE , cushionData .x ());
291+ addEntityPacket .write (Types .DOUBLE , cushionData .y ());
292+ addEntityPacket .write (Types .DOUBLE , cushionData .z ());
293+ addEntityPacket .write (Types .LOW_PRECISION_VECTOR , Vector3d .ZERO ); // Movement
294+ addEntityPacket .write (Types .BYTE , (byte ) 0 ); // X rot, unused by falling blocks
295+ addEntityPacket .write (Types .BYTE , (byte ) 0 ); // Y rot
296+ addEntityPacket .write (Types .BYTE , (byte ) 0 ); // Y head rot
297+ addEntityPacket .write (Types .VAR_INT , WHITE_CARPET_BLOCK_STATE + color );
298+ addEntityPacket .send (Protocol26_3To26_2 .class );
299+
300+ final PacketWrapper entityDataPacket = PacketWrapper .create (ClientboundPackets26_1 .SET_ENTITY_DATA , event .user ());
301+ entityDataPacket .write (Types .VAR_INT , event .entityId ());
302+ entityDataPacket .write (VersionedTypes .V26_2 .entityDataList , cushionData .entityData ());
303+ entityDataPacket .send (Protocol26_3To26_2 .class );
304+
305+ if (!isBundling ) {
306+ final PacketWrapper bundleEnd = PacketWrapper .create (ClientboundPackets26_1 .BUNDLE_DELIMITER , event .user ());
307+ bundleEnd .send (Protocol26_3To26_2 .class );
308+ }
309+ }
310+
311+ @ Override
312+ public void handleEntityData (final int entityId , final List <EntityData > dataList , final UserConnection connection ) {
313+ super .handleEntityData (entityId , dataList , connection );
314+
315+ final TrackedEntity entity = tracker (connection ).entity (entityId );
316+ final CushionData cushionData = entity != null ? entity .get (CushionData .class ) : null ;
317+ if (cushionData == null ) {
318+ return ;
319+ }
320+
321+ final List <EntityData > entityData = cushionData .entityData ();
322+ entityData .removeIf (first -> dataList .stream ().anyMatch (second -> first .id () == second .id ()));
323+ for (final EntityData data : dataList ) {
324+ final Object value = data .value ();
325+ entityData .add (new EntityData (data .id (), data .dataType (), Copyable .copy (value )));
326+ }
327+ }
328+
329+ private @ Nullable CushionData cushionData (final PacketWrapper wrapper , final int entityId ) {
330+ final TrackedEntity entity = tracker (wrapper .user ()).entity (entityId );
331+ return entity != null ? entity .get (CushionData .class ) : null ;
332+ }
333+
334+ private void trackCushionMovement (final PacketWrapper wrapper , final int entityId ) {
335+ final CushionData cushionData = cushionData (wrapper , entityId );
336+ if (cushionData != null ) {
337+ final double x = cushionData .x () + wrapper .get (Types .SHORT , 0 ) / 4096D ;
338+ final double y = cushionData .y () + wrapper .get (Types .SHORT , 1 ) / 4096D ;
339+ final double z = cushionData .z () + wrapper .get (Types .SHORT , 2 ) / 4096D ;
340+ cushionData .setPosition (x , y , z );
341+ }
342+ }
343+
344+ private void trackCushionPosition (final PacketWrapper wrapper , final int entityId , final double x , final double y , final double z ) {
345+ final CushionData cushionData = cushionData (wrapper , entityId );
346+ if (cushionData != null ) {
347+ cushionData .setPosition (x , y , z );
348+ }
349+ }
350+
224351 private void handleGamemodes (final PacketWrapper wrapper ) {
225352 final int gamemode = wrapper .read (Types .VAR_INT );
226353 wrapper .write (Types .BYTE , (byte ) gamemode );
@@ -267,6 +394,9 @@ protected void registerRewrites() {
267394 MAPPED_DATA_TYPES .optionalComponentType
268395 );
269396 filter ().type (EntityTypes26_3 .CUSHION ).handler ((event , data ) -> {
397+ if (event .index () == 8 ) {
398+ updateCushionColor (event , data .value ());
399+ }
270400 if (event .index () > 7 ) {
271401 event .cancel (); // Cancel all non-entity data
272402 }
0 commit comments