diff --git a/src/main/java/net/minecraft/entity/Entity.java b/src/main/java/net/minecraft/entity/Entity.java index 813d106..10f2ed8 100644 --- a/src/main/java/net/minecraft/entity/Entity.java +++ b/src/main/java/net/minecraft/entity/Entity.java @@ -2512,6 +2512,16 @@ return false; } + public boolean isEntityItem() + { + return false; + } + + public boolean isEntityXPOrb() + { + return false; + } + public double getEntityDespawnDistance() { return 9216d;//16384.0d; diff --git a/src/main/java/net/minecraft/entity/EntityLiving.java b/src/main/java/net/minecraft/entity/EntityLiving.java index 6c1f720..14d6f04 100644 --- a/src/main/java/net/minecraft/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/entity/EntityLiving.java @@ -2,9 +2,11 @@ import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; + import java.util.Iterator; import java.util.List; import java.util.UUID; + import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.ai.EntityAITasks; import net.minecraft.entity.ai.EntityJumpHelper; @@ -1152,4 +1154,35 @@ { return true; } + + public EnumCreatureType getCreatureType() + { + if(isEntityAnimal()) + return EnumCreatureType.creature; + if(isEntityAmbient()) + return EnumCreatureType.ambient; + if(isEntityWater()) + return EnumCreatureType.waterCreature; + + return EnumCreatureType.monster; + } + + public void despawnInactive() + { + if(!canDespawn() || ++entityAge <= 600) + return; + + EntityPlayer player = worldObj.getClosestPlayerToEntity(this, -1.0D); + + if (player != null) + { + double distX = player.posX - posX; + double distY = player.posY - posY; + double distZ = player.posZ - posZ; + double square = distX*distX + distY*distY + distZ*distZ; + + if (square > getEntityDespawnDistance()) + setDead(); + } + } } diff --git a/src/main/java/net/minecraft/entity/item/EntityItem.java b/src/main/java/net/minecraft/entity/item/EntityItem.java index 142239b..f3b1bcb 100644 --- a/src/main/java/net/minecraft/entity/item/EntityItem.java +++ b/src/main/java/net/minecraft/entity/item/EntityItem.java @@ -451,4 +451,11 @@ { this.field_145801_f = p_145799_1_; } + + /*===================================== ULTRAMINE START =====================================*/ + + public boolean isEntityItem() + { + return true; + } } \ No newline at end of file diff --git a/src/main/java/net/minecraft/entity/item/EntityXPOrb.java b/src/main/java/net/minecraft/entity/item/EntityXPOrb.java index b16b1fc..820327e 100644 --- a/src/main/java/net/minecraft/entity/item/EntityXPOrb.java +++ b/src/main/java/net/minecraft/entity/item/EntityXPOrb.java @@ -236,4 +236,11 @@ { return false; } + + /*===================================== ULTRAMINE START =====================================*/ + + public boolean isEntityXPOrb() + { + return true; + } } \ No newline at end of file diff --git a/src/main/java/net/minecraft/world/World.java b/src/main/java/net/minecraft/world/World.java index 75da45d..e340261 100644 --- a/src/main/java/net/minecraft/world/World.java +++ b/src/main/java/net/minecraft/world/World.java @@ -17,6 +17,7 @@ import java.util.concurrent.Callable; import org.ultramine.server.ConfigurationHandler; +import org.ultramine.server.ServerLoadBalancer; import org.ultramine.server.chunk.ChunkHash; import org.ultramine.server.chunk.IChunkLoadCallback; @@ -2012,12 +2013,12 @@ public void updateEntityWithOptionalForce(Entity p_72866_1_, boolean p_72866_2_) { - int i = MathHelper.floor_double(p_72866_1_.posX); - int j = MathHelper.floor_double(p_72866_1_.posZ); + //int i = MathHelper.floor_double(p_72866_1_.posX); + //int j = MathHelper.floor_double(p_72866_1_.posZ); //boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(i >> 4, j >> 4)); //byte b0 = isForced ? (byte)0 : 32; //boolean canUpdate = !p_72866_2_ || this.checkChunksExist(i - b0, 0, j - b0, i + b0, 0, j + b0); - boolean canUpdate = p_72866_1_.isEntityPlayerMP() || activeChunkSet.containsKey(ChunkHash.chunkToKey(i >> 4, j >> 4)) || isRemote && p_72866_1_.isEntityPlayer(); + boolean canUpdate = balancer.canUpdateEntity(p_72866_1_); //if (!canUpdate) //{ @@ -4027,6 +4028,7 @@ public static final int MAX_BLOCK_COORD = 500000;//524288; + private final ServerLoadBalancer balancer = new ServerLoadBalancer(this); public Chunk getChunkIfExists(int cx, int cz) { diff --git a/src/main/java/net/minecraft/world/chunk/Chunk.java b/src/main/java/net/minecraft/world/chunk/Chunk.java index 6535be2..d042ab2 100644 --- a/src/main/java/net/minecraft/world/chunk/Chunk.java +++ b/src/main/java/net/minecraft/world/chunk/Chunk.java @@ -926,7 +926,6 @@ { Entity entity = (Entity)iterator.next(); entity.onChunkLoad(); - onEntityAdd(entity); } this.worldObj.addLoadedEntities(this.entityLists[i]); @@ -1556,6 +1555,8 @@ private short entityAnimalCount; private short entityAmbientCount; private short entityWaterCount; + private short entityItemCount; + private short entityXPOrbCount; public PendingBlockUpdate pollPending(long time) { @@ -1657,6 +1658,10 @@ else if(e.isEntityAmbient()) ++entityAmbientCount; else if(e.isEntityWater()) ++entityWaterCount; } + else if(e.isEntityItem()) + ++entityItemCount; + else if(e.isEntityXPOrb()) + ++entityXPOrbCount; } private void onEntityRemove(Entity e) @@ -1669,6 +1674,10 @@ else if(e.isEntityAmbient()) --entityAmbientCount; else if(e.isEntityWater()) --entityWaterCount; } + else if(e.isEntityItem()) + --entityItemCount; + else if(e.isEntityXPOrb()) + --entityXPOrbCount; } private void resetEntityCounters() @@ -1678,6 +1687,8 @@ entityAnimalCount = 0; entityAmbientCount = 0; entityWaterCount = 0; + entityItemCount = 0; + entityXPOrbCount = 0; } public int getEntityCount() @@ -1701,4 +1712,16 @@ return 0; } } + + public int getEntityCountOfSameType(Entity e) + { + if(e.isEntityMonster()) return entityMonsterCount; + else if(e.isEntityAnimal()) return entityAnimalCount; + else if(e.isEntityAmbient()) return entityAmbientCount; + else if(e.isEntityWater()) return entityWaterCount; + else if(e.isEntityItem()) return entityItemCount; + else if(e.isEntityXPOrb()) return entityXPOrbCount; + + return 0; + } } diff --git a/src/main/java/org/ultramine/server/ServerLoadBalancer.java b/src/main/java/org/ultramine/server/ServerLoadBalancer.java new file mode 100644 index 0000000..bdb7c47 --- /dev/null +++ b/src/main/java/org/ultramine/server/ServerLoadBalancer.java @@ -0,0 +1,92 @@ +package org.ultramine.server; + +import java.util.Random; + +import org.ultramine.server.WorldsConfig.WorldConfig.LoadBalancer.Limits; +import org.ultramine.server.WorldsConfig.WorldConfig.LoadBalancer.Limits.PerChunkEntityLimits; +import org.ultramine.server.chunk.ChunkHash; + +import cpw.mods.fml.common.FMLCommonHandler; +import gnu.trove.map.TIntByteMap; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; + +public class ServerLoadBalancer +{ + private static final boolean isClient = FMLCommonHandler.instance().getSide().isClient(); + private static final PerChunkEntityLimits clientLimits = new PerChunkEntityLimits(); + private static final PerChunkEntityLimits infinityLimits = new PerChunkEntityLimits(); + private static final Random rng = new Random(); + private final World world; + private final TIntByteMap activeChunkSet; + + static + { + clientLimits.lowerLimit = 32; + clientLimits.higherLimit = Integer.MAX_VALUE; + infinityLimits.lowerLimit = Integer.MAX_VALUE; + infinityLimits.higherLimit = Integer.MAX_VALUE; + } + + public ServerLoadBalancer(World world) + { + this.world = world; + this.activeChunkSet = world.getActiveChunkSet(); + } + + public boolean canUpdateEntity(Entity ent) + { + if(ent.isEntityPlayerMP() || isClient && world.isRemote && ent.isEntityPlayer()) + return true; + int cx = MathHelper.floor_double(ent.posX) >> 4; + int cz = MathHelper.floor_double(ent.posZ) >> 4; + int prior = activeChunkSet.get(ChunkHash.chunkToKey(cx, cz)); + if(prior == Byte.MAX_VALUE) + { + if(ent.isEntityLiving()) + ((EntityLiving)ent).despawnInactive(); + return false; + } + + if(!ent.addedToChunk) + return true; + + Chunk chunk = world.getChunkFromChunkCoords(cx, cz); + int count = chunk.getEntityCountOfSameType(ent); + PerChunkEntityLimits getLimits = getLimits(ent); + if(count > getLimits.higherLimit) + { + ent.setDead(); + return false; + } + if(count > getLimits.lowerLimit) + { + float rate = (float)getLimits.lowerLimit / (float)count; + if(rng.nextFloat() < rate) + return true; + return false; + } + + return true; + } + + private PerChunkEntityLimits getLimits(Entity e) + { + if(isClient) + return clientLimits; + Limits limits = ((WorldServer)e.worldObj).getConfig().loadBalancer.limits; + + if(e.isEntityMonster()) return limits.monsters; + else if(e.isEntityAnimal()) return limits.animals; + else if(e.isEntityAmbient()) return limits.ambient; + else if(e.isEntityWater()) return limits.water; + else if(e.isEntityItem()) return limits.items; + else if(e.isEntityXPOrb()) return limits.xpOrbs; + + return infinityLimits; + } +} diff --git a/src/main/java/org/ultramine/server/WorldsConfig.java b/src/main/java/org/ultramine/server/WorldsConfig.java index 4cbb563..7c05e24 100644 --- a/src/main/java/org/ultramine/server/WorldsConfig.java +++ b/src/main/java/org/ultramine/server/WorldsConfig.java @@ -15,6 +15,7 @@ public MobSpawn mobSpawn; public Settings settings; public ChunkLoading chunkLoading; + public LoadBalancer loadBalancer; public static class Generation { @@ -93,5 +94,25 @@ public int chunkCacheSize; public boolean enableChunkLoaders = true; } + + public static class LoadBalancer + { + public Limits limits; + public static class Limits + { + public PerChunkEntityLimits monsters; + public PerChunkEntityLimits animals; + public PerChunkEntityLimits water; + public PerChunkEntityLimits ambient; + public PerChunkEntityLimits items; + public PerChunkEntityLimits xpOrbs; + + public static class PerChunkEntityLimits + { + public int lowerLimit; + public int higherLimit; + } + } + } } } diff --git a/src/main/resources/org/ultramine/defaults/defaultworlds.yml b/src/main/resources/org/ultramine/defaults/defaultworlds.yml index 18e2b01..ba550ce 100644 --- a/src/main/resources/org/ultramine/defaults/defaultworlds.yml +++ b/src/main/resources/org/ultramine/defaults/defaultworlds.yml @@ -22,14 +22,6 @@ localCheckRadius: 1 localLimit: 3 nightlyLocalLimit: 5 - water: - enabled: true - minRadius: 3 - maxRadius: 5 - minPlayerDistance: 0 - performInterval: 400 - localCheckRadius: 4 - localLimit: 3 animals: enabled: true minRadius: 5 @@ -38,6 +30,14 @@ performInterval: 401 localCheckRadius: 5 localLimit: 3 + water: + enabled: true + minRadius: 3 + maxRadius: 5 + minPlayerDistance: 0 + performInterval: 400 + localCheckRadius: 4 + localLimit: 3 ambient: enabled: true minPlayerDistance: 8 @@ -58,7 +58,27 @@ chunkUpdateRadius: 7 chunkCacheSize: 1024 enableChunkLoaders: true - + loadBalancer: + limits: + monsters: + lowerLimit: 16 + higherLimit: 16 + animals: + lowerLimit: 4 + higherLimit: 64 + water: + lowerLimit: 4 + higherLimit: 16 + ambient: + lowerLimit: 16 + higherLimit: 16 + items: + lowerLimit: 16 + higherLimit: 1024 + xpOrbs: + lowerLimit: 8 + higherLimit: 16 + worlds: world: <<: *global