This commit is contained in:
Beaness 2022-08-06 23:38:31 +02:00
parent 762263ebe8
commit 40f1bec4cb
5 changed files with 224 additions and 427 deletions

View File

@ -1,111 +0,0 @@
package com.elevatemc.spigot.visuals;
import net.minecraft.server.*;
import java.util.List;
/*
* This is a custom entity tracker made for the cannoning entities tnt and sand.
* The goal behind this is to reduce packets and logic without hiding entities.
* It may not completely replicate the original behavior, but it should make up
* for that with it's advantages.
* Source: IonSpigot
*/
public class CannonTrackerEntry extends EntityTrackerEntry {
private boolean movingX;
private boolean movingY;
private boolean movingZ;
private double updateX;
private double updateY;
private double updateZ;
public CannonTrackerEntry(Entity entity, int i, int j, boolean flag) {
super(entity, i, j, flag);
this.movingX = entity.motX != 0.0;
this.movingY = true;
this.movingZ = entity.motZ != 0.0;
this.updateX = entity.locX;
this.updateY = entity.locY;
this.updateZ = entity.locZ;
}
@Override
public void track(List<EntityHuman> list) {
boolean motionX = this.tracker.motX != 0.0;
boolean motionY = this.tracker.motY != 0.0;
boolean motionZ = this.tracker.motZ != 0.0;
// This tracked entities motion has changed or an explosion has occurred, update it!
if (!this.tracker.ai && motionX == movingX && motionY == movingY && motionZ == movingZ) {
return;
}
// This entity has moved 4 blocks since the last update, search for players
if (this.tracker.e(updateX, updateY, updateZ) > 16.0D) {
this.scanPlayers(list);
this.updateX = this.tracker.locX;
this.updateY = this.tracker.locY;
this.updateZ = this.tracker.locZ;
}
// Update nearby players, only resynchronise when motion is updated
if (motionX || motionY || motionZ) {
this.broadcastUpdate();
}
// Keep what of which axis the entity is moving on
this.tracker.ai = false;
this.movingX = motionX;
this.movingY = motionY;
this.movingZ = motionZ;
}
private void broadcastUpdate() {
DataWatcher datawatcher = this.tracker.getDataWatcher();
if (datawatcher.a()) {
this.broadcastIncludingSelf(new PacketPlayOutEntityMetadata(this.tracker.getId(), datawatcher, false));
}
// Only update location on movement
if (this.tracker.lastX != this.tracker.locX || this.tracker.lastY != this.tracker.locY || this.tracker.lastZ != this.tracker.locZ) {
this.broadcast(new PacketPlayOutEntityTeleport(this.tracker));
}
this.broadcast(new PacketPlayOutEntityVelocity(this.tracker));
}
@Override
public void updatePlayer(EntityPlayer entityplayer) {
// Check configurable distance as a cube then visible distance.
if (this.c(entityplayer) && this.tracker.h(entityplayer) < 4096.0D) {
if (this.trackedPlayers.contains(entityplayer) || (!this.e(entityplayer) && !this.tracker.attachedToPlayer)) {
return;
}
entityplayer.removeQueue.remove(this.tracker.getId());
this.trackedPlayerMap.put(entityplayer, true); // Paper
Packet packet = this.c(); // IonSpigot
if (packet == null) return; // IonSpigot - If it's null don't update the client!
entityplayer.playerConnection.sendPacket(packet);
if (this.tracker.getCustomNameVisible()) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityMetadata(this.tracker.getId(), this.tracker.getDataWatcher(), true));
}
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityVelocity(this.tracker.getId(), this.tracker.motX, this.tracker.motY, this.tracker.motZ));
if (this.tracker.vehicle != null) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutAttachEntity(0, this.tracker, this.tracker.vehicle));
}
} else if (this.trackedPlayers.contains(entityplayer)) {
this.trackedPlayers.remove(entityplayer);
entityplayer.d(this.tracker);
}
}
}

View File

