ServerEntity.java

net.minecraft.server.level.ServerEntity

信息

  • 全限定名:net.minecraft.server.level.ServerEntity
  • 类型:public class
  • 包:net.minecraft.server.level
  • 源码路径:src/main/java/net/minecraft/server/level/ServerEntity.java
  • 起始行号:L50
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L51
    • 说明:

      TODO

  • TOLERANCE_LEVEL_ROTATION

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L52
    • 说明:

      TODO

  • TOLERANCE_LEVEL_POSITION

    • 类型: double
    • 修饰符: private static final
    • 源码定位: L53
    • 说明:

      TODO

  • FORCED_POS_UPDATE_PERIOD

    • 类型: int
    • 修饰符: public static final
    • 源码定位: L54
    • 说明:

      TODO

  • FORCED_TELEPORT_PERIOD

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L55
    • 说明:

      TODO

  • level

    • 类型: ServerLevel
    • 修饰符: private final
    • 源码定位: L56
    • 说明:

      TODO

  • entity

    • 类型: Entity
    • 修饰符: private final
    • 源码定位: L57
    • 说明:

      TODO

  • updateInterval

    • 类型: int
    • 修饰符: private final
    • 源码定位: L58
    • 说明:

      TODO

  • trackDelta

    • 类型: boolean
    • 修饰符: private final
    • 源码定位: L59
    • 说明:

      TODO

  • synchronizer

    • 类型: ServerEntity.Synchronizer
    • 修饰符: private final
    • 源码定位: L60
    • 说明:

      TODO

  • positionCodec

    • 类型: VecDeltaCodec
    • 修饰符: private final
    • 源码定位: L61
    • 说明:

      TODO

  • lastSentYRot

    • 类型: byte
    • 修饰符: private
    • 源码定位: L62
    • 说明:

      TODO

  • lastSentXRot

    • 类型: byte
    • 修饰符: private
    • 源码定位: L63
    • 说明:

      TODO

  • lastSentYHeadRot

    • 类型: byte
    • 修饰符: private
    • 源码定位: L64
    • 说明:

      TODO

  • lastSentMovement

    • 类型: Vec3
    • 修饰符: private
    • 源码定位: L65
    • 说明:

      TODO

  • tickCount

    • 类型: int
    • 修饰符: private
    • 源码定位: L66
    • 说明:

      TODO

  • teleportDelay

    • 类型: int
    • 修饰符: private
    • 源码定位: L67
    • 说明:

      TODO

  • lastPassengers

    • 类型: List<Entity>
    • 修饰符: private
    • 源码定位: L68
    • 说明:

      TODO

  • wasRiding

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L69
    • 说明:

      TODO

  • wasOnGround

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L70
    • 说明:

      TODO

  • trackedDataValues

    • 类型: List<SynchedEntityData.DataValue<?>>
    • 修饰符: private
    • 源码定位: L71
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.server.level.ServerEntity.Synchronizer
    • 类型: interface
    • 修饰符: public
    • 源码定位: L352
    • 说明:

      TODO

构造器

public ServerEntity(ServerLevel level, Entity entity, int updateInterval, boolean trackDelta, ServerEntity.Synchronizer synchronizer) @ L73

  • 构造器名:ServerEntity
  • 源码定位:L73
  • 修饰符:public

参数:

  • level: ServerLevel
  • entity: Entity
  • updateInterval: int
  • trackDelta: boolean
  • synchronizer: ServerEntity.Synchronizer

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void sendChanges() @ L88

  • 方法名:sendChanges
  • 源码定位:L88
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

private void handleMinecartPosRot(NewMinecartBehavior newMinecartBehavior, byte yRotn, byte xRotn, boolean shouldSendRotation) @ L224

  • 方法名:handleMinecartPosRot
  • 源码定位:L224
  • 返回类型:void
  • 修饰符:private

参数:

  • newMinecartBehavior: NewMinecartBehavior
  • yRotn: byte
  • xRotn: byte
  • shouldSendRotation: boolean

说明:

TODO

public void removePairing(ServerPlayer player) @ L255

  • 方法名:removePairing
  • 源码定位:L255
  • 返回类型:void
  • 修饰符:public

参数:

  • player: ServerPlayer

说明:

TODO

public void addPairing(ServerPlayer player) @ L260

  • 方法名:addPairing
  • 源码定位:L260
  • 返回类型:void
  • 修饰符:public

参数:

  • player: ServerPlayer

说明:

TODO

public void sendPairingData(ServerPlayer player, Consumer<Packet<ClientGamePacketListener>> broadcast) @ L267

  • 方法名:sendPairingData
  • 源码定位:L267
  • 返回类型:void
  • 修饰符:public

参数:

  • player: ServerPlayer
  • broadcast: Consumer<Packet>

说明:

TODO

public Vec3 getPositionBase() @ L314

  • 方法名:getPositionBase
  • 源码定位:L314
  • 返回类型:Vec3
  • 修饰符:public

参数:

说明:

TODO

public Vec3 getLastSentMovement() @ L318

  • 方法名:getLastSentMovement
  • 源码定位:L318
  • 返回类型:Vec3
  • 修饰符:public

参数:

说明:

TODO

public float getLastSentXRot() @ L322

  • 方法名:getLastSentXRot
  • 源码定位:L322
  • 返回类型:float
  • 修饰符:public

参数:

说明:

TODO

public float getLastSentYRot() @ L326

  • 方法名:getLastSentYRot
  • 源码定位:L326
  • 返回类型:float
  • 修饰符:public

参数:

说明:

TODO

public float getLastSentYHeadRot() @ L330

  • 方法名:getLastSentYHeadRot
  • 源码定位:L330
  • 返回类型:float
  • 修饰符:public

参数:

说明:

TODO

private void sendDirtyEntityData() @ L334

  • 方法名:sendDirtyEntityData
  • 源码定位:L334
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

