diff options
Diffstat (limited to 'CraftBukkit-Patches/0016-Entity-Activation-Range.patch')
-rw-r--r-- | CraftBukkit-Patches/0016-Entity-Activation-Range.patch | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/CraftBukkit-Patches/0016-Entity-Activation-Range.patch b/CraftBukkit-Patches/0016-Entity-Activation-Range.patch new file mode 100644 index 0000000000..afb1768c66 --- /dev/null +++ b/CraftBukkit-Patches/0016-Entity-Activation-Range.patch @@ -0,0 +1,522 @@ +From 72e1c5a2f9954a7dafbf3ccfc9477330df7bc861 Mon Sep 17 00:00:00 2001 +From: Aikar <[email protected]> +Date: Sun, 3 Feb 2013 05:10:21 -0500 +Subject: [PATCH] Entity Activation Range + +This feature gives 3 new configurable ranges that if an entity of the matching type is outside of this radius of any player, will tick at 5% of its normal rate. + +This will drastically cut down on tick timings for entities that are not in range of a user to actually be "used". +This change can have dramatic impact on gameplay if configured too low. Balance according to your servers desired gameplay. + +diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java +index a7d9c11..33798d8 100644 +--- a/src/main/java/net/minecraft/server/Entity.java ++++ b/src/main/java/net/minecraft/server/Entity.java +@@ -90,7 +90,7 @@ public abstract class Entity { + public int ticksLived; + public int maxFireTicks; + public int fireTicks; // CraftBukkit - private -> public +- protected boolean inWater; ++ public boolean inWater; // Spigot - protected -> public + public int noDamageTicks; + private boolean justCreated; + protected boolean fireProof; +@@ -114,7 +114,13 @@ public abstract class Entity { + public boolean valid; // CraftBukkit + public org.bukkit.projectiles.ProjectileSource projectileSource; // CraftBukkit - For projectiles only + ++ // Spigot start + public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getEntityTimings(this); // Spigot ++ public final byte activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this); ++ public final boolean defaultActivationState; ++ public long activatedTick = 0; ++ public void inactiveTick() { } ++ // Spigot end + + public int getId() { + return this.id; +@@ -141,7 +147,12 @@ public abstract class Entity { + this.setPosition(0.0D, 0.0D, 0.0D); + if (world != null) { + this.dimension = world.worldProvider.dimension; ++ // Spigot start ++ this.defaultActivationState = org.spigotmc.ActivationRange.initializeEntityActivationState(this, world.spigotConfig); ++ } else { ++ this.defaultActivationState = false; + } ++ // Spigot end + + this.datawatcher = new DataWatcher(this); + this.datawatcher.a(0, Byte.valueOf((byte) 0)); +diff --git a/src/main/java/net/minecraft/server/EntityAgeable.java b/src/main/java/net/minecraft/server/EntityAgeable.java +index 36ed831..7ddca48 100644 +--- a/src/main/java/net/minecraft/server/EntityAgeable.java ++++ b/src/main/java/net/minecraft/server/EntityAgeable.java +@@ -6,6 +6,31 @@ public abstract class EntityAgeable extends EntityCreature { + private float bq; + public boolean ageLocked = false; // CraftBukkit + ++ // Spigot start ++ @Override ++ public void inactiveTick() ++ { ++ super.inactiveTick(); ++ if ( this.world.isStatic || this.ageLocked ) ++ { // CraftBukkit ++ this.a( this.isBaby() ); ++ } else ++ { ++ int i = this.getAge(); ++ ++ if ( i < 0 ) ++ { ++ ++i; ++ this.setAge( i ); ++ } else if ( i > 0 ) ++ { ++ --i; ++ this.setAge( i ); ++ } ++ } ++ } ++ // Spigot end ++ + public EntityAgeable(World world) { + super(world); + } +diff --git a/src/main/java/net/minecraft/server/EntityArrow.java b/src/main/java/net/minecraft/server/EntityArrow.java +index 88b0751..ac5d5d2 100644 +--- a/src/main/java/net/minecraft/server/EntityArrow.java ++++ b/src/main/java/net/minecraft/server/EntityArrow.java +@@ -15,7 +15,7 @@ public class EntityArrow extends Entity implements IProjectile { + private int f = -1; + private Block g; + private int h; +- private boolean inGround; ++ public boolean inGround = false; // Spigot - private -> public + public int fromPlayer; + public int shake; + public Entity shooter; +@@ -24,6 +24,18 @@ public class EntityArrow extends Entity implements IProjectile { + private double damage = 2.0D; + public int knockbackStrength; // CraftBukkit - private -> public + ++ // Spigot Start ++ @Override ++ public void inactiveTick() ++ { ++ if ( this.inGround ) ++ { ++ this.at += 19; // Despawn counter. First int after shooter ++ } ++ super.inactiveTick(); ++ } ++ // Spigot End ++ + public EntityArrow(World world) { + super(world); + this.j = 10.0D; +diff --git a/src/main/java/net/minecraft/server/EntityFireworks.java b/src/main/java/net/minecraft/server/EntityFireworks.java +index 759d46c..b977cf7 100644 +--- a/src/main/java/net/minecraft/server/EntityFireworks.java ++++ b/src/main/java/net/minecraft/server/EntityFireworks.java +@@ -5,6 +5,15 @@ public class EntityFireworks extends Entity { + private int ticksFlown; + public int expectedLifespan; // CraftBukkit - private -> public + ++ // Spigot Start ++ @Override ++ public void inactiveTick() ++ { ++ this.ticksFlown += 19; ++ super.inactiveTick(); ++ } ++ // Spigot End ++ + public EntityFireworks(World world) { + super(world); + this.a(0.25F, 0.25F); +diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java +index 6a0bee6..92ad5c7 100644 +--- a/src/main/java/net/minecraft/server/EntityLiving.java ++++ b/src/main/java/net/minecraft/server/EntityLiving.java +@@ -84,6 +84,13 @@ public abstract class EntityLiving extends Entity { + public int maxAirTicks = 300; + ArrayList<org.bukkit.inventory.ItemStack> drops = null; + // CraftBukkit end ++ // Spigot start ++ public void inactiveTick() ++ { ++ super.inactiveTick(); ++ ++this.aU; // Above all the floats ++ } ++ // Spigot end + + public EntityLiving(World world) { + super(world); +diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java +index e03712a..e876b66 100644 +--- a/src/main/java/net/minecraft/server/World.java ++++ b/src/main/java/net/minecraft/server/World.java +@@ -1317,6 +1317,7 @@ public abstract class World implements IBlockAccess { + this.f.clear(); + this.methodProfiler.c("regular"); + ++ org.spigotmc.ActivationRange.activateEntities(this); // Spigot + timings.entityTick.startTiming(); // Spigot + // CraftBukkit start - Use field for loop variable + for (this.tickPosition = 0; this.tickPosition < this.entityList.size(); ++this.tickPosition) { +@@ -1473,9 +1474,11 @@ public abstract class World implements IBlockAccess { + int j = MathHelper.floor(entity.locZ); + byte b0 = 32; + +- // CraftBukkit start - Use neighbor cache instead of looking up +- Chunk startingChunk = this.getChunkIfLoaded(i >> 4, j >> 4); +- if (!flag || (startingChunk != null && startingChunk.areNeighborsLoaded(2)) /* this.b(i - b0, 0, j - b0, i + b0, 0, j + b0) */) { ++ // Spigot start ++ if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { ++ entity.ticksLived++; ++ entity.inactiveTick(); ++ } else { + entity.tickTimer.startTiming(); // Spigot + // CraftBukkit end + entity.S = entity.locX; +diff --git a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java b/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java +index 558574f..41d2d87 100644 +--- a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java ++++ b/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java +@@ -39,6 +39,9 @@ public class SpigotTimings { + + public static final CustomTimingsHandler playerCommandTimer = new CustomTimingsHandler("** playerCommand"); + ++ public static final CustomTimingsHandler entityActivationCheckTimer = new CustomTimingsHandler("entityActivationCheck"); ++ public static final CustomTimingsHandler checkIfActiveTimer = new CustomTimingsHandler("** checkIfActive"); ++ + public static final HashMap<String, CustomTimingsHandler> entityTypeTimingMap = new HashMap<String, CustomTimingsHandler>(); + public static final HashMap<String, CustomTimingsHandler> tileEntityTypeTimingMap = new HashMap<String, CustomTimingsHandler>(); + public static final HashMap<String, CustomTimingsHandler> pluginTaskTimingMap = new HashMap<String, CustomTimingsHandler>(); +diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java +new file mode 100644 +index 0000000..84a7dd6 +--- /dev/null ++++ b/src/main/java/org/spigotmc/ActivationRange.java +@@ -0,0 +1,296 @@ ++package org.spigotmc; ++ ++import java.util.ArrayList; ++import java.util.List; ++import net.minecraft.server.AxisAlignedBB; ++import net.minecraft.server.Chunk; ++import net.minecraft.server.Entity; ++import net.minecraft.server.EntityAmbient; ++import net.minecraft.server.EntityAnimal; ++import net.minecraft.server.EntityArrow; ++import net.minecraft.server.EntityComplexPart; ++import net.minecraft.server.EntityCreature; ++import net.minecraft.server.EntityEnderCrystal; ++import net.minecraft.server.EntityEnderDragon; ++import net.minecraft.server.EntityFireball; ++import net.minecraft.server.EntityFireworks; ++import net.minecraft.server.EntityHuman; ++import net.minecraft.server.EntityLiving; ++import net.minecraft.server.EntityMonster; ++import net.minecraft.server.EntityProjectile; ++import net.minecraft.server.EntitySheep; ++import net.minecraft.server.EntitySlime; ++import net.minecraft.server.EntityTNTPrimed; ++import net.minecraft.server.EntityVillager; ++import net.minecraft.server.EntityWeather; ++import net.minecraft.server.EntityWither; ++import net.minecraft.server.MathHelper; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.World; ++import org.bukkit.craftbukkit.SpigotTimings; ++ ++public class ActivationRange ++{ ++ ++ static AxisAlignedBB maxBB = AxisAlignedBB.a( 0, 0, 0, 0, 0, 0 ); ++ static AxisAlignedBB miscBB = AxisAlignedBB.a( 0, 0, 0, 0, 0, 0 ); ++ static AxisAlignedBB animalBB = AxisAlignedBB.a( 0, 0, 0, 0, 0, 0 ); ++ static AxisAlignedBB monsterBB = AxisAlignedBB.a( 0, 0, 0, 0, 0, 0 ); ++ ++ /** ++ * Initializes an entities type on construction to specify what group this ++ * entity is in for activation ranges. ++ * ++ * @param entity ++ * @return group id ++ */ ++ public static byte initializeEntityActivationType(Entity entity) ++ { ++ if ( entity instanceof EntityMonster || entity instanceof EntitySlime ) ++ { ++ return 1; // Monster ++ } else if ( entity instanceof EntityCreature || entity instanceof EntityAmbient ) ++ { ++ return 2; // Animal ++ } else ++ { ++ return 3; // Misc ++ } ++ } ++ ++ /** ++ * These entities are excluded from Activation range checks. ++ * ++ * @param entity ++ * @param world ++ * @return boolean If it should always tick. ++ */ ++ public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config) ++ { ++ if ( ( entity.activationType == 3 && config.miscActivationRange == 0 ) ++ || ( entity.activationType == 2 && config.animalActivationRange == 0 ) ++ || ( entity.activationType == 1 && config.monsterActivationRange == 0 ) ++ || entity instanceof EntityHuman ++ || entity instanceof EntityProjectile ++ || entity instanceof EntityEnderDragon ++ || entity instanceof EntityComplexPart ++ || entity instanceof EntityWither ++ || entity instanceof EntityFireball ++ || entity instanceof EntityWeather ++ || entity instanceof EntityTNTPrimed ++ || entity instanceof EntityEnderCrystal ++ || entity instanceof EntityFireworks ) ++ { ++ return true; ++ } ++ ++ return false; ++ } ++ ++ /** ++ * Utility method to grow an AABB without creating a new AABB or touching ++ * the pool, so we can re-use ones we have. ++ * ++ * @param target ++ * @param source ++ * @param x ++ * @param y ++ * @param z ++ */ ++ public static void growBB(AxisAlignedBB target, AxisAlignedBB source, int x, int y, int z) ++ { ++ target.a = source.a - x; ++ target.b = source.b - y; ++ target.c = source.c - z; ++ target.d = source.d + x; ++ target.e = source.e + y; ++ target.f = source.f + z; ++ } ++ ++ /** ++ * Find what entities are in range of the players in the world and set ++ * active if in range. ++ * ++ * @param world ++ */ ++ public static void activateEntities(World world) ++ { ++ SpigotTimings.entityActivationCheckTimer.startTiming(); ++ final int miscActivationRange = world.spigotConfig.miscActivationRange; ++ final int animalActivationRange = world.spigotConfig.animalActivationRange; ++ final int monsterActivationRange = world.spigotConfig.monsterActivationRange; ++ ++ int maxRange = Math.max( monsterActivationRange, animalActivationRange ); ++ maxRange = Math.max( maxRange, miscActivationRange ); ++ maxRange = Math.min( ( world.spigotConfig.viewDistance << 4 ) - 8, maxRange ); ++ ++ for ( Entity player : new ArrayList<Entity>( world.players ) ) ++ { ++ ++ player.activatedTick = MinecraftServer.currentTick; ++ growBB( maxBB, player.boundingBox, maxRange, 256, maxRange ); ++ growBB( miscBB, player.boundingBox, miscActivationRange, 256, miscActivationRange ); ++ growBB( animalBB, player.boundingBox, animalActivationRange, 256, animalActivationRange ); ++ growBB( monsterBB, player.boundingBox, monsterActivationRange, 256, monsterActivationRange ); ++ ++ int i = MathHelper.floor( maxBB.a / 16.0D ); ++ int j = MathHelper.floor( maxBB.d / 16.0D ); ++ int k = MathHelper.floor( maxBB.c / 16.0D ); ++ int l = MathHelper.floor( maxBB.f / 16.0D ); ++ ++ for ( int i1 = i; i1 <= j; ++i1 ) ++ { ++ for ( int j1 = k; j1 <= l; ++j1 ) ++ { ++ if ( world.getWorld().isChunkLoaded( i1, j1 ) ) ++ { ++ activateChunkEntities( world.getChunkAt( i1, j1 ) ); ++ } ++ } ++ } ++ } ++ SpigotTimings.entityActivationCheckTimer.stopTiming(); ++ } ++ ++ /** ++ * Checks for the activation state of all entities in this chunk. ++ * ++ * @param chunk ++ */ ++ private static void activateChunkEntities(Chunk chunk) ++ { ++ for ( List<Entity> slice : chunk.entitySlices ) ++ { ++ for ( Entity entity : slice ) ++ { ++ if ( MinecraftServer.currentTick > entity.activatedTick ) ++ { ++ if ( entity.defaultActivationState ) ++ { ++ entity.activatedTick = MinecraftServer.currentTick; ++ continue; ++ } ++ switch ( entity.activationType ) ++ { ++ case 1: ++ if ( monsterBB.b( entity.boundingBox ) ) ++ { ++ entity.activatedTick = MinecraftServer.currentTick; ++ } ++ break; ++ case 2: ++ if ( animalBB.b( entity.boundingBox ) ) ++ { ++ entity.activatedTick = MinecraftServer.currentTick; ++ } ++ break; ++ case 3: ++ default: ++ if ( miscBB.b( entity.boundingBox ) ) ++ { ++ entity.activatedTick = MinecraftServer.currentTick; ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ /** ++ * If an entity is not in range, do some more checks to see if we should ++ * give it a shot. ++ * ++ * @param entity ++ * @return ++ */ ++ public static boolean checkEntityImmunities(Entity entity) ++ { ++ // quick checks. ++ if ( entity.inWater /* isInWater */ || entity.fireTicks > 0 ) ++ { ++ return true; ++ } ++ if ( !( entity instanceof EntityArrow ) ) ++ { ++ if ( !entity.onGround || entity.passenger != null ++ || entity.vehicle != null ) ++ { ++ return true; ++ } ++ } else if ( !( (EntityArrow) entity ).inGround ) ++ { ++ return true; ++ } ++ // special cases. ++ if ( entity instanceof EntityLiving ) ++ { ++ EntityLiving living = (EntityLiving) entity; ++ if ( living.attackTicks > 0 || living.hurtTicks > 0 || living.effects.size() > 0 ) ++ { ++ return true; ++ } ++ if ( entity instanceof EntityCreature && ( (EntityCreature) entity ).target != null ) ++ { ++ return true; ++ } ++ if ( entity instanceof EntityVillager && ( (EntityVillager) entity ).bY() /* Getter for first boolean */ ) ++ { ++ return true; ++ } ++ if ( entity instanceof EntityAnimal ) ++ { ++ EntityAnimal animal = (EntityAnimal) entity; ++ if ( animal.isBaby() || animal.ce() /*love*/ ) ++ { ++ return true; ++ } ++ if ( entity instanceof EntitySheep && ( (EntitySheep) entity ).isSheared() ) ++ { ++ return true; ++ } ++ } ++ } ++ return false; ++ } ++ ++ /** ++ * Checks if the entity is active for this tick. ++ * ++ * @param entity ++ * @return ++ */ ++ public static boolean checkIfActive(Entity entity) ++ { ++ SpigotTimings.checkIfActiveTimer.startTiming(); ++ boolean isActive = entity.activatedTick >= MinecraftServer.currentTick || entity.defaultActivationState; ++ ++ // Should this entity tick? ++ if ( !isActive ) ++ { ++ if ( ( MinecraftServer.currentTick - entity.activatedTick - 1 ) % 20 == 0 ) ++ { ++ // Check immunities every 20 ticks. ++ if ( checkEntityImmunities( entity ) ) ++ { ++ // Triggered some sort of immunity, give 20 full ticks before we check again. ++ entity.activatedTick = MinecraftServer.currentTick + 20; ++ } ++ isActive = true; ++ } ++ // Add a little performance juice to active entities. Skip 1/4 if not immune. ++ } else if ( !entity.defaultActivationState && entity.ticksLived % 4 == 0 && !checkEntityImmunities( entity ) ) ++ { ++ isActive = false; ++ } ++ int x = MathHelper.floor( entity.locX ); ++ int z = MathHelper.floor( entity.locZ ); ++ // Make sure not on edge of unloaded chunk ++ Chunk chunk = entity.world.getChunkIfLoaded( x >> 4, z >> 4 ); ++ if ( isActive && !( chunk != null && chunk.areNeighborsLoaded( 1 ) ) ) ++ { ++ isActive = false; ++ } ++ SpigotTimings.checkIfActiveTimer.stopTiming(); ++ return isActive; ++ } ++} +diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java +index 46249d7..ed2836a 100644 +--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java ++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java +@@ -138,4 +138,15 @@ public class SpigotWorldConfig + mobSpawnRange = (byte) getInt( "mob-spawn-range", 4 ); + log( "Mob Spawn Range: " + mobSpawnRange ); + } ++ ++ public int animalActivationRange = 32; ++ public int monsterActivationRange = 32; ++ public int miscActivationRange = 16; ++ private void activationRange() ++ { ++ animalActivationRange = getInt( "entity-activation-range.animals", animalActivationRange ); ++ monsterActivationRange = getInt( "entity-activation-range.monsters", monsterActivationRange ); ++ miscActivationRange = getInt( "entity-activation-range.misc", miscActivationRange ); ++ log( "Entity Activation Range: An " + animalActivationRange + " / Mo " + monsterActivationRange + " / Mi " + miscActivationRange ); ++ } + } +-- +1.9.1 + |