Paper/nms-patches/Entity.patch
Pokechu22 4d3bf20155 Re-enable the vanilla debug MethodProfiler and /debug command
This is highly useful for profiling vanilla code, and in some cases plugin code.  It is somewhat expensive, though, which is why it was initially disabled.

I chose to use a system property instead of a configuration setting because 1) the MethodProfiler is exclusive to CraftBukkit and not part of the general API (the timings system is the general API equivalent), and 2) using a static final boolean property _may_ allow the JITter to optimize out the methods when disabled (though I'm not sure of it).

There are several changes to fix cases where the profiler code was broken slightly by other craftbukkit changes.  All of cases have been fixed, except for the block entity ticking one, due to the cost of the getSimpleName call.  For that, a ticking entry is used instead, so that time spent actually ticking the block entities can be compared with time processing the list.

This (effectively) reverts 7dde6cc566.
2017-01-18 17:42:35 -08:00

655 lines
28 KiB
Diff

--- a/net/minecraft/server/Entity.java
+++ b/net/minecraft/server/Entity.java
@@ -16,8 +16,48 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+// CraftBukkit start
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Server;
+import org.bukkit.TravelAgent;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Hanging;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Vehicle;
+import org.bukkit.event.entity.EntityCombustByEntityEvent;
+import org.bukkit.event.hanging.HangingBreakByEntityEvent;
+import org.bukkit.event.vehicle.VehicleBlockCollisionEvent;
+import org.bukkit.event.vehicle.VehicleEnterEvent;
+import org.bukkit.event.vehicle.VehicleExitEvent;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftEntity;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityAirChangeEvent;
+import org.bukkit.event.entity.EntityCombustEvent;
+import org.bukkit.event.entity.EntityPortalEvent;
+import org.bukkit.plugin.PluginManager;
+// CraftBukkit end
+
public abstract class Entity implements ICommandListener {
+ // CraftBukkit start
+ private static final int CURRENT_LEVEL = 2;
+ static boolean isLevelAtLeast(NBTTagCompound tag, int level) {
+ return tag.hasKey("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
+ }
+
+ protected CraftEntity bukkitEntity;
+
+ public CraftEntity getBukkitEntity() {
+ if (bukkitEntity == null) {
+ bukkitEntity = CraftEntity.getEntity(world.getServer(), this);
+ }
+ return bukkitEntity;
+ }
+ // CraftBukikt end
+
private static final Logger a = LogManager.getLogger();
private static final List<ItemStack> b = Collections.emptyList();
private static final AxisAlignedBB c = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
@@ -101,6 +141,9 @@
private boolean aH;
private double[] aI;
private long aJ;
+ public boolean valid; // CraftBukkit
+ public org.bukkit.projectiles.ProjectileSource projectileSource; // CraftBukkit - For projectiles only
+ public boolean forceExplosionKnockback; // CraftBukkit - SPIGOT-949
public Entity(World world) {
this.id = Entity.entityCount++;
@@ -206,6 +249,33 @@
}
protected void setYawPitch(float f, float f1) {
+ // CraftBukkit start - yaw was sometimes set to NaN, so we need to set it back to 0
+ if (Float.isNaN(f)) {
+ f = 0;
+ }
+
+ if (f == Float.POSITIVE_INFINITY || f == Float.NEGATIVE_INFINITY) {
+ if (this instanceof EntityPlayer) {
+ this.world.getServer().getLogger().warning(this.getName() + " was caught trying to crash the server with an invalid yaw");
+ ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Nope");
+ }
+ f = 0;
+ }
+
+ // pitch was sometimes set to NaN, so we need to set it back to 0
+ if (Float.isNaN(f1)) {
+ f1 = 0;
+ }
+
+ if (f1 == Float.POSITIVE_INFINITY || f1 == Float.NEGATIVE_INFINITY) {
+ if (this instanceof EntityPlayer) {
+ this.world.getServer().getLogger().warning(this.getName() + " was caught trying to crash the server with an invalid pitch");
+ ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Nope");
+ }
+ f1 = 0;
+ }
+ // CraftBukkit end
+
this.yaw = f % 360.0F;
this.pitch = f1 % 360.0F;
}
@@ -249,7 +319,7 @@
if (this.ak) {
MinecraftServer minecraftserver = this.world.getMinecraftServer();
- if (minecraftserver.getAllowNether()) {
+ if (true || minecraftserver.getAllowNether()) { // CraftBukkit
if (!this.isPassenger()) {
int i = this.V();
@@ -334,6 +404,27 @@
protected void burnFromLava() {
if (!this.fireProof) {
this.damageEntity(DamageSource.LAVA, 4.0F);
+
+ // CraftBukkit start - Fallen in lava TODO: this event spams!
+ if (this instanceof EntityLiving) {
+ if (fireTicks <= 0) {
+ // not on fire yet
+ // TODO: shouldn't be sending null for the block
+ org.bukkit.block.Block damager = null; // ((WorldServer) this.l).getWorld().getBlockAt(i, j, k);
+ org.bukkit.entity.Entity damagee = this.getBukkitEntity();
+ EntityCombustEvent combustEvent = new org.bukkit.event.entity.EntityCombustByBlockEvent(damager, damagee, 15);
+ this.world.getServer().getPluginManager().callEvent(combustEvent);
+
+ if (!combustEvent.isCancelled()) {
+ this.setOnFire(combustEvent.getDuration());
+ }
+ } else {
+ // This will be called every single tick the entity is in lava, so don't throw an event
+ this.setOnFire(15);
+ }
+ return;
+ }
+ // CraftBukkit end - we also don't throw an event unless the object in lava is living, to save on some event calls
this.setOnFire(15);
}
}
@@ -374,6 +465,22 @@
this.a(this.getBoundingBox().d(d0, d1, d2));
this.recalcPosition();
} else {
+ // CraftBukkit start - Don't do anything if we aren't moving
+ // We need to do this regardless of whether or not we are moving thanks to portals
+ try {
+ this.checkBlockCollisions();
+ } catch (Throwable throwable) {
+ CrashReport crashreport = CrashReport.a(throwable, "Checking entity block collision");
+ CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being checked for collision");
+
+ this.appendEntityCrashDetails(crashreportsystemdetails);
+ throw new ReportedException(crashreport);
+ }
+ // Check if we're moving
+ if (d0 == 0 && d1 == 0 && d2 == 0 && this.isVehicle() && this.isPassenger()) {
+ return;
+ }
+ // CraftBukkit end
if (enummovetype == EnumMoveType.PISTON) {
long i = this.world.getTime();
@@ -515,7 +622,7 @@
}
}
- boolean flag = this.onGround || d1 != d1 && d1 < 0.0D;
+ boolean flag = this.onGround || d1 != d8 && d1 < 0.0D; // CraftBukkit - decompile error
double d11;
if (this.P > 0.0F && flag && (d7 != d0 || d9 != d2)) {
@@ -613,7 +720,7 @@
this.world.methodProfiler.a("rest");
this.recalcPosition();
this.positionChanged = d7 != d0 || d9 != d2;
- this.B = d1 != d1;
+ this.B = d1 != d8; // CraftBukkit - decompile error
this.onGround = this.B && d8 < 0.0D;
this.C = this.positionChanged || this.B;
l = MathHelper.floor(this.locX);
@@ -648,6 +755,28 @@
block1.a(this.world, this);
}
+ // CraftBukkit start
+ if (positionChanged && getBukkitEntity() instanceof Vehicle) {
+ Vehicle vehicle = (Vehicle) this.getBukkitEntity();
+ org.bukkit.block.Block bl = this.world.getWorld().getBlockAt(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ));
+
+ if (d6 > d0) {
+ bl = bl.getRelative(BlockFace.EAST);
+ } else if (d6 < d0) {
+ bl = bl.getRelative(BlockFace.WEST);
+ } else if (d8 > d2) {
+ bl = bl.getRelative(BlockFace.SOUTH);
+ } else if (d8 < d2) {
+ bl = bl.getRelative(BlockFace.NORTH);
+ }
+
+ if (bl.getType() != org.bukkit.Material.AIR) {
+ VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl);
+ world.getServer().getPluginManager().callEvent(event);
+ }
+ }
+ // CraftBukkit end
+
if (this.playStepSound() && (!this.onGround || !this.isSneaking() || !(this instanceof EntityHuman)) && !this.isPassenger()) {
double d22 = this.locX - d4;
double d23 = this.locY - d5;
@@ -681,6 +810,8 @@
}
}
+ // CraftBukkit start - Move to the top of the method
+ /*
try {
this.checkBlockCollisions();
} catch (Throwable throwable) {
@@ -690,6 +821,8 @@
this.appendEntityCrashDetails(crashreportsystemdetails);
throw new ReportedException(crashreport);
}
+ */
+ // CraftBukkit end
boolean flag1 = this.ai();
@@ -698,7 +831,14 @@
if (!flag1) {
++this.fireTicks;
if (this.fireTicks == 0) {
- this.setOnFire(8);
+ // CraftBukkit start
+ EntityCombustEvent event = new org.bukkit.event.entity.EntityCombustByBlockEvent(null, getBukkitEntity(), 8);
+ world.getServer().getPluginManager().callEvent(event);
+
+ if (!event.isCancelled()) {
+ this.setOnFire(event.getDuration());
+ }
+ // CraftBukkit end
}
}
} else if (this.fireTicks <= 0) {
@@ -819,7 +959,7 @@
return null;
}
- protected void burn(int i) {
+ protected void burn(float i) { // CraftBukkit - int -> float
if (!this.fireProof) {
this.damageEntity(DamageSource.FIRE, (float) i);
}
@@ -987,6 +1127,13 @@
}
public void spawnIn(World world) {
+ // CraftBukkit start
+ if (world == null) {
+ die();
+ this.world = ((CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle();
+ return;
+ }
+ // CraftBukkit end
this.world = world;
}
@@ -1219,6 +1366,18 @@
try {
nbttagcompound.set("Pos", this.a(new double[] { this.locX, this.locY, this.locZ}));
nbttagcompound.set("Motion", this.a(new double[] { this.motX, this.motY, this.motZ}));
+
+ // CraftBukkit start - Checking for NaN pitch/yaw and resetting to zero
+ // TODO: make sure this is the best way to address this.
+ if (Float.isNaN(this.yaw)) {
+ this.yaw = 0;
+ }
+
+ if (Float.isNaN(this.pitch)) {
+ this.pitch = 0;
+ }
+ // CraftBukkit end
+
nbttagcompound.set("Rotation", this.a(new float[] { this.yaw, this.pitch}));
nbttagcompound.setFloat("FallDistance", this.fallDistance);
nbttagcompound.setShort("Fire", (short) this.fireTicks);
@@ -1228,6 +1387,12 @@
nbttagcompound.setBoolean("Invulnerable", this.invulnerable);
nbttagcompound.setInt("PortalCooldown", this.portalCooldown);
nbttagcompound.a("UUID", this.getUniqueID());
+ // CraftBukkit start
+ // PAIL: Check above UUID reads 1.8 properly, ie: UUIDMost / UUIDLeast
+ nbttagcompound.setLong("WorldUUIDLeast", this.world.getDataManager().getUUID().getLeastSignificantBits());
+ nbttagcompound.setLong("WorldUUIDMost", this.world.getDataManager().getUUID().getMostSignificantBits());
+ nbttagcompound.setInt("Bukkit.updateLevel", CURRENT_LEVEL);
+ // CraftBukkit end
if (this.hasCustomName()) {
nbttagcompound.setString("CustomName", this.getCustomName());
}
@@ -1303,6 +1468,8 @@
this.motX = nbttaglist1.e(0);
this.motY = nbttaglist1.e(1);
this.motZ = nbttaglist1.e(2);
+
+ /* CraftBukkit start - Moved section down
if (Math.abs(this.motX) > 10.0D) {
this.motX = 0.0D;
}
@@ -1314,6 +1481,7 @@
if (Math.abs(this.motZ) > 10.0D) {
this.motZ = 0.0D;
}
+ // CraftBukkit end */
this.locX = nbttaglist.e(0);
this.locY = nbttaglist.e(1);
@@ -1371,6 +1539,58 @@
this.setPosition(this.locX, this.locY, this.locZ);
}
+ // CraftBukkit start
+ if (this instanceof EntityLiving) {
+ EntityLiving entity = (EntityLiving) this;
+
+ // Reset the persistence for tamed animals
+ if (entity instanceof EntityTameableAnimal && !isLevelAtLeast(nbttagcompound, 2) && !nbttagcompound.getBoolean("PersistenceRequired")) {
+ EntityInsentient entityinsentient = (EntityInsentient) entity;
+ entityinsentient.persistent = !entityinsentient.isTypeNotPersistent();
+ }
+ }
+ // CraftBukkit end
+
+ // CraftBukkit start - Exempt Vehicles from notch's sanity check
+ if (!(getBukkitEntity() instanceof Vehicle)) {
+ if (Math.abs(this.motX) > 10.0D) {
+ this.motX = 0.0D;
+ }
+
+ if (Math.abs(this.motY) > 10.0D) {
+ this.motY = 0.0D;
+ }
+
+ if (Math.abs(this.motZ) > 10.0D) {
+ this.motZ = 0.0D;
+ }
+ }
+ // CraftBukkit end
+
+ // CraftBukkit start - Reset world
+ if (this instanceof EntityPlayer) {
+ Server server = Bukkit.getServer();
+ org.bukkit.World bworld = null;
+
+ // TODO: Remove World related checks, replaced with WorldUID
+ String worldName = nbttagcompound.getString("world");
+
+ if (nbttagcompound.hasKey("WorldUUIDMost") && nbttagcompound.hasKey("WorldUUIDLeast")) {
+ UUID uid = new UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast"));
+ bworld = server.getWorld(uid);
+ } else {
+ bworld = server.getWorld(worldName);
+ }
+
+ if (bworld == null) {
+ EntityPlayer entityPlayer = (EntityPlayer) this;
+ bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(entityPlayer.dimension).getWorld();
+ }
+
+ spawnIn(bworld == null? null : ((CraftWorld) bworld).getHandle());
+ }
+ // CraftBukkit end
+
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Loading entity NBT");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being loaded");
@@ -1438,6 +1658,12 @@
if (itemstack.isEmpty()) {
return null;
} else {
+ // CraftBukkit start - Capture drops for death event
+ if (this instanceof EntityLiving && !((EntityLiving) this).forceDrops) {
+ ((EntityLiving) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack));
+ return null;
+ }
+ // CraftBukkit end
EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY + (double) f, this.locZ, itemstack);
entityitem.q();
@@ -1563,6 +1789,24 @@
if (entity.bB() != this) {
throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)");
} else {
+ // CraftBukkit start
+ com.google.common.base.Preconditions.checkState(!entity.passengers.contains(this), "Circular entity riding! %s %s", this, entity);
+
+ CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle();
+ Entity orig = craft == null ? null : craft.getHandle();
+ if (getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity && entity.world.isChunkLoaded((int) entity.locX >> 4, (int) entity.locZ >> 4, false)) { // Boolean not used
+ VehicleEnterEvent event = new VehicleEnterEvent(
+ (Vehicle) getBukkitEntity(),
+ entity.getBukkitEntity()
+ );
+ Bukkit.getPluginManager().callEvent(event);
+ CraftEntity craftn = (CraftEntity) entity.getBukkitEntity().getVehicle();
+ Entity n = craftn == null ? null : craftn.getHandle();
+ if (event.isCancelled() || n != orig) {
+ return;
+ }
+ }
+ // CraftBukkit end
if (!this.world.isClientSide && entity instanceof EntityHuman && !(this.bw() instanceof EntityHuman)) {
this.passengers.add(0, entity);
} else {
@@ -1576,6 +1820,22 @@
if (entity.bB() == this) {
throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)");
} else {
+ // CraftBukkit start
+ CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle();
+ Entity orig = craft == null ? null : craft.getHandle();
+ if (getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity) {
+ VehicleExitEvent event = new VehicleExitEvent(
+ (Vehicle) getBukkitEntity(),
+ (LivingEntity) entity.getBukkitEntity()
+ );
+ Bukkit.getPluginManager().callEvent(event);
+ CraftEntity craftn = (CraftEntity) entity.getBukkitEntity().getVehicle();
+ Entity n = craftn == null ? null : craftn.getHandle();
+ if (event.isCancelled() || n != orig) {
+ return;
+ }
+ }
+ // CraftBukkit end
this.passengers.remove(entity);
entity.j = 60;
}
@@ -1715,14 +1975,48 @@
}
public void setAirTicks(int i) {
- this.datawatcher.set(Entity.az, Integer.valueOf(i));
+ // CraftBukkit start
+ EntityAirChangeEvent event = new EntityAirChangeEvent(this.getBukkitEntity(), i);
+ if (event.isCancelled()) {
+ return;
+ }
+ this.datawatcher.set(Entity.az, Integer.valueOf(event.getAmount()));
+ // CraftBukkit end
}
public void onLightningStrike(EntityLightning entitylightning) {
- this.damageEntity(DamageSource.LIGHTNING, 5.0F);
+ // CraftBukkit start
+ final org.bukkit.entity.Entity thisBukkitEntity = this.getBukkitEntity();
+ final org.bukkit.entity.Entity stormBukkitEntity = entitylightning.getBukkitEntity();
+ final PluginManager pluginManager = Bukkit.getPluginManager();
+
+ if (thisBukkitEntity instanceof Hanging) {
+ HangingBreakByEntityEvent hangingEvent = new HangingBreakByEntityEvent((Hanging) thisBukkitEntity, stormBukkitEntity);
+ pluginManager.callEvent(hangingEvent);
+
+ if (hangingEvent.isCancelled()) {
+ return;
+ }
+ }
+
+ if (this.fireProof) {
+ return;
+ }
+ CraftEventFactory.entityDamage = entitylightning;
+ if (!this.damageEntity(DamageSource.LIGHTNING, 5.0F)) {
+ CraftEventFactory.entityDamage = null;
+ return;
+ }
+ // CraftBukkit end
++this.fireTicks;
if (this.fireTicks == 0) {
- this.setOnFire(8);
+ // CraftBukkit start - Call a combust event when lightning strikes
+ EntityCombustByEntityEvent entityCombustEvent = new EntityCombustByEntityEvent(stormBukkitEntity, thisBukkitEntity, 8);
+ pluginManager.callEvent(entityCombustEvent);
+ if (!entityCombustEvent.isCancelled()) {
+ this.setOnFire(entityCombustEvent.getDuration());
+ }
+ // CraftBukkit end
}
}
@@ -1867,19 +2161,70 @@
if (!this.world.isClientSide && !this.dead) {
this.world.methodProfiler.a("changeDimension");
MinecraftServer minecraftserver = this.B_();
- int j = this.dimension;
- WorldServer worldserver = minecraftserver.getWorldServer(j);
- WorldServer worldserver1 = minecraftserver.getWorldServer(i);
+ // CraftBukkit start - Move logic into new function "teleportTo(Location,boolean)"
+ // int j = this.dimension;
+ // WorldServer worldserver = minecraftserver.getWorldServer(j);
+ // WorldServer worldserver1 = minecraftserver.getWorldServer(i);
+ WorldServer exitWorld = null;
+ if (this.dimension < CraftWorld.CUSTOM_DIMENSION_OFFSET) { // Plugins must specify exit from custom Bukkit worlds
+ // Only target existing worlds (compensate for allow-nether/allow-end as false)
+ for (WorldServer world : minecraftserver.worlds) {
+ if (world.dimension == i) {
+ exitWorld = world;
+ }
+ }
+ }
+
+ BlockPosition blockposition = null; // PAIL: CHECK
+ Location enter = this.getBukkitEntity().getLocation();
+ Location exit;
+ if (exitWorld != null) {
+ if (blockposition != null) {
+ exit = new Location(exitWorld.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ());
+ } else {
+ exit = minecraftserver.getPlayerList().calculateTarget(enter, minecraftserver.getWorldServer(i));
+ }
+ }
+ else {
+ exit = null;
+ }
+ boolean useTravelAgent = exitWorld != null && !(this.dimension == 1 && exitWorld.dimension == 1); // don't use agent for custom worlds or return from THE_END
+
+ TravelAgent agent = exit != null ? (TravelAgent) ((CraftWorld) exit.getWorld()).getHandle().getTravelAgent() : org.bukkit.craftbukkit.CraftTravelAgent.DEFAULT; // return arbitrary TA to compensate for implementation dependent plugins
+ EntityPortalEvent event = new EntityPortalEvent(this.getBukkitEntity(), enter, exit, agent);
+ event.useTravelAgent(useTravelAgent);
+ event.getEntity().getServer().getPluginManager().callEvent(event);
+ if (event.isCancelled() || event.getTo() == null || event.getTo().getWorld() == null || !this.isAlive()) {
+ return null;
+ }
+ exit = event.useTravelAgent() ? event.getPortalTravelAgent().findOrCreate(event.getTo()) : event.getTo();
+ // Need to make sure the profiler state is reset afterwards (but we still want to time the call)
+ Entity entity = this.teleportTo(exit, true);
+ this.world.methodProfiler.b();
+ return entity;
+ }
+ return null;
+ }
+
+ public Entity teleportTo(Location exit, boolean portal) {
+ if (true) {
+ WorldServer worldserver = ((CraftWorld) getBukkitEntity().getLocation().getWorld()).getHandle();
+ WorldServer worldserver1 = ((CraftWorld) exit.getWorld()).getHandle();
+ int i = worldserver1.dimension;
+ // CraftBukkit end
this.dimension = i;
+ /* CraftBukkit start - TODO: Check if we need this
if (j == 1 && i == 1) {
worldserver1 = minecraftserver.getWorldServer(0);
this.dimension = 0;
}
+ // CraftBukkit end */
this.world.kill(this);
this.dead = false;
this.world.methodProfiler.a("reposition");
+ /* CraftBukkit start - Handled in calculateTarget
BlockPosition blockposition;
if (i == 1) {
@@ -1908,12 +2253,18 @@
blockposition = new BlockPosition(this);
}
- worldserver.entityJoinedWorld(this, false);
+ // CraftBukkit end */
+ // CraftBukkit start - Ensure chunks are loaded in case TravelAgent is not used which would initially cause chunks to load during find/create
+ // minecraftserver.getPlayerList().changeWorld(this, j, worldserver, worldserver1);
+ worldserver1.getMinecraftServer().getPlayerList().repositionEntity(this, exit, portal);
+ // worldserver.entityJoinedWorld(this, false); // Handled in repositionEntity
+ // CraftBukkit end
this.world.methodProfiler.c("reloading");
Entity entity = EntityTypes.a(this.getClass(), (World) worldserver1);
if (entity != null) {
entity.a(this);
+ /* CraftBukkit start - We need to do this...
if (j == 1 && i == 1) {
BlockPosition blockposition1 = worldserver1.q(worldserver1.getSpawn());
@@ -1921,6 +2272,7 @@
} else {
entity.setPositionRotation(blockposition, entity.yaw, entity.pitch);
}
+ // CraftBukkit end */
boolean flag = entity.attachedToPlayer;
@@ -1928,13 +2280,21 @@
worldserver1.addEntity(entity);
entity.attachedToPlayer = flag;
worldserver1.entityJoinedWorld(entity, false);
+ // CraftBukkit start - Forward the CraftEntity to the new entity
+ this.getBukkitEntity().setHandle(entity);
+ entity.bukkitEntity = this.getBukkitEntity();
+
+ if (this instanceof EntityInsentient) {
+ ((EntityInsentient)this).unleash(true, false); // Unleash to prevent duping of leads.
+ }
+ // CraftBukkit end
}
this.dead = true;
this.world.methodProfiler.b();
worldserver.m();
worldserver1.m();
- this.world.methodProfiler.b();
+ // this.world.methodProfiler.b(); // CraftBukkit: Moved up to keep balanced
return entity;
} else {
return null;
@@ -2038,6 +2398,11 @@
}
public void setCustomName(String s) {
+ // CraftBukkit start - Add a sane limit for name length
+ if (s.length() > 256) {
+ s = s.substring(0, 256);
+ }
+ // CraftBukkit end
this.datawatcher.set(Entity.aA, s);
}
@@ -2095,7 +2460,26 @@
}
public void a(AxisAlignedBB axisalignedbb) {
- this.boundingBox = axisalignedbb;
+ // CraftBukkit start - block invalid bounding boxes
+ double a = axisalignedbb.a,
+ b = axisalignedbb.b,
+ c = axisalignedbb.c,
+ d = axisalignedbb.d,
+ e = axisalignedbb.e,
+ f = axisalignedbb.f;
+ double len = axisalignedbb.d - axisalignedbb.a;
+ if (len < 0) d = a;
+ if (len > 64) d = a + 64.0;
+
+ len = axisalignedbb.e - axisalignedbb.b;
+ if (len < 0) e = b;
+ if (len > 64) e = b + 64.0;
+
+ len = axisalignedbb.f - axisalignedbb.c;
+ if (len < 0) f = c;
+ if (len > 64) f = c + 64.0;
+ this.boundingBox = new AxisAlignedBB(a, b, c, d, e, f);
+ // CraftBukkit end
}
public float getHeadHeight() {
@@ -2269,7 +2653,7 @@
for (Iterator iterator = this.bx().iterator(); iterator.hasNext(); entity.a(oclass, set)) {
entity = (Entity) iterator.next();
if (oclass.isAssignableFrom(entity.getClass())) {
- set.add(entity);
+ set.add((T) entity); // CraftBukkit - decompile error
}
}