/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.Lists * com.mojang.datafixers.util.Pair * com.mojang.logging.LogUtils * org.jspecify.annotations.Nullable * org.slf4j.Logger */ package net.minecraft.server.level; import com.google.common.collect.Lists; import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; import net.minecraft.core.component.DataComponents; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundBundlePacket; import net.minecraft.network.protocol.game.ClientboundEntityPositionSyncPacket; import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket; import net.minecraft.network.protocol.game.ClientboundMoveMinecartPacket; import net.minecraft.network.protocol.game.ClientboundProjectilePowerPacket; import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket; import net.minecraft.network.protocol.game.VecDeltaCodec; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.Leashable; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.decoration.ItemFrame; import net.minecraft.world.entity.projectile.AbstractArrow; import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; import net.minecraft.world.entity.vehicle.AbstractMinecart; import net.minecraft.world.entity.vehicle.MinecartBehavior; import net.minecraft.world.entity.vehicle.NewMinecartBehavior; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.MapItem; import net.minecraft.world.level.Level; import net.minecraft.world.level.saveddata.maps.MapId; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import net.minecraft.world.phys.Vec3; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public class ServerEntity { private static final Logger LOGGER = LogUtils.getLogger(); private static final int TOLERANCE_LEVEL_ROTATION = 1; private static final double TOLERANCE_LEVEL_POSITION = 7.62939453125E-6; public static final int FORCED_POS_UPDATE_PERIOD = 60; private static final int FORCED_TELEPORT_PERIOD = 400; private final ServerLevel level; private final Entity entity; private final int updateInterval; private final boolean trackDelta; private final Synchronizer synchronizer; private final VecDeltaCodec positionCodec = new VecDeltaCodec(); private byte lastSentYRot; private byte lastSentXRot; private byte lastSentYHeadRot; private Vec3 lastSentMovement; private int tickCount; private int teleportDelay; private List lastPassengers = Collections.emptyList(); private boolean wasRiding; private boolean wasOnGround; private @Nullable List> trackedDataValues; public ServerEntity(ServerLevel level, Entity entity, int updateInterval, boolean trackDelta, Synchronizer synchronizer) { this.level = level; this.synchronizer = synchronizer; this.entity = entity; this.updateInterval = updateInterval; this.trackDelta = trackDelta; this.positionCodec.setBase(entity.trackingPosition()); this.lastSentMovement = entity.getDeltaMovement(); this.lastSentYRot = Mth.packDegrees(entity.getYRot()); this.lastSentXRot = Mth.packDegrees(entity.getXRot()); this.lastSentYHeadRot = Mth.packDegrees(entity.getYHeadRot()); this.wasOnGround = entity.onGround(); this.trackedDataValues = entity.getEntityData().getNonDefaultValues(); } public void sendChanges() { Entity entity; this.entity.updateDataBeforeSync(); List passengers = this.entity.getPassengers(); if (!passengers.equals(this.lastPassengers)) { this.synchronizer.sendToTrackingPlayersFiltered(new ClientboundSetPassengersPacket(this.entity), player -> passengers.contains(player) == this.lastPassengers.contains(player)); this.lastPassengers = passengers; } if ((entity = this.entity) instanceof ItemFrame) { ItemFrame frame = (ItemFrame)entity; if (this.tickCount % 10 == 0) { MapId id; MapItemSavedData data; ItemStack itemStack = frame.getItem(); if (itemStack.getItem() instanceof MapItem && (data = MapItem.getSavedData(id = itemStack.get(DataComponents.MAP_ID), (Level)this.level)) != null) { for (ServerPlayer serverPlayer : this.level.players()) { data.tickCarriedBy(serverPlayer, itemStack); Packet packet = data.getUpdatePacket(id, serverPlayer); if (packet == null) continue; serverPlayer.connection.send(packet); } } this.sendDirtyEntityData(); } } if (this.tickCount % this.updateInterval == 0 || this.entity.needsSync || this.entity.getEntityData().isDirty()) { boolean shouldSendRotation; byte yRotn = Mth.packDegrees(this.entity.getYRot()); byte xRotn = Mth.packDegrees(this.entity.getXRot()); boolean bl = shouldSendRotation = Math.abs(yRotn - this.lastSentYRot) >= 1 || Math.abs(xRotn - this.lastSentXRot) >= 1; if (this.entity.isPassenger()) { if (shouldSendRotation) { this.synchronizer.sendToTrackingPlayers(new ClientboundMoveEntityPacket.Rot(this.entity.getId(), yRotn, xRotn, this.entity.onGround())); this.lastSentYRot = yRotn; this.lastSentXRot = xRotn; } this.positionCodec.setBase(this.entity.trackingPosition()); this.sendDirtyEntityData(); this.wasRiding = true; } else { AbstractMinecart minecart; MinecartBehavior minecartBehavior; Entity entity2 = this.entity; if (entity2 instanceof AbstractMinecart && (minecartBehavior = (minecart = (AbstractMinecart)entity2).getBehavior()) instanceof NewMinecartBehavior) { NewMinecartBehavior newMinecartBehavior = (NewMinecartBehavior)minecartBehavior; this.handleMinecartPosRot(newMinecartBehavior, yRotn, xRotn, shouldSendRotation); } else { Vec3 movement; double diff; boolean deltaTooBig; ++this.teleportDelay; Vec3 vec3 = this.entity.trackingPosition(); boolean positionChanged = this.positionCodec.delta(vec3).lengthSqr() >= 7.62939453125E-6; Packet packet = null; boolean pos = positionChanged || this.tickCount % 60 == 0; boolean sentPosition = false; boolean sentRotation = false; long xa = this.positionCodec.encodeX(vec3); long ya = this.positionCodec.encodeY(vec3); long za = this.positionCodec.encodeZ(vec3); boolean bl2 = deltaTooBig = xa < -32768L || xa > 32767L || ya < -32768L || ya > 32767L || za < -32768L || za > 32767L; if (this.entity.getRequiresPrecisePosition() || deltaTooBig || this.teleportDelay > 400 || this.wasRiding || this.wasOnGround != this.entity.onGround()) { this.wasOnGround = this.entity.onGround(); this.teleportDelay = 0; packet = ClientboundEntityPositionSyncPacket.of(this.entity); sentPosition = true; sentRotation = true; } else if (pos && shouldSendRotation || this.entity instanceof AbstractArrow) { packet = new ClientboundMoveEntityPacket.PosRot(this.entity.getId(), (short)xa, (short)ya, (short)za, yRotn, xRotn, this.entity.onGround()); sentPosition = true; sentRotation = true; } else if (pos) { packet = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short)xa, (short)ya, (short)za, this.entity.onGround()); sentPosition = true; } else if (shouldSendRotation) { packet = new ClientboundMoveEntityPacket.Rot(this.entity.getId(), yRotn, xRotn, this.entity.onGround()); sentRotation = true; } if ((this.entity.needsSync || this.trackDelta || this.entity instanceof LivingEntity && ((LivingEntity)this.entity).isFallFlying()) && ((diff = (movement = this.entity.getDeltaMovement()).distanceToSqr(this.lastSentMovement)) > 1.0E-7 || diff > 0.0 && movement.lengthSqr() == 0.0)) { this.lastSentMovement = movement; Entity entity3 = this.entity; if (entity3 instanceof AbstractHurtingProjectile) { AbstractHurtingProjectile projectile = (AbstractHurtingProjectile)entity3; this.synchronizer.sendToTrackingPlayers(new ClientboundBundlePacket((Iterable>)List.of(new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement), new ClientboundProjectilePowerPacket(projectile.getId(), projectile.accelerationPower)))); } else { this.synchronizer.sendToTrackingPlayers(new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement)); } } if (packet != null) { this.synchronizer.sendToTrackingPlayers(packet); } this.sendDirtyEntityData(); if (sentPosition) { this.positionCodec.setBase(vec3); } if (sentRotation) { this.lastSentYRot = yRotn; this.lastSentXRot = xRotn; } this.wasRiding = false; } } byte yHeadRot = Mth.packDegrees(this.entity.getYHeadRot()); if (Math.abs(yHeadRot - this.lastSentYHeadRot) >= 1) { this.synchronizer.sendToTrackingPlayers(new ClientboundRotateHeadPacket(this.entity, yHeadRot)); this.lastSentYHeadRot = yHeadRot; } this.entity.needsSync = false; } ++this.tickCount; if (this.entity.hurtMarked) { this.entity.hurtMarked = false; this.synchronizer.sendToTrackingPlayersAndSelf(new ClientboundSetEntityMotionPacket(this.entity)); } } private void handleMinecartPosRot(NewMinecartBehavior newMinecartBehavior, byte yRotn, byte xRotn, boolean shouldSendRotation) { this.sendDirtyEntityData(); if (newMinecartBehavior.lerpSteps.isEmpty()) { boolean shouldSendPosition; Vec3 movement = this.entity.getDeltaMovement(); double diff = movement.distanceToSqr(this.lastSentMovement); Vec3 currentPosition = this.entity.trackingPosition(); boolean positionChanged = this.positionCodec.delta(currentPosition).lengthSqr() >= 7.62939453125E-6; boolean bl = shouldSendPosition = positionChanged || this.tickCount % 60 == 0; if (shouldSendPosition || shouldSendRotation || diff > 1.0E-7) { this.synchronizer.sendToTrackingPlayers(new ClientboundMoveMinecartPacket(this.entity.getId(), List.of(new NewMinecartBehavior.MinecartStep(this.entity.position(), this.entity.getDeltaMovement(), this.entity.getYRot(), this.entity.getXRot(), 1.0f)))); } } else { this.synchronizer.sendToTrackingPlayers(new ClientboundMoveMinecartPacket(this.entity.getId(), List.copyOf(newMinecartBehavior.lerpSteps))); newMinecartBehavior.lerpSteps.clear(); } this.lastSentYRot = yRotn; this.lastSentXRot = xRotn; this.positionCodec.setBase(this.entity.position()); } public void removePairing(ServerPlayer player) { this.entity.stopSeenByPlayer(player); player.connection.send(new ClientboundRemoveEntitiesPacket(this.entity.getId())); } public void addPairing(ServerPlayer player) { ArrayList> packets = new ArrayList>(); this.sendPairingData(player, packets::add); player.connection.send(new ClientboundBundlePacket((Iterable>)packets)); this.entity.startSeenByPlayer(player); } public void sendPairingData(ServerPlayer player, Consumer> broadcast) { Leashable leashable; LivingEntity livingEntity; Object attributes; Entity entity; this.entity.updateDataBeforeSync(); if (this.entity.isRemoved()) { LOGGER.warn("Fetching packet for removed entity {}", (Object)this.entity); } Packet packet = this.entity.getAddEntityPacket(this); broadcast.accept(packet); if (this.trackedDataValues != null) { broadcast.accept(new ClientboundSetEntityDataPacket(this.entity.getId(), this.trackedDataValues)); } if ((entity = this.entity) instanceof LivingEntity && !(attributes = (livingEntity = (LivingEntity)entity).getAttributes().getSyncableAttributes()).isEmpty()) { broadcast.accept(new ClientboundUpdateAttributesPacket(this.entity.getId(), (Collection)attributes)); } if ((attributes = this.entity) instanceof LivingEntity) { livingEntity = (LivingEntity)attributes; ArrayList slots = Lists.newArrayList(); for (EquipmentSlot slot : EquipmentSlot.VALUES) { ItemStack itemStack = livingEntity.getItemBySlot(slot); if (itemStack.isEmpty()) continue; slots.add(Pair.of((Object)slot, (Object)itemStack.copy())); } if (!slots.isEmpty()) { broadcast.accept(new ClientboundSetEquipmentPacket(this.entity.getId(), slots)); } } if (!this.entity.getPassengers().isEmpty()) { broadcast.accept(new ClientboundSetPassengersPacket(this.entity)); } if (this.entity.isPassenger()) { broadcast.accept(new ClientboundSetPassengersPacket(this.entity.getVehicle())); } if ((entity = this.entity) instanceof Leashable && (leashable = (Leashable)((Object)entity)).isLeashed()) { broadcast.accept(new ClientboundSetEntityLinkPacket(this.entity, leashable.getLeashHolder())); } } public Vec3 getPositionBase() { return this.positionCodec.getBase(); } public Vec3 getLastSentMovement() { return this.lastSentMovement; } public float getLastSentXRot() { return Mth.unpackDegrees(this.lastSentXRot); } public float getLastSentYRot() { return Mth.unpackDegrees(this.lastSentYRot); } public float getLastSentYHeadRot() { return Mth.unpackDegrees(this.lastSentYHeadRot); } private void sendDirtyEntityData() { SynchedEntityData entityData = this.entity.getEntityData(); List> packedValues = entityData.packDirty(); if (packedValues != null) { this.trackedDataValues = entityData.getNonDefaultValues(); this.synchronizer.sendToTrackingPlayersAndSelf(new ClientboundSetEntityDataPacket(this.entity.getId(), packedValues)); } if (this.entity instanceof LivingEntity) { Set attributes = ((LivingEntity)this.entity).getAttributes().getAttributesToSync(); if (!attributes.isEmpty()) { this.synchronizer.sendToTrackingPlayersAndSelf(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributes)); } attributes.clear(); } } public static interface Synchronizer { public void sendToTrackingPlayers(Packet var1); public void sendToTrackingPlayersAndSelf(Packet var1); public void sendToTrackingPlayersFiltered(Packet var1, Predicate var2); } }