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 trackingPlayers = Sets.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 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 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 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 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; } }