433 lines
16 KiB
Java
Executable file
433 lines
16 KiB
Java
Executable file
package game.entity;
|
|
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
import game.collect.Sets;
|
|
|
|
import game.entity.attributes.AttributeInstance;
|
|
import game.entity.attributes.AttributeMap;
|
|
import game.entity.npc.EntityNPC;
|
|
import game.entity.projectile.EntityArrow;
|
|
import game.entity.types.EntityLiving;
|
|
import game.item.ItemStack;
|
|
import game.log.Log;
|
|
import game.nbt.NBTTagCompound;
|
|
import game.network.Packet;
|
|
import game.packet.S14PacketEntity;
|
|
import game.packet.S18PacketEntityTeleport;
|
|
import game.packet.S19PacketEntityHeadLook;
|
|
import game.packet.S1BPacketEntityAttach;
|
|
import game.packet.S1CPacketEntityMetadata;
|
|
import game.packet.S1DPacketEntityEffect;
|
|
import game.packet.S20PacketEntityProperties;
|
|
import game.packet.S43PacketUpdateEntityNBT;
|
|
import game.packet.SPacketEntityEquipment;
|
|
import game.packet.SPacketEntityVelocity;
|
|
import game.packet.SPacketSpawnMob;
|
|
import game.packet.SPacketSpawnObject;
|
|
import game.packet.SPacketSpawnPlayer;
|
|
import game.potion.PotionEffect;
|
|
import game.util.ExtMath;
|
|
|
|
public class EntityTrackerEntry {
|
|
public final Entity trackedEntity;
|
|
private final int trackingDistanceThreshold;
|
|
private final int updateFrequency;
|
|
private final boolean sendVelocityUpdates;
|
|
private final Set<EntityNPC> trackingPlayers = Sets.<EntityNPC>newHashSet();
|
|
|
|
private Entity lastRiding;
|
|
private int encodedPosX;
|
|
private int encodedPosY;
|
|
private int encodedPosZ;
|
|
private int encodedRotationYaw;
|
|
private int encodedRotationPitch;
|
|
private int lastHeadMotion;
|
|
private double lastTrackedEntityMotionX;
|
|
private double lastTrackedEntityMotionY;
|
|
private double lastTrackedEntityMotionZ;
|
|
private int updateCounter;
|
|
private double lastTrackedEntityPosX;
|
|
private double lastTrackedEntityPosY;
|
|
private double lastTrackedEntityPosZ;
|
|
private boolean firstUpdateDone;
|
|
private int ticksSinceLastForcedTeleport;
|
|
private boolean ridingEntity;
|
|
private boolean onGround;
|
|
private boolean playerEntitiesUpdated;
|
|
|
|
public EntityTrackerEntry(Entity trackedEntityIn, int trackingDistanceThresholdIn, int updateFrequencyIn, boolean sendVelocityUpdatesIn) {
|
|
this.trackedEntity = trackedEntityIn;
|
|
this.trackingDistanceThreshold = trackingDistanceThresholdIn;
|
|
this.updateFrequency = updateFrequencyIn;
|
|
this.sendVelocityUpdates = sendVelocityUpdatesIn;
|
|
this.encodedPosX = ExtMath.floord(trackedEntityIn.posX * 32.0D);
|
|
this.encodedPosY = ExtMath.floord(trackedEntityIn.posY * 32.0D);
|
|
this.encodedPosZ = ExtMath.floord(trackedEntityIn.posZ * 32.0D);
|
|
this.encodedRotationYaw = ExtMath.floorf(trackedEntityIn.rotYaw * 256.0F / 360.0F);
|
|
this.encodedRotationPitch = ExtMath.floorf(trackedEntityIn.rotPitch * 256.0F / 360.0F);
|
|
this.lastHeadMotion = ExtMath.floorf(trackedEntityIn.getRotationYawHead() * 256.0F / 360.0F);
|
|
this.onGround = trackedEntityIn.onGround;
|
|
}
|
|
|
|
public boolean equals(Object obj) {
|
|
return obj instanceof EntityTrackerEntry
|
|
? ((EntityTrackerEntry)obj).trackedEntity.getId() == this.trackedEntity.getId()
|
|
: false;
|
|
}
|
|
|
|
public int hashCode() {
|
|
return this.trackedEntity.getId();
|
|
}
|
|
|
|
public void updatePlayerList(List<EntityNPC> players) {
|
|
this.playerEntitiesUpdated = false;
|
|
|
|
if(!this.firstUpdateDone
|
|
|| this.trackedEntity.getDistanceSq(this.lastTrackedEntityPosX, this.lastTrackedEntityPosY, this.lastTrackedEntityPosZ) > 16.0D) {
|
|
this.lastTrackedEntityPosX = this.trackedEntity.posX;
|
|
this.lastTrackedEntityPosY = this.trackedEntity.posY;
|
|
this.lastTrackedEntityPosZ = this.trackedEntity.posZ;
|
|
this.firstUpdateDone = true;
|
|
this.playerEntitiesUpdated = true;
|
|
this.updatePlayerEntities(players);
|
|
}
|
|
|
|
if(this.lastRiding != this.trackedEntity.vehicle || this.trackedEntity.vehicle != null && this.updateCounter % 60 == 0) {
|
|
this.lastRiding = this.trackedEntity.vehicle;
|
|
this.sendPacketToTrackedPlayers(new S1BPacketEntityAttach(0, this.trackedEntity, this.trackedEntity.vehicle));
|
|
}
|
|
|
|
// if(this.trackedEntity instanceof EntityFrame && this.updateCounter % 10 == 0) {
|
|
//// EntityItemFrame entityitemframe = (EntityItemFrame)this.trackedEntity;
|
|
//// ItemStack itemstack = entityitemframe.getDisplayedItem();
|
|
////
|
|
//// if(itemstack != null && itemstack.getItem() instanceof ItemMap) {
|
|
//// MapData mapdata = Items.filled_map.getMapData(itemstack, this.trackedEntity.worldObj);
|
|
////
|
|
//// for(EntityNPC entityplayer : players) {
|
|
//// EntityNPCMP entityplayermp = (EntityNPCMP)entityplayer;
|
|
//// mapdata.updateVisiblePlayers(entityplayermp, itemstack);
|
|
//// Packet packet = Items.filled_map.createMapDataPacket(itemstack, this.trackedEntity.worldObj, entityplayermp);
|
|
////
|
|
//// if(packet != null) {
|
|
//// entityplayermp.netHandler.sendPacket(packet);
|
|
//// }
|
|
//// }
|
|
//// }
|
|
//
|
|
// this.sendMetadataToAllAssociatedPlayers();
|
|
// }
|
|
|
|
if(this.updateCounter % this.updateFrequency == 0 || this.trackedEntity.isAirBorne
|
|
|| this.trackedEntity.getDataWatcher().hasObjectChanged()) {
|
|
if(this.trackedEntity.vehicle == null) {
|
|
++this.ticksSinceLastForcedTeleport;
|
|
int k = ExtMath.floord(this.trackedEntity.posX * 32.0D);
|
|
int j1 = ExtMath.floord(this.trackedEntity.posY * 32.0D);
|
|
int k1 = ExtMath.floord(this.trackedEntity.posZ * 32.0D);
|
|
int l1 = ExtMath.floorf(this.trackedEntity.rotYaw * 256.0F / 360.0F);
|
|
int i2 = ExtMath.floorf(this.trackedEntity.rotPitch * 256.0F / 360.0F);
|
|
int j2 = k - this.encodedPosX;
|
|
int k2 = j1 - this.encodedPosY;
|
|
int i = k1 - this.encodedPosZ;
|
|
Packet packet1 = null;
|
|
boolean flag = Math.abs(j2) >= 4 || Math.abs(k2) >= 4 || Math.abs(i) >= 4 || this.updateCounter % 60 == 0;
|
|
boolean flag1 = Math.abs(l1 - this.encodedRotationYaw) >= 4 || Math.abs(i2 - this.encodedRotationPitch) >= 4;
|
|
|
|
if(this.updateCounter > 0 || this.trackedEntity instanceof EntityArrow) {
|
|
if(j2 >= -128 && j2 < 128 && k2 >= -128 && k2 < 128 && i >= -128 && i < 128 && this.ticksSinceLastForcedTeleport <= 400
|
|
&& !this.ridingEntity && this.onGround == this.trackedEntity.onGround) {
|
|
if((!flag || !flag1) && !(this.trackedEntity instanceof EntityArrow)) {
|
|
if(flag) {
|
|
packet1 = new S14PacketEntity.S15PacketEntityRelMove(this.trackedEntity.getId(), (byte)j2, (byte)k2, (byte)i,
|
|
this.trackedEntity.onGround);
|
|
}
|
|
else if(flag1) {
|
|
packet1 = new S14PacketEntity.S16PacketEntityLook(this.trackedEntity.getId(), (byte)l1, (byte)i2,
|
|
this.trackedEntity.onGround);
|
|
}
|
|
}
|
|
else {
|
|
packet1 = new S14PacketEntity.S17PacketEntityLookMove(this.trackedEntity.getId(), (byte)j2, (byte)k2, (byte)i,
|
|
(byte)l1, (byte)i2, this.trackedEntity.onGround);
|
|
}
|
|
}
|
|
else {
|
|
this.onGround = this.trackedEntity.onGround;
|
|
this.ticksSinceLastForcedTeleport = 0;
|
|
packet1 = new S18PacketEntityTeleport(this.trackedEntity.getId(), k, j1, k1, (byte)l1, (byte)i2,
|
|
this.trackedEntity.onGround);
|
|
}
|
|
}
|
|
|
|
if(this.sendVelocityUpdates) {
|
|
double d0 = this.trackedEntity.motionX - this.lastTrackedEntityMotionX;
|
|
double d1 = this.trackedEntity.motionY - this.lastTrackedEntityMotionY;
|
|
double d2 = this.trackedEntity.motionZ - this.lastTrackedEntityMotionZ;
|
|
double d3 = 0.02D;
|
|
double d4 = d0 * d0 + d1 * d1 + d2 * d2;
|
|
|
|
if(d4 > d3 * d3 || d4 > 0.0D && this.trackedEntity.motionX == 0.0D && this.trackedEntity.motionY == 0.0D
|
|
&& this.trackedEntity.motionZ == 0.0D) {
|
|
this.lastTrackedEntityMotionX = this.trackedEntity.motionX;
|
|
this.lastTrackedEntityMotionY = this.trackedEntity.motionY;
|
|
this.lastTrackedEntityMotionZ = this.trackedEntity.motionZ;
|
|
this.sendPacketToTrackedPlayers(new SPacketEntityVelocity(this.trackedEntity.getId(), this.lastTrackedEntityMotionX,
|
|
this.lastTrackedEntityMotionY, this.lastTrackedEntityMotionZ));
|
|
}
|
|
}
|
|
|
|
if(packet1 != null) {
|
|
this.sendPacketToTrackedPlayers(packet1);
|
|
}
|
|
|
|
this.sendMetadataToAllAssociatedPlayers();
|
|
|
|
if(flag) {
|
|
this.encodedPosX = k;
|
|
this.encodedPosY = j1;
|
|
this.encodedPosZ = k1;
|
|
}
|
|
|
|
if(flag1) {
|
|
this.encodedRotationYaw = l1;
|
|
this.encodedRotationPitch = i2;
|
|
}
|
|
|
|
this.ridingEntity = false;
|
|
}
|
|
else {
|
|
int j = ExtMath.floorf(this.trackedEntity.rotYaw * 256.0F / 360.0F);
|
|
int i1 = ExtMath.floorf(this.trackedEntity.rotPitch * 256.0F / 360.0F);
|
|
boolean flag2 = Math.abs(j - this.encodedRotationYaw) >= 4 || Math.abs(i1 - this.encodedRotationPitch) >= 4;
|
|
|
|
if(flag2) {
|
|
this.sendPacketToTrackedPlayers(new S14PacketEntity.S16PacketEntityLook(this.trackedEntity.getId(), (byte)j, (byte)i1,
|
|
this.trackedEntity.onGround));
|
|
this.encodedRotationYaw = j;
|
|
this.encodedRotationPitch = i1;
|
|
}
|
|
|
|
this.encodedPosX = ExtMath.floord(this.trackedEntity.posX * 32.0D);
|
|
this.encodedPosY = ExtMath.floord(this.trackedEntity.posY * 32.0D);
|
|
this.encodedPosZ = ExtMath.floord(this.trackedEntity.posZ * 32.0D);
|
|
this.sendMetadataToAllAssociatedPlayers();
|
|
this.ridingEntity = true;
|
|
}
|
|
|
|
int l = ExtMath.floorf(this.trackedEntity.getRotationYawHead() * 256.0F / 360.0F);
|
|
|
|
if(Math.abs(l - this.lastHeadMotion) >= 4) {
|
|
this.sendPacketToTrackedPlayers(new S19PacketEntityHeadLook(this.trackedEntity, (byte)l));
|
|
this.lastHeadMotion = l;
|
|
}
|
|
|
|
this.trackedEntity.isAirBorne = false;
|
|
}
|
|
|
|
++this.updateCounter;
|
|
|
|
if(this.trackedEntity.veloChanged) {
|
|
this.sendPacketToTrackedAndSelf(new SPacketEntityVelocity(this.trackedEntity));
|
|
this.trackedEntity.veloChanged = false;
|
|
}
|
|
}
|
|
|
|
private void sendMetadataToAllAssociatedPlayers() {
|
|
DataWatcher datawatcher = this.trackedEntity.getDataWatcher();
|
|
|
|
if(datawatcher.hasObjectChanged()) {
|
|
this.sendPacketToTrackedAndSelf(new S1CPacketEntityMetadata(this.trackedEntity.getId(), datawatcher, false));
|
|
}
|
|
|
|
if(this.trackedEntity instanceof EntityLiving) {
|
|
AttributeMap serversideattributemap = ((EntityLiving)this.trackedEntity).getAttributeMap();
|
|
Set<AttributeInstance> set = serversideattributemap.getDirty();
|
|
|
|
if(!set.isEmpty()) {
|
|
this.sendPacketToTrackedAndSelf(new S20PacketEntityProperties(this.trackedEntity.getId(), set));
|
|
}
|
|
|
|
set.clear();
|
|
}
|
|
}
|
|
|
|
public void sendPacketToTrackedPlayers(Packet packetIn) {
|
|
for(EntityNPC entityplayermp : this.trackingPlayers) {
|
|
entityplayermp.connection.sendPacket(packetIn);
|
|
}
|
|
}
|
|
|
|
public void sendPacketToTrackedAndSelf(Packet packetIn) {
|
|
this.sendPacketToTrackedPlayers(packetIn);
|
|
|
|
if(this.trackedEntity.isPlayer()) {
|
|
((EntityNPC)this.trackedEntity).connection.sendPacket(packetIn);
|
|
}
|
|
}
|
|
|
|
public void sendDestroyEntityPacketToTrackedPlayers() {
|
|
for(EntityNPC entityplayermp : this.trackingPlayers) {
|
|
entityplayermp.connection.removeEntity(this.trackedEntity);
|
|
}
|
|
}
|
|
|
|
public void removeFromTrackedPlayers(EntityNPC playerMP) {
|
|
if(this.trackingPlayers.contains(playerMP)) {
|
|
playerMP.connection.removeEntity(this.trackedEntity);
|
|
this.trackingPlayers.remove(playerMP);
|
|
}
|
|
}
|
|
|
|
public void updatePlayerEntity(EntityNPC playerMP) {
|
|
if(playerMP != this.trackedEntity) {
|
|
if(this.canBeSeen(playerMP)) {
|
|
if(!this.trackingPlayers.contains(playerMP) && (this.isPlayerWatchingThisChunk(playerMP) || this.trackedEntity.forceSpawn)) {
|
|
this.trackingPlayers.add(playerMP);
|
|
Packet packet = this.createSpawnPacket();
|
|
playerMP.connection.sendPacket(packet);
|
|
|
|
if(!this.trackedEntity.getDataWatcher().isBlank()) {
|
|
playerMP.connection
|
|
.sendPacket(new S1CPacketEntityMetadata(this.trackedEntity.getId(), this.trackedEntity.getDataWatcher(), true));
|
|
}
|
|
|
|
NBTTagCompound nbttagcompound = this.trackedEntity.getNBTTagCompound();
|
|
|
|
if(nbttagcompound != null) {
|
|
playerMP.connection.sendPacket(new S43PacketUpdateEntityNBT(this.trackedEntity.getId(), nbttagcompound));
|
|
}
|
|
|
|
if(this.trackedEntity instanceof EntityLiving) {
|
|
AttributeMap serversideattributemap = ((EntityLiving)this.trackedEntity).getAttributeMap();
|
|
Collection<AttributeInstance> collection = serversideattributemap.getWatchedAttributes();
|
|
|
|
if(!collection.isEmpty()) {
|
|
playerMP.connection.sendPacket(new S20PacketEntityProperties(this.trackedEntity.getId(), collection));
|
|
}
|
|
}
|
|
|
|
this.lastTrackedEntityMotionX = this.trackedEntity.motionX;
|
|
this.lastTrackedEntityMotionY = this.trackedEntity.motionY;
|
|
this.lastTrackedEntityMotionZ = this.trackedEntity.motionZ;
|
|
|
|
// if(this.trackedEntity.isPlayer() && !((EntityNPCMP)this.trackedEntity).isVisibleTo(playerMP))
|
|
// return;
|
|
|
|
if(this.sendVelocityUpdates && !(packet instanceof SPacketSpawnMob)) {
|
|
playerMP.connection.sendPacket(new SPacketEntityVelocity(this.trackedEntity.getId(),
|
|
this.trackedEntity.motionX, this.trackedEntity.motionY, this.trackedEntity.motionZ));
|
|
}
|
|
|
|
if(this.trackedEntity.vehicle != null) {
|
|
playerMP.connection.sendPacket(new S1BPacketEntityAttach(0, this.trackedEntity, this.trackedEntity.vehicle));
|
|
}
|
|
|
|
if(this.trackedEntity instanceof EntityLiving && ((EntityLiving)this.trackedEntity).getLeashedTo() != null) {
|
|
playerMP.connection.sendPacket(
|
|
new S1BPacketEntityAttach(1, this.trackedEntity, ((EntityLiving)this.trackedEntity).getLeashedTo()));
|
|
}
|
|
|
|
if(this.trackedEntity instanceof EntityLiving) {
|
|
for(int i = 0; i < 5; ++i) {
|
|
ItemStack itemstack = ((EntityLiving)this.trackedEntity).getItem(i);
|
|
|
|
if(itemstack != null) {
|
|
playerMP.connection
|
|
.sendPacket(new SPacketEntityEquipment(this.trackedEntity.getId(), i, itemstack));
|
|
}
|
|
}
|
|
}
|
|
|
|
// if(this.trackedEntity.isPlayer()) {
|
|
// EntityNPC entityplayer = (EntityNPC)this.trackedEntity;
|
|
//
|
|
// if(entityplayer.isPlayerSleeping()) {
|
|
// playerMP.netHandler.sendPacket(new SPacketUseBed(entityplayer, new BlockPos(this.trackedEntity)));
|
|
// }
|
|
// }
|
|
|
|
if(this.trackedEntity instanceof EntityLiving) {
|
|
EntityLiving entitylivingbase = (EntityLiving)this.trackedEntity;
|
|
|
|
for(PotionEffect potioneffect : entitylivingbase.getEffects()) {
|
|
playerMP.connection.sendPacket(new S1DPacketEntityEffect(this.trackedEntity.getId(), potioneffect));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(this.trackingPlayers.contains(playerMP)) {
|
|
this.trackingPlayers.remove(playerMP);
|
|
playerMP.connection.removeEntity(this.trackedEntity);
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean canBeSeen(EntityNPC playerMP) {
|
|
double d0 = playerMP.posX - (double)(this.encodedPosX / 32);
|
|
double d1 = playerMP.posZ - (double)(this.encodedPosZ / 32);
|
|
return d0 >= (double)(-this.trackingDistanceThreshold) && d0 <= (double)this.trackingDistanceThreshold
|
|
&& d1 >= (double)(-this.trackingDistanceThreshold) && d1 <= (double)this.trackingDistanceThreshold
|
|
&& this.trackedEntity.isVisibleTo(playerMP);
|
|
}
|
|
|
|
private boolean isPlayerWatchingThisChunk(EntityNPC playerMP) {
|
|
return playerMP.getServerWorld().isPlayerWatchingChunk(playerMP, this.trackedEntity.chunkCoordX,
|
|
this.trackedEntity.chunkCoordZ);
|
|
}
|
|
|
|
public void updatePlayerEntities(List<EntityNPC> players) {
|
|
for(int i = 0; i < players.size(); ++i) {
|
|
this.updatePlayerEntity(players.get(i));
|
|
}
|
|
}
|
|
|
|
private Packet createSpawnPacket() {
|
|
if(this.trackedEntity.dead) {
|
|
Log.JNI.warn("Erstelle Spawn-Paket für entferntes Objekt");
|
|
}
|
|
|
|
SPacketSpawnObject packet = null;
|
|
// int oid = EntityRegistry.getObjectID(this.trackedEntity);
|
|
// if(oid != 0) {
|
|
// }
|
|
if(this.trackedEntity.isPlayer()) {
|
|
return new SPacketSpawnPlayer((EntityNPC)this.trackedEntity);
|
|
}
|
|
else if(this.trackedEntity instanceof EntityLiving) {
|
|
this.lastHeadMotion = ExtMath.floorf(this.trackedEntity.getRotationYawHead() * 256.0F / 360.0F);
|
|
return new SPacketSpawnMob((EntityLiving)this.trackedEntity);
|
|
}
|
|
// else if(this.trackedEntity instanceof EntityPainting) {
|
|
// return new SPacketSpawnPainting((EntityPainting)this.trackedEntity);
|
|
// }
|
|
// else if(this.trackedEntity instanceof EntityXPOrb) {
|
|
// return new SPacketSpawnExperienceOrb((EntityXPOrb)this.trackedEntity);
|
|
// }
|
|
// else if(this.trackedEntity instanceof IObjectData) {
|
|
// packet = new SPacketSpawnObject(this.trackedEntity, ((IObjectData)this.trackedEntity).getPacketData());
|
|
// }
|
|
else {
|
|
return new SPacketSpawnObject(this.trackedEntity);
|
|
}
|
|
// else {
|
|
// throw new IllegalArgumentException("Kann Spawn-Paket für " + this.trackedEntity.getClass() + " nicht erstellen!");
|
|
// }
|
|
|
|
// return packet;
|
|
}
|
|
|
|
public void removeTrackedPlayerSymmetric(EntityNPC playerMP) {
|
|
if(this.trackingPlayers.contains(playerMP)) {
|
|
this.trackingPlayers.remove(playerMP);
|
|
playerMP.connection.removeEntity(this.trackedEntity);
|
|
}
|
|
}
|
|
|
|
public boolean isUpdated() {
|
|
return this.playerEntitiesUpdated;
|
|
}
|
|
}
|