@ -247,75 +247,54 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
}
if (!this.chunkCoordIntPairQueue.isEmpty()) {
ArrayList<Chunk> chunkList = Lists.newArrayList();
Iterator<ChunkCoordIntPair> chunksToLoad = this.chunkCoordIntPairQueue.iterator();
ArrayList<TileEntity> tileEntities = Lists.newArrayList();
ArrayList arraylist = Lists.newArrayList();
Iterator iterator1 = this.chunkCoordIntPairQueue.iterator();
ArrayList arraylist1 = Lists.newArrayList();
Chunk chunk = null;
Chunk chunk;
while (chunksToLoad.hasNext() && chunkList.size() < this.world.spigotConfig.maxBulkChunk) { // Spigot
ChunkCoordIntPair chunkcoordintpair = chunksToLoad.next();
while (iterator1.hasNext() && arraylist.size() < this.world.spigotConfig.maxBulkChunk) { // Spigot
ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator1.next();
if (chunkcoordintpair != null) {
if (this.world.isLoaded(chunkcoordintpair.x << 4, 0, chunkcoordintpair.z << 4)) {// [Nacho-0024] Do not create new BlockPosition when loading chunk
if (this.world.isLoaded(new BlockPosition(chunkcoordintpair.x << 4, 0, chunkcoordintpair.z << 4))) {
chunk = this.world.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z);
if (chunk.isReady()) {
chunkList.add(chunk);
tileEntities.addAll(chunk.tileEntities.values()); // CraftBukkit - Get tile entities directly from the chunk instead of the world
chunksToLoad.remove();
arraylist.add(chunk);
arraylist1.addAll(chunk.tileEntities.values()); // CraftBukkit - Get tile entities directly from the chunk instead of the world
iterator1.remove();
}
}
} else {
chunksToLoad.remove();
iterator1.remove();
}
}
if (!chunkList.isEmpty()) {
if (chunkList.size() == 1) {
this.playerConnection.sendPacket(new PacketPlayOutMapChunk(chunkList.get(0), true, '\uffff'));
if (!arraylist.isEmpty()) {
if (arraylist.size() == 1) {
this.playerConnection.sendPacket(new PacketPlayOutMapChunk((Chunk) arraylist.get(0), true, '\uffff'));
} else {
this.playerConnection.sendPacket(new PacketPlayOutMapChunkBulk(chunkList));
this.playerConnection.sendPacket(new PacketPlayOutMapChunkBulk(arraylist));
}
Iterator<TileEntity> tileEntitiesIterator = tileEntities.iterator();
Iterator iterator2 = arraylist1.iterator();
while (tileEntitiesIterator.hasNext()) {
TileEntity tileentity = tileEntitiesIterator.next();
while (iterator2.hasNext()) {
TileEntity tileentity = (TileEntity) iterator2.next();
this.a(tileentity);
}
// //Nacho - if there are a lot of entities, we end up scanning the WHOLE list of entities multiple times
// // Which isn't the best if we have 100 players doing that
// So instead of updating all entities by chunk, we update all entities at once with a hashset of chunks
// This means we don't have to pass over the list x chunks
// o(chunk * entityList) => o(entitylist)
iterator2 = arraylist.iterator();
// Iterator<Chunk> chunkIterator = chunkList.iterator();
// while (chunkIterator.hasNext())
// {
// chunk = (Chunk) chunkIterator.next();
// this.u().getTracker().a(this, chunk);
// }
// Nacho - end
LongOpenHashSet chunkPosSet = new LongOpenHashSet(chunkList.size());
for (Chunk newChunk : chunkList)
chunkPosSet.add(this.chunkToLong(newChunk.locX, newChunk.locZ));
Iterator<EntityTrackerEntry> trackerEntryIterator = this.u().getTracker().getEntityTrackerEntries();
while (trackerEntryIterator.hasNext())
{
EntityTrackerEntry entitytrackerentry = trackerEntryIterator.next();
if (entitytrackerentry.tracker != this && chunkPosSet.contains(this.chunkToLong(entitytrackerentry.tracker.ae, entitytrackerentry.tracker.ag)))
{
entitytrackerentry.updatePlayer(this);
}
while (iterator2.hasNext()) {
chunk = (Chunk) iterator2.next();
this.u().getTracker().a(this, chunk);
}
}
}
Entity entity = this.C();
if (entity != this) {

View File

@ -1,34 +1,21 @@
package net.minecraft.server;
import com.elevatemc.spigot.config.eSpigotConfig;
import com.elevatemc.spigot.visuals.CannonTrackerEntry;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import com.elevatemc.spigot.util.SynchronizedIntHashMap;
import com.elevatemc.spigot.util.task.Task;
import com.elevatemc.spigot.util.task.impl.ThreadTaskExecutor;
public class EntityTracker {
private static final Logger LOGGER = LogManager.getLogger();
private static final ThreadTaskExecutor TASK_EXECUTOR = new ThreadTaskExecutor("EntityTracker");
static {
TASK_EXECUTOR.start();
}
private WorldServer world;
private Set<EntityTrackerEntry> c = Sets.newConcurrentHashSet(); // eSpigot - ConcurrentHashSet
public IntHashMap<EntityTrackerEntry> trackedEntities = new SynchronizedIntHashMap<>(); // eSpigot - Thread safe implementation of IntHashMap (SynchronizedIntHashMap)
private static final Logger a = LogManager.getLogger();
private final WorldServer world;
private Set<EntityTrackerEntry> c = Sets.newConcurrentHashSet();
public IntHashMap<EntityTrackerEntry> trackedEntities = new IntHashMap();
private int e;
public EntityTracker(WorldServer worldserver) {
@ -39,6 +26,16 @@ public class EntityTracker {
public void track(Entity entity) {
if (entity instanceof EntityPlayer) {
this.addEntity(entity, 512, 2);
EntityPlayer entityplayer = (EntityPlayer) entity;
Iterator iterator = this.c.iterator();
while (iterator.hasNext()) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next();
if (entitytrackerentry.tracker != entityplayer) {
entitytrackerentry.updatePlayerFor(entityplayer);
}
}
} else if (entity instanceof EntityFishingHook) {
this.addEntity(entity, 64, 5, true);
} else if (entity instanceof EntityArrow) {
@ -98,34 +95,28 @@ public class EntityTracker {
}
public void addEntity(Entity entity, int i, final int j, boolean flag) {
org.spigotmc.AsyncCatcher.catchOp( "entity track"); // Spigot
i = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, i); // Spigot
if (i > this.e) {
i = this.e;
}
if (this.trackedEntities.b(entity.getId())) { // IntHashMap already contains entity id
try {
if (this.trackedEntities.b(entity.getId())) {
throw new IllegalStateException("Entity is already tracked!");
}
final int finalI = i; // CraftBukkit - fix decompile error
EntityTrackerEntry entitytrackerentry = new EntityTrackerEntry(entity, i, j, flag);
EntityTrackerEntry entitytrackerentry = createTracker(entity, i, j, flag); // IonSpigot
// We want to add them to these collections directly to ensure compatibility with plugins like Citizens
this.c.add(entitytrackerentry); // Add entity to entity tracker entries set
this.trackedEntities.a(entity.getId(), entitytrackerentry); // Add entity to trackedEntities collection
TASK_EXECUTOR.submit(executor -> {
try {
entitytrackerentry.scanPlayers(this.world.players); // Update all players in world,
// essentially the only method that would
// be heavy in this method is this method (EntityTrackerEntry#scanPlayers)
this.c.add(entitytrackerentry);
this.trackedEntities.a(entity.getId(), entitytrackerentry);
entitytrackerentry.scanPlayers(this.world.players);
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Adding entity to track");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity To Track");
crashreportsystemdetails.a("Tracking range", finalI + " blocks");
crashreportsystemdetails.a("Tracking range", (Object) (i + " blocks"));
final int finalI = i; // CraftBukkit - fix decompile error
crashreportsystemdetails.a("Update interval", new Callable() {
public String a() throws Exception {
String s = "Once per " + finalI + " ticks"; // CraftBukkit
@ -144,158 +135,121 @@ public class EntityTracker {
entity.appendEntityCrashDetails(crashreportsystemdetails);
CrashReportSystemDetails crashreportsystemdetails1 = crashreport.a("Entity That Is Already Tracked");
this.trackedEntities.get(entity.getId()).tracker.appendEntityCrashDetails(crashreportsystemdetails1);
((EntityTrackerEntry) this.trackedEntities.get(entity.getId())).tracker.appendEntityCrashDetails(crashreportsystemdetails1);
try {
throw new ReportedException(crashreport);
} catch (ReportedException reportedexception) {
EntityTracker.LOGGER.error("\"Silently\" catching entity tracking error.", reportedexception);
EntityTracker.a.error("\"Silently\" catching entity tracking error.", reportedexception);
}
}
});
}
// IonSpigot start
private EntityTrackerEntry createTracker(Entity entity, int i, int j, boolean flag) {
if (entity.isCannoningEntity && eSpigotConfig.cannonTracker) {
return new CannonTrackerEntry(entity, i, j, flag);
} else {
return new EntityTrackerEntry(entity, i, j, flag);
}
}
// IonSpigot end
public void untrackEntity(Entity entity) {
//org.spigotmc.AsyncCatcher.catchOp( "entity untrack"); // Spigot
boolean mainThread = Thread.currentThread() == MinecraftServer.getServer().primaryThread;
org.spigotmc.AsyncCatcher.catchOp( "entity untrack"); // Spigot
if (entity instanceof EntityPlayer) {
EntityPlayer entityplayer = (EntityPlayer) entity;
// The best way to go around reducing load on this method is by fully doing the iteration asynchronously
// We honestly don't need to handle this asynchronously if the size of the entity tracker entry set
// Iterate through all entity tracker entries
Iterator iterator = this.c.iterator();
if (this.c.size() < 20 || !mainThread)
for (EntityTrackerEntry entitytrackerentry : this.c)
entitytrackerentry.a(entityplayer); // Untrack entity
else {
TASK_EXECUTOR.submit(executor ->
{for(EntityTrackerEntry entityTrackerEntry : this.c){entityTrackerEntry.a(entityplayer);}});
while (iterator.hasNext()) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next();
entitytrackerentry.a(entityplayer);
}
}
EntityTrackerEntry entitytrackerentry1 = this.trackedEntities.d(entity.getId());
EntityTrackerEntry entitytrackerentry1 = (EntityTrackerEntry) this.trackedEntities.d(entity.getId());
if (entitytrackerentry1 != null) {
this.c.remove(entitytrackerentry1);
TASK_EXECUTOR.submit(executor -> entitytrackerentry1.a());
}
entitytrackerentry1.a();
}
private final Task updatePlayerTask = executor -> {
List<Entity> pending = Lists.newArrayList();
// Iterate through all entitytracker entries
for (EntityTrackerEntry entitytrackerentry : this.c) {
entitytrackerentry.track(this.world.players); // Ensure you're tracking them
if (entitytrackerentry.n && entitytrackerentry.tracker instanceof EntityPlayer) {
pending.add(entitytrackerentry.tracker);
}
}
for (Object o : pending) {
EntityPlayer entityplayer = (EntityPlayer) o;
for (EntityTrackerEntry entitytrackerentry1 : this.c) {
if (entitytrackerentry1.tracker != entityplayer) {
entitytrackerentry1.updatePlayer(entityplayer);
}
}
}
};
public void updatePlayers() {
if (Bukkit.isPrimaryThread())
TASK_EXECUTOR.submit(updatePlayerTask);
else updatePlayerTask.onExecute(null); // It's already being ran async so no need to make sure it runs on a separate thread
ArrayList arraylist = Lists.newArrayList();
Iterator iterator = this.c.iterator();
while (iterator.hasNext()) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next();
entitytrackerentry.track(this.world.players);
if (entitytrackerentry.n && entitytrackerentry.tracker instanceof EntityPlayer) {
arraylist.add(entitytrackerentry.tracker);
}
}
// Force update
public void a(EntityPlayer entityplayer) {
boolean mainThread = Thread.currentThread() == MinecraftServer.getServer().primaryThread;
for (int i = 0; i < arraylist.size(); ++i) {
EntityPlayer entityplayer = (EntityPlayer) arraylist.get(i);
Iterator iterator1 = this.c.iterator();
while (iterator1.hasNext()) {
EntityTrackerEntry entitytrackerentry1 = (EntityTrackerEntry) iterator1.next();
if (entitytrackerentry1.tracker != entityplayer) {
entitytrackerentry1.updatePlayerFor(entityplayer);
}
}
}
}
public void a(EntityPlayer entityplayer) {
Iterator iterator = this.c.iterator();
while (iterator.hasNext()) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next();
Task task = executor -> {
for (EntityTrackerEntry entitytrackerentry : this.c) {
if (entitytrackerentry.tracker == entityplayer) {
entitytrackerentry.scanPlayers(this.world.players);
} else {
entitytrackerentry.updatePlayer(entityplayer);
entitytrackerentry.updatePlayerFor(entityplayer);
}
}
};
if (!mainThread)
task.onExecute(null);
else TASK_EXECUTOR.submit(task);
}
public void a(Entity entity, Packet<?> packet) {
// The packets being passed onto this method generally don't tend to make gameplay less smooth if it takes a 10L delay, so we can submit them to our TaskExecutor
Task task = executor -> {
EntityTrackerEntry entitytrackerentry = this.trackedEntities.get(entity.getId());
}
public void a(Entity entity, Packet packet) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.trackedEntities.get(entity.getId());
if (entitytrackerentry != null) {
entitytrackerentry.broadcast(packet);
}
};
if (!Bukkit.isPrimaryThread())
task.onExecute(null);
else TASK_EXECUTOR.submit(task);
}
public void sendPacketToEntity(Entity entity, Packet<?> packet) { /* Used for entity animations & entity status packets, same reasoning for async as EntityTracker#a(Entity, Packet) method */
Task task = executor -> {
EntityTrackerEntry entitytrackerentry = this.trackedEntities.get(entity.getId());
public void sendPacketToEntity(Entity entity, Packet packet) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.trackedEntities.get(entity.getId());
if (entitytrackerentry != null)
if (entitytrackerentry != null) {
entitytrackerentry.broadcastIncludingSelf(packet);
};
}
if (!Bukkit.isPrimaryThread())
task.onExecute(null);
else TASK_EXECUTOR.submit(task);
}
public void untrackPlayer(EntityPlayer entityplayer) {
Task task = executor -> {
for (EntityTrackerEntry entitytrackerentry : this.c)
entitytrackerentry.clear(entityplayer);
};
Iterator iterator = this.c.iterator();
if (!Bukkit.isPrimaryThread())
task.onExecute(null);
else TASK_EXECUTOR.submit(task);
while (iterator.hasNext()) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next();
entitytrackerentry.clear(entityplayer);
}
public Iterator<EntityTrackerEntry> getEntityTrackerEntries()
{
return this.c.iterator();
}
public void a(EntityPlayer entityplayer, Chunk chunk) {
Task task = executor -> {
for (EntityTrackerEntry entitytrackerentry : this.c) {
if (entitytrackerentry.tracker != entityplayer
&& entitytrackerentry.tracker.ae == chunk.locX
&& entitytrackerentry.tracker.ag == chunk.locZ) {
entitytrackerentry.updatePlayer(entityplayer);
}
}
};
Iterator iterator = this.c.iterator();
while (iterator.hasNext()) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next();
if (entitytrackerentry.tracker != entityplayer && entitytrackerentry.tracker.ae == chunk.locX && entitytrackerentry.tracker.ag == chunk.locZ) {
entitytrackerentry.updatePlayerFor(entityplayer);
}
}
if (!Bukkit.isPrimaryThread())
task.onExecute(null);
else TASK_EXECUTOR.submit(task);
}
}

View File

@ -1,15 +1,14 @@
package net.minecraft.server;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerVelocityEvent;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import com.elevatemc.spigot.config.eSpigotConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
// CraftBukkit start
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerVelocityEvent;
// CraftBukkit end
public class EntityTrackerEntry {
@ -41,7 +40,7 @@ public class EntityTrackerEntry {
// PaperSpigot start
// Replace trackedPlayers Set with a Map. The value is true until the player receives
// their first update (which is forced to have absolute coordinates), false afterward.
public java.util.Map<EntityPlayer, Boolean> trackedPlayerMap = new ConcurrentHashMap<>(); // eSpigot - ConcurrentHashMap
public java.util.Map<EntityPlayer, Boolean> trackedPlayerMap = new ConcurrentHashMap<>();
public Set<EntityPlayer> trackedPlayers = trackedPlayerMap.keySet();
// PaperSpigot end
@ -60,7 +59,7 @@ public class EntityTrackerEntry {
}
public boolean equals(Object object) {
return object instanceof EntityTrackerEntry && ((EntityTrackerEntry) object).tracker.getId() == this.tracker.getId();
return object instanceof EntityTrackerEntry ? ((EntityTrackerEntry) object).tracker.getId() == this.tracker.getId() : false;
}
public int hashCode() {
@ -83,16 +82,17 @@ public class EntityTrackerEntry {
this.broadcast(new PacketPlayOutAttachEntity(0, this.tracker, this.tracker.vehicle));
}
if (this.tracker instanceof EntityItemFrame && this.m % 20 == 0) { // Paper
if (this.tracker instanceof EntityItemFrame /*&& this.m % 10 == 0*/) { // CraftBukkit - Moved below, should always enter this block
EntityItemFrame entityitemframe = (EntityItemFrame) this.tracker;
ItemStack itemstack = entityitemframe.getItem();
if (itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { // Paper - moved back up
if (this.m % 10 == 0 && itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { // CraftBukkit - Moved this.m % 10 logic here so item frames do not enter the other blocks
WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, this.tracker.world);
// CraftBukkit
Iterator iterator = this.trackedPlayers.iterator(); // CraftBukkit
for (EntityPlayer trackedPlayer : this.trackedPlayers) {
EntityPlayer entityplayer = trackedPlayer;
while (iterator.hasNext()) {
EntityHuman entityhuman = (EntityHuman) iterator.next();
EntityPlayer entityplayer = (EntityPlayer) entityhuman;
worldmap.a(entityplayer, itemstack);
Packet packet = Items.FILLED_MAP.c(itemstack, this.tracker.world, entityplayer);
@ -112,16 +112,17 @@ public class EntityTrackerEntry {
if (this.tracker.vehicle == null) {
++this.v;
i = MathHelper.floor(this.tracker.locX * 32.0D);
i = MathHelper.floor((this.tracker.locX) * 32.0D);
j = MathHelper.floor(this.tracker.locY * 32.0D);
int k = MathHelper.floor(this.tracker.locZ * 32.0D);
int k = MathHelper.floor((this.tracker.locZ) * 32.0D);
int l = MathHelper.d(this.tracker.yaw * 256.0F / 360.0F);
int i1 = MathHelper.d(this.tracker.pitch * 256.0F / 360.0F);
//System.out.println(String.format("%s, %s, %s", this.tracker.locX, this.tracker.locY, this.tracker.locZ));
int j1 = i - this.xLoc;
int k1 = j - this.yLoc;
int l1 = k - this.zLoc;
Object object = null;
boolean flag = Math.abs(j1) >= 4 || Math.abs(k1) >= 4 || Math.abs(l1) >= 4 || this.m % 60 == 0;
boolean flag = Math.abs(j1) >= 2 || Math.abs(k1) >= 2 || Math.abs(l1) >= 2;
boolean flag1 = Math.abs(l - this.yRot) >= 4 || Math.abs(i1 - this.xRot) >= 4;
if (this.m > 0 || this.tracker instanceof EntityArrow) { // PaperSpigot - Moved up
@ -138,7 +139,9 @@ public class EntityTrackerEntry {
}
// CraftBukkit end
if (j1 >= -128 && j1 < 128 && k1 >= -128 && k1 < 128 && l1 >= -128 && l1 < 128 && this.v <= 100 && !this.x && this.y == this.tracker.onGround) { // Kohi - greatly reduce forced teleport interval - 400 -> 100
if (!(j1 == 0 && k1 == 0 && l1 == 0 && !flag1)) {
if (j1 >= -128 && j1 < 128 && k1 >= -128 && k1 < 128 && l1 >= -128 && l1 < 128 && this.v <= 5 && !this.x && this.y == this.tracker.onGround) {
if ((!flag || !flag1) && !(this.tracker instanceof EntityArrow)) {
if (flag) {
object = new PacketPlayOutEntity.PacketPlayOutRelEntityMove(this.tracker.getId(), (byte) j1, (byte) k1, (byte) l1, this.tracker.onGround);
@ -153,13 +156,13 @@ public class EntityTrackerEntry {
this.v = 0;
// CraftBukkit start - Refresh list of who can see a player before sending teleport packet
if (this.tracker instanceof EntityPlayer) {
// SportPaper - Fix invisibility on teleport
this.scanPlayers(new ArrayList<EntityHuman>(this.tracker.world.players));
this.scanPlayers(new ArrayList<>(this.trackedPlayers));
}
// CraftBukkit end
object = new PacketPlayOutEntityTeleport(this.tracker.getId(), i, j, k, (byte) l, (byte) i1, this.tracker.onGround);
}
}
}
if (this.u) {
double d0 = this.tracker.motX - this.j;
@ -261,11 +264,7 @@ public class EntityTrackerEntry {
}
if (!cancelled) {
if (this.tracker instanceof EntityPlayer) {
((EntityPlayer) this.tracker).playerConnection.sendPacket(new PacketPlayOutEntityVelocity(this.tracker));
} else if (this.tracker instanceof EntityArrow || this.tracker instanceof EntityProjectile) {
this.broadcast(new PacketPlayOutEntityVelocity(this.tracker));
}
this.broadcastIncludingSelf(new PacketPlayOutEntityVelocity(this.tracker));
}
// CraftBukkit end
this.tracker.velocityChanged = false;
@ -277,51 +276,20 @@ public class EntityTrackerEntry {
DataWatcher datawatcher = this.tracker.getDataWatcher();
if (datawatcher.a()) {
if (eSpigotConfig.obfuscatePlayerHealth && this.tracker instanceof EntityHuman) {
List<DataWatcher.WatchableObject> changedMetadata = datawatcher.c();
Iterator<DataWatcher.WatchableObject> iter = changedMetadata.iterator();
boolean found = false;
while (iter.hasNext()) {
DataWatcher.WatchableObject watchable = iter.next();
if (watchable.a() == 6) {
iter.remove();
found = true;
}
}
if (found) {
changedMetadata.add(new DataWatcher.WatchableObject(3, 6, 1.0F));
}
PacketPlayOutEntityMetadata modifiedPacket = new PacketPlayOutEntityMetadata(this.tracker.getId(), changedMetadata);
// Beanes - Broadcast the modified metadata packet to everyone and send the correct packet to the player
this.broadcast(modifiedPacket);
if (this.tracker instanceof EntityPlayer)
((EntityPlayer) this.tracker).playerConnection.sendPacket(new PacketPlayOutEntityMetadata(this.tracker.getId(), datawatcher, false));
} else {
this.broadcastIncludingSelf(new PacketPlayOutEntityMetadata(this.tracker.getId(), datawatcher, false));
}
}
if (this.tracker instanceof EntityLiving) {
AttributeMapServer attributemapserver = (AttributeMapServer) ((EntityLiving) this.tracker).getAttributeMap();
Set<AttributeInstance> set = attributemapserver.getAttributes();
Set set = attributemapserver.getAttributes();
if (!set.isEmpty()) {
// CraftBukkit start - Send scaled max health
if (this.tracker instanceof EntityPlayer) {
((EntityPlayer) this.tracker).getBukkitEntity().injectScaledMaxHealth(set, false);
((EntityPlayer) this.tracker).playerConnection.sendPacket(new PacketPlayOutUpdateAttributes(this.tracker.getId(), set)); // MineHQ
}
// CraftBukkit end
// MineHQ start
// this.broadcastIncludingSelf(new PacketPlayOutUpdateAttributes(this.tracker.getId(), set)); // CraftBukkit
if (this.tracker.passenger instanceof EntityPlayer) {
((EntityPlayer) this.tracker.passenger).playerConnection.sendPacket(new PacketPlayOutUpdateAttributes(this.tracker.getId(), set));
}
// MineHQ end
this.broadcastIncludingSelf(new PacketPlayOutUpdateAttributes(this.tracker.getId(), set));
}
set.clear();
@ -330,25 +298,35 @@ public class EntityTrackerEntry {
}
public void broadcast(Packet packet) {
for (EntityPlayer entityplayer : this.trackedPlayers)
Iterator iterator = this.trackedPlayers.iterator();
while (iterator.hasNext()) {
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
entityplayer.playerConnection.sendPacket(packet);
}
}
public void broadcastIncludingSelf(Packet packet) {
this.broadcast(packet);
if (this.tracker instanceof EntityPlayer)
if (this.tracker instanceof EntityPlayer) {
((EntityPlayer) this.tracker).playerConnection.sendPacket(packet);
}
public void a() {
}
public void a() {
Iterator iterator = this.trackedPlayers.iterator();
while (iterator.hasNext()) {
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
for (EntityPlayer entityplayer : this.trackedPlayers) {
entityplayer.d(this.tracker);
}
}
// Untrack entity
public void a(EntityPlayer entityplayer) {
if (this.trackedPlayers.contains(entityplayer)) {
entityplayer.d(this.tracker);
@ -357,7 +335,8 @@ public class EntityTrackerEntry {
}
public void updatePlayer(EntityPlayer entityplayer) {
public void updatePlayerFor(EntityPlayer entityplayer) {
org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
if (entityplayer != this.tracker) {
if (this.c(entityplayer)) {
if (!this.trackedPlayers.contains(entityplayer) && (this.e(entityplayer) || this.tracker.attachedToPlayer)) {
@ -385,8 +364,6 @@ public class EntityTrackerEntry {
entityplayer.playerConnection.sendPacket(new PacketPlayOutUpdateEntityNBT(this.tracker.getId(), nbttagcompound));
}
// MineHQ start
/*
if (this.tracker instanceof EntityLiving) {
AttributeMapServer attributemapserver = (AttributeMapServer) ((EntityLiving) this.tracker).getAttributeMap();
Collection collection = attributemapserver.c();
@ -401,8 +378,6 @@ public class EntityTrackerEntry {
entityplayer.playerConnection.sendPacket(new PacketPlayOutUpdateAttributes(this.tracker.getId(), collection));
}
}
*/
// MineHQ end
this.j = this.tracker.motX;
this.k = this.tracker.motY;
@ -438,22 +413,17 @@ public class EntityTrackerEntry {
}
// CraftBukkit start - Fix for nonsensical head yaw
if(this.tracker instanceof EntityLiving) { // SportPaper - avoid processing entities that can't change head rotation
this.i = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F);
// SportPaper start
// This was originally introduced by CraftBukkit, though the implementation is wrong since it's broadcasting
// the packet again in a method that is already called for each player. This would create a very serious performance issue
// with high player and entity counts (each sendPacket call involves waking up the event loop and flushing the network stream).
// this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i));
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i));
// SportPaper end
}
this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i));
// CraftBukkit end
if (this.tracker instanceof EntityLiving) {
EntityLiving entityliving = (EntityLiving) this.tracker;
Iterator iterator = entityliving.getEffects().iterator();
while (iterator.hasNext()) {
MobEffect mobeffect = (MobEffect) iterator.next();
for (MobEffect mobeffect : entityliving.getEffects()) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityEffect(this.tracker.getId(), mobeffect));
}
}
@ -475,17 +445,18 @@ public class EntityTrackerEntry {
return d0 >= (double) (-this.b) && d0 <= (double) this.b && d1 >= (double) (-this.b) && d1 <= (double) this.b && this.tracker.a(entityplayer);
}
protected boolean e(EntityPlayer entityplayer) { // IonSpigot - private -> protected
private boolean e(EntityPlayer entityplayer) {
return entityplayer.u().getPlayerChunkMap().a(entityplayer, this.tracker.ae, this.tracker.ag);
}
public void scanPlayers(List<EntityHuman> list) {
for (EntityHuman entityHuman : list) {
this.updatePlayer((EntityPlayer) entityHuman);
}
for (int i = 0; i < list.size(); ++i) {
this.updatePlayerFor((EntityPlayer) list.get(i));
}
protected Packet c() {
}
private Packet c() {
if (this.tracker.dead) {
// CraftBukkit start - Remove useless error spam, just return
// EntityTrackerEntry.p.warn("Fetching addPacket for removed entity");
@ -596,7 +567,11 @@ public class EntityTrackerEntry {
}
public void clear(EntityPlayer entityplayer) {
if (this.trackedPlayers.remove(entityplayer)) // eSpigot - Directly remove
org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot
if (this.trackedPlayers.contains(entityplayer)) {
this.trackedPlayers.remove(entityplayer);
entityplayer.d(this.tracker);
}
}
}

View File

@ -1027,9 +1027,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
if (!eSpigotConfig.showHiddenPlayersInTab)
getHandle().playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, other));
EntityTrackerEntry entry = tracker.trackedEntities.get(other.getId());
EntityTrackerEntry entry = (EntityTrackerEntry) tracker.trackedEntities.get(other.getId());
if (entry != null && !entry.trackedPlayers.contains(getHandle())) {
entry.updatePlayer(getHandle());
entry.updatePlayerFor(getHandle());
}
}