代码

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.6293945E-6F;
    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 ServerEntity.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<Entity> lastPassengers = Collections.emptyList();
    private boolean wasRiding;
    private boolean wasOnGround;
    private @Nullable List<SynchedEntityData.DataValue<?>> trackedDataValues;
 
    public ServerEntity(ServerLevel level, Entity entity, int updateInterval, boolean trackDelta, ServerEntity.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() {
        this.entity.updateDataBeforeSync();
        List<Entity> 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 (this.entity instanceof ItemFrame frame && this.tickCount % 10 == 0) {
            ItemStack itemStack = frame.getItem();
            if (itemStack.getItem() instanceof MapItem) {
                MapId id = itemStack.get(DataComponents.MAP_ID);
                MapItemSavedData data = MapItem.getSavedData(id, this.level);
                if (data != null) {
                    for (ServerPlayer player : this.level.players()) {
                        data.tickCarriedBy(player, itemStack, frame);
                        Packet<?> packet = data.getUpdatePacket(id, player);
                        if (packet != null) {
                            player.connection.send(packet);
                        }
                    }
                }
            }
 
            this.sendDirtyEntityData();
        }
 
        if (this.tickCount % this.updateInterval == 0 || this.entity.needsSync || this.entity.getEntityData().isDirty()) {
            byte yRotn = Mth.packDegrees(this.entity.getYRot());
            byte xRotn = Mth.packDegrees(this.entity.getXRot());
            boolean 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 if (this.entity instanceof AbstractMinecart minecart && minecart.getBehavior() instanceof NewMinecartBehavior newMinecartBehavior) {
                this.handleMinecartPosRot(newMinecartBehavior, yRotn, xRotn, shouldSendRotation);
            } else {
                this.teleportDelay++;
                Vec3 currentPosition = this.entity.trackingPosition();
                boolean positionChanged = this.positionCodec.delta(currentPosition).lengthSqr() >= 7.6293945E-6F;
                Packet<ClientGamePacketListener> packet = null;
                boolean pos = positionChanged || this.tickCount % 60 == 0;
                boolean sentPosition = false;
                boolean sentRotation = false;
                long xa = this.positionCodec.encodeX(currentPosition);
                long ya = this.positionCodec.encodeY(currentPosition);
                long za = this.positionCodec.encodeZ(currentPosition);
                boolean 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)) {
                    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;
                    }
                } else {
                    packet = new ClientboundMoveEntityPacket.PosRot(this.entity.getId(), (short)xa, (short)ya, (short)za, yRotn, xRotn, this.entity.onGround());
                    sentPosition = true;
                    sentRotation = true;
                }
 
                if (this.entity.needsSync || this.trackDelta || this.entity instanceof LivingEntity && ((LivingEntity)this.entity).isFallFlying()) {
                    Vec3 movement = this.entity.getDeltaMovement();
                    double diff = movement.distanceToSqr(this.lastSentMovement);
                    if (diff > 1.0E-7 || diff > 0.0 && movement.lengthSqr() == 0.0) {
                        this.lastSentMovement = movement;
                        if (this.entity instanceof AbstractHurtingProjectile projectile) {
                            this.synchronizer
                                .sendToTrackingPlayers(
                                    new ClientboundBundlePacket(
                                        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(currentPosition);
                }
 
                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()) {
            Vec3 movement = this.entity.getDeltaMovement();
            double diff = movement.distanceToSqr(this.lastSentMovement);
            Vec3 currentPosition = this.entity.trackingPosition();
            boolean positionChanged = this.positionCodec.delta(currentPosition).lengthSqr() >= 7.6293945E-6F;
            boolean 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) {
        List<Packet<? super ClientGamePacketListener>> packets = new ArrayList<>();
        this.sendPairingData(player, packets::add);
        player.connection.send(new ClientboundBundlePacket(packets));
        this.entity.startSeenByPlayer(player);
    }
 
    public void sendPairingData(ServerPlayer player, Consumer<Packet<ClientGamePacketListener>> broadcast) {
        this.entity.updateDataBeforeSync();
        if (this.entity.isRemoved()) {
            LOGGER.warn("Fetching packet for removed entity {}", this.entity);
        }
 
        Packet<ClientGamePacketListener> packet = this.entity.getAddEntityPacket(this);
        broadcast.accept(packet);
        if (this.trackedDataValues != null) {
            broadcast.accept(new ClientboundSetEntityDataPacket(this.entity.getId(), this.trackedDataValues));
        }
 
        if (this.entity instanceof LivingEntity livingEntity) {
            Collection<AttributeInstance> attributes = livingEntity.getAttributes().getSyncableAttributes();
            if (!attributes.isEmpty()) {
                broadcast.accept(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributes));
            }
        }
 
        if (this.entity instanceof LivingEntity livingEntityx) {
            List<Pair<EquipmentSlot, ItemStack>> slots = Lists.newArrayList();
 
            for (EquipmentSlot slot : EquipmentSlot.VALUES) {
                ItemStack itemStack = livingEntityx.getItemBySlot(slot);
                if (!itemStack.isEmpty()) {
                    slots.add(Pair.of(slot, 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 (this.entity instanceof Leashable leashable && leashable.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<SynchedEntityData.DataValue<?>> 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<AttributeInstance> attributes = ((LivingEntity)this.entity).getAttributes().getAttributesToSync();
            if (!attributes.isEmpty()) {
                this.synchronizer.sendToTrackingPlayersAndSelf(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributes));
            }
 
            attributes.clear();
        }
    }
 
    public interface Synchronizer {
        void sendToTrackingPlayers(Packet<? super ClientGamePacketListener> packet);
 
        void sendToTrackingPlayersAndSelf(Packet<? super ClientGamePacketListener> packet);
 
        void sendToTrackingPlayersFiltered(Packet<? super ClientGamePacketListener> packet, Predicate<ServerPlayer> predicate);
    }
}

引用的其他类