From 32ca2b4fb04b90d0768609b329746dee1b2281c6 Mon Sep 17 00:00:00 2001 From: XCompWiz Date: Wed, 3 Oct 2012 02:34:50 +0300 Subject: [PATCH 1/5] Improves DimensionManager Adds handling for unloading and hotloading of worlds, fixes some typos, allows for dimensions to be unregistered (allowing save specific dimension registrations), general changes to match these features. --- .../common/DimensionManager.java | 97 +++++++++++++++++-- 1 file changed, 87 insertions(+), 10 deletions(-) diff --git a/common/net/minecraftforge/common/DimensionManager.java b/common/net/minecraftforge/common/DimensionManager.java index 504139352..527ab0936 100644 --- a/common/net/minecraftforge/common/DimensionManager.java +++ b/common/net/minecraftforge/common/DimensionManager.java @@ -15,6 +15,7 @@ import cpw.mods.fml.common.FMLCommonHandler; import net.minecraft.server.MinecraftServer; import net.minecraft.src.*; +import net.minecraftforge.event.world.WorldEvent; public class DimensionManager { @@ -23,7 +24,9 @@ public class DimensionManager private static Hashtable worlds = new Hashtable(); private static boolean hasInit = false; private static Hashtable dimensions = new Hashtable(); - private static Map> persistentChunkStore = Maps.newHashMap(); + private static Map> persistentChunkStore = Maps.newHashMap(); //FIXME: Unused? + private static ArrayList unloadQueue = new ArrayList(); + private static int nextFree; public static boolean registerProviderType(int id, Class provider, boolean keepLoaded) { @@ -42,6 +45,7 @@ public class DimensionManager { return; } + nextFree = 0; //FIXME: Load/store nextFree from/in file in world dir, since other dims could have been registered in previous sessions by a now uninstalled mod registerProviderType( 0, WorldProviderSurface.class, true); registerProviderType(-1, WorldProviderHell.class, true); registerProviderType( 1, WorldProviderEnd.class, false); @@ -54,13 +58,27 @@ public class DimensionManager { if (!providers.containsKey(providerType)) { - throw new IllegalArgumentException(String.format("Failed to register dimensiuon for id %d, provider type %d does not exist", id, providerType)); + throw new IllegalArgumentException(String.format("Failed to register dimension for id %d, provider type %d does not exist", id, providerType)); } if (dimensions.containsKey(id)) { - throw new IllegalArgumentException(String.format("Failed to register dimensiuon for id %d, One is already registered", id)); + throw new IllegalArgumentException(String.format("Failed to register dimension for id %d, One is already registered", id)); } dimensions.put(id, providerType); + if (id >= nextFree) + nextFree = id+1; + } + + /** + * For unregistering a dimension when the save is changed (disconnected from a server or loaded a new save + */ + public static void unregisterDimension(int id) + { + if (!dimensions.containsKey(id)) + { + throw new IllegalArgumentException(String.format("Failed to unregister dimension for id %d; No provider registered", id)); + } + dimensions.remove(id); } public static int getProviderType(int dim) @@ -79,17 +97,26 @@ public class DimensionManager public static Integer[] getIDs() { - return dimensions.keySet().toArray(new Integer[0]); + return worlds.keySet().toArray(new Integer[worlds.size()]); //Only loaded dims, since usually used to cycle through loaded worlds } public static void setWorld(int id, WorldServer world) { - worlds.put(id, world); + if (world != null) { + worlds.put(id, world); + MinecraftServer.getServer().worldTickTimes.put(id, new long[100]); + } else { + worlds.remove(id); + MinecraftServer.getServer().worldTickTimes.remove(id); + } ArrayList tmp = new ArrayList(); - tmp.add(worlds.get( 0)); - tmp.add(worlds.get(-1)); - tmp.add(worlds.get( 1)); + if (worlds.get( 0) != null) + tmp.add(worlds.get( 0)); + if (worlds.get(-1) != null) + tmp.add(worlds.get(-1)); + if (worlds.get( 1) != null) + tmp.add(worlds.get( 1)); for (Entry entry : worlds.entrySet()) { @@ -102,7 +129,32 @@ public class DimensionManager } MinecraftServer.getServer().worldServers = tmp.toArray(new WorldServer[0]); - MinecraftServer.getServer().worldTickTimes.put(id, new long[100]); + } + + public static void initDimension(int dim) { + WorldServer overworld = getWorld(0); + if (overworld == null) { + throw new RuntimeException("Cannot Hotload Dim: Overworld is not Loaded!"); + } + try { + DimensionManager.getProviderType(dim); + } catch (Exception e) { + System.err.println("Cannot Hotload Dim: " + e.getMessage()); + return; //If a provider hasn't been registered then we can't hotload the dim + } + MinecraftServer mcServer = overworld.getMinecraftServer(); + ISaveHandler savehandler = overworld.getSaveHandler(); + WorldSettings worldSettings = new WorldSettings(overworld.getWorldInfo()); + + WorldServer world = (dim == 0 ? overworld : new WorldServerMulti(mcServer, savehandler, overworld.getWorldInfo().getWorldName(), dim, worldSettings, overworld, mcServer.theProfiler)); + MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(world)); + world.addWorldAccess(new WorldManager(mcServer, world)); + if (!mcServer.isSinglePlayer()) + { + world.getWorldInfo().setGameType(mcServer.getGameType()); + } + + mcServer.setDifficultyForAllWorlds(mcServer.getDifficulty()); } public static WorldServer getWorld(int id) @@ -138,7 +190,7 @@ public class DimensionManager } else { - return null; + throw new RuntimeException(String.format("No WorldProvider bound for dimension %d", dim)); //It's going to crash anyway at this point. Might as well be informative } } catch (Exception e) @@ -148,4 +200,29 @@ public class DimensionManager throw new RuntimeException(e); } } + + public static void unloadWorld(int id) { + unloadQueue.add(id); + } + + /* + * To be called by the server at the appropriate time, do not call from mod code. + */ + public static void unloadWorlds(Hashtable worldTickTimes) { + for (int id : unloadQueue) { + try { + worlds.get(id).saveAllChunks(true, null); + } catch (MinecraftException e) { + e.printStackTrace(); + } + MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(worlds.get(id))); + ((WorldServer)worlds.get(id)).flush(); + setWorld(id, null); + } + unloadQueue.clear(); + } + + public static int getNextFreeDimId() { + return nextFree; + } } From bbc5673ad8a8661e94eea97cb7c025f21461f60a Mon Sep 17 00:00:00 2001 From: XCompWiz Date: Wed, 3 Oct 2012 02:37:27 +0300 Subject: [PATCH 2/5] Adds world unloading and hotloading calls Adds world unloaded message to MinecraftServer on save. Adds world unloading calls to chunk provider/manager when all chunks are unloaded. Adds call in MinecraftServer getWorld to hotload world if it isn't loaded. --- .../server/MinecraftServer.java.patch | 40 +++++++++++++++---- .../src/ChunkProviderServer.java.patch | 22 ++++++++-- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/patches/common/net/minecraft/server/MinecraftServer.java.patch b/patches/common/net/minecraft/server/MinecraftServer.java.patch index c566ecb59..78854a3a3 100644 --- a/patches/common/net/minecraft/server/MinecraftServer.java.patch +++ b/patches/common/net/minecraft/server/MinecraftServer.java.patch @@ -95,7 +95,15 @@ this.setDifficultyForAllWorlds(this.getDifficulty()); this.initialWorldChunkLoad(); } -@@ -622,13 +602,13 @@ +@@ -408,6 +388,7 @@ + for (int var3 = 0; var3 < var2; ++var3) + { + WorldServer var4 = var1[var3]; ++ MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(var4)); + var4.flush(); + } + +@@ -622,13 +603,13 @@ { this.theProfiler.startSection("levels"); @@ -113,26 +121,36 @@ this.theProfiler.startSection(var4.getWorldInfo().getWorldName()); if (this.tickCounter % 20 == 0) -@@ -659,7 +639,7 @@ +@@ -659,9 +640,11 @@ } } - this.timeOfLastDimensionTick[var1][this.tickCounter % 100] = System.nanoTime() - var2; +- } +- + worldTickTimes.get(id)[this.tickCounter % 100] = System.nanoTime() - var2; - } - ++ } ++ ++ this.theProfiler.endStartSection("dim_unloading"); ++ DimensionManager.unloadWorlds(worldTickTimes); this.theProfiler.endStartSection("connection"); -@@ -717,7 +697,8 @@ + this.getNetworkThread().networkTick(); + this.theProfiler.endStartSection("players"); +@@ -717,7 +700,12 @@ */ public WorldServer worldServerForDimension(int par1) { - return par1 == -1 ? this.worldServers[1] : (par1 == 1 ? this.worldServers[2] : this.worldServers[0]); + WorldServer ret = DimensionManager.getWorld(par1); -+ return (ret != null ? ret : DimensionManager.getWorld(0)); ++ if (ret == null) { ++ DimensionManager.initDimension(par1); ++ ret = DimensionManager.getWorld(par1); ++ } ++ return ret; } @SideOnly(Side.SERVER) -@@ -830,7 +811,7 @@ +@@ -830,7 +818,7 @@ public String getServerModName() { @@ -141,3 +159,11 @@ } /** +@@ -1104,6 +1092,7 @@ + + if (var2 != null) + { ++ MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(var2)); + var2.flush(); + } + } diff --git a/patches/common/net/minecraft/src/ChunkProviderServer.java.patch b/patches/common/net/minecraft/src/ChunkProviderServer.java.patch index f02696e50..3308ad2bf 100644 --- a/patches/common/net/minecraft/src/ChunkProviderServer.java.patch +++ b/patches/common/net/minecraft/src/ChunkProviderServer.java.patch @@ -1,15 +1,25 @@ --- ../src_base/common/net/minecraft/src/ChunkProviderServer.java +++ ../src_work/common/net/minecraft/src/ChunkProviderServer.java -@@ -7,6 +7,8 @@ +@@ -7,6 +7,9 @@ import java.util.List; import java.util.Set; ++import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.common.ForgeChunkManager; + import cpw.mods.fml.common.registry.GameRegistry; public class ChunkProviderServer implements IChunkProvider -@@ -93,7 +95,11 @@ +@@ -50,7 +53,7 @@ + */ + public void unloadChunksIfNotNearSpawn(int par1, int par2) + { +- if (this.currentServer.provider.canRespawnHere()) ++ if (this.currentServer.provider.canRespawnHere() && DimensionManager.shouldLoadSpawn(currentServer.provider.dimensionId)) + { + ChunkCoordinates var3 = this.currentServer.getSpawnPoint(); + int var4 = par1 * 16 + 8 - var3.posX; +@@ -93,7 +96,11 @@ if (var5 == null) { @@ -22,7 +32,7 @@ if (var5 == null) { -@@ -274,6 +280,11 @@ +@@ -274,6 +281,11 @@ { if (!this.currentServer.canNotSave) { @@ -34,11 +44,15 @@ for (int var1 = 0; var1 < 100; ++var1) { if (!this.chunksToUnload.isEmpty()) -@@ -286,6 +297,7 @@ +@@ -286,6 +298,11 @@ this.chunksToUnload.remove(var2); this.loadedChunkHashMap.remove(var2.longValue()); this.loadedChunks.remove(var3); + ForgeChunkManager.putDormantChunk(ChunkCoordIntPair.chunkXZ2Int(var3.xPosition, var3.zPosition), var3); ++ if(loadedChunks.size() == 0 && ForgeChunkManager.getPersistentChunksFor(currentServer).size() == 0 && !DimensionManager.shouldLoadSpawn(currentServer.provider.dimensionId)) { ++ DimensionManager.unloadWorld(currentServer.provider.dimensionId); ++ return currentChunkProvider.unload100OldestChunks(); ++ } } } From babc12d2b5b1882ca1f334f938255aa748710bfd Mon Sep 17 00:00:00 2001 From: XCompWiz Date: Wed, 3 Oct 2012 02:41:32 +0300 Subject: [PATCH 3/5] MapStorage Fix Fixes setting and timing of map storage object to allow for the WorldProvider to use it during initialization Forces single instance of map storage object (per side) Moves setting of spawn to after provider setup --- .../common/net/minecraft/src/World.java.patch | 141 ++++++++++++------ .../net/minecraft/src/WorldClient.java.patch | 11 +- 2 files changed, 100 insertions(+), 52 deletions(-) diff --git a/patches/common/net/minecraft/src/World.java.patch b/patches/common/net/minecraft/src/World.java.patch index f3dd5ac00..e9566e415 100644 --- a/patches/common/net/minecraft/src/World.java.patch +++ b/patches/common/net/minecraft/src/World.java.patch @@ -28,19 +28,62 @@ /** * boolean; if true updates scheduled by scheduleBlockUpdate happen immediately */ -@@ -132,6 +151,11 @@ - * Gets the biome for a given set of x/z coordinates +@@ -133,6 +152,11 @@ */ public BiomeGenBase getBiomeGenForCoords(int par1, int par2) -+ { + { + return provider.getBiomeGenForCoords(par1, par2); + } + + public BiomeGenBase getBiomeGenForCoordsBody(int par1, int par2) - { ++ { if (this.blockExists(par1, 0, par2)) { -@@ -269,7 +293,8 @@ + Chunk var3 = this.getChunkFromBlockCoords(par1, par2); +@@ -162,8 +186,11 @@ + this.theProfiler = par5Profiler; + this.worldInfo = new WorldInfo(par4WorldSettings, par2Str); + this.provider = par3WorldProvider; +- this.mapStorage = new MapStorage(par1ISaveHandler); +- par3WorldProvider.registerWorld(this); ++ } ++ // Broken up so that the WorldClient gets the chance to set the mapstorage object before the dimension initializes ++ @SideOnly(Side.CLIENT) ++ protected void finishSetup() { ++ this.provider.registerWorld(this); + this.chunkProvider = this.createChunkProvider(); + this.calculateInitialSkylight(); + this.calculateInitialWeather(); +@@ -177,7 +204,7 @@ + this.isRemote = false; + this.saveHandler = par1ISaveHandler; + this.theProfiler = par5Profiler; +- this.mapStorage = new MapStorage(par1ISaveHandler); ++ this.mapStorage = getMapStorage(par1ISaveHandler); + this.worldInfo = par1ISaveHandler.loadWorldInfo(); + + if (par4WorldProvider != null) +@@ -215,6 +242,19 @@ + this.calculateInitialWeather(); + } + ++ private static MapStorage s_mapStorage; ++ private static ISaveHandler s_savehandler; ++ //Provides a solution for different worlds getting different copies of the same data, potentially rewriting the data or causing race conditions/stale data ++ //Buildcraft has suffered from the issue this fixes. If you load the same data from two different worlds they can get two different copies of the same object, thus the last saved gets final say. ++ private MapStorage getMapStorage(ISaveHandler savehandler) ++ { ++ if (s_savehandler != savehandler || s_mapStorage == null) { ++ s_mapStorage = new MapStorage(savehandler); ++ s_savehandler = savehandler; ++ } ++ return s_mapStorage; ++ } ++ + /** + * Creates the chunk provider for this world. Called in the constructor. Retrieves provider from worldProvider? + */ +@@ -269,7 +309,8 @@ */ public boolean isAirBlock(int par1, int par2, int par3) { @@ -50,7 +93,7 @@ } /** -@@ -278,7 +303,8 @@ +@@ -278,7 +319,8 @@ public boolean blockHasTileEntity(int par1, int par2, int par3) { int var4 = this.getBlockId(par1, par2, par3); @@ -60,7 +103,7 @@ } /** -@@ -980,7 +1006,7 @@ +@@ -980,7 +1022,7 @@ */ public boolean isDaytime() { @@ -69,7 +112,7 @@ } /** -@@ -1012,7 +1038,7 @@ +@@ -1012,7 +1054,7 @@ int var12 = this.getBlockMetadata(var8, var9, var10); Block var13 = Block.blocksList[var11]; @@ -78,7 +121,7 @@ { MovingObjectPosition var14 = var13.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3); -@@ -1212,6 +1238,12 @@ +@@ -1212,6 +1254,12 @@ */ public void playSoundAtEntity(Entity par1Entity, String par2Str, float par3, float par4) { @@ -91,7 +134,7 @@ if (par1Entity != null && par2Str != null) { Iterator var5 = this.worldAccesses.iterator(); -@@ -1312,6 +1344,11 @@ +@@ -1312,6 +1360,11 @@ EntityPlayer var5 = (EntityPlayer)par1Entity; this.playerEntities.add(var5); this.updateAllPlayersSleepingFlag(); @@ -103,7 +146,7 @@ } this.getChunkFromChunkCoords(var2, var3).addEntity(par1Entity); -@@ -1563,6 +1600,12 @@ +@@ -1563,6 +1616,12 @@ * Calculates the color for the skybox */ public Vec3 getSkyColor(Entity par1Entity, float par2) @@ -116,7 +159,7 @@ { float var3 = this.getCelestialAngle(par2); float var4 = MathHelper.cos(var3 * (float)Math.PI * 2.0F) * 2.0F + 0.5F; -@@ -1658,6 +1701,12 @@ +@@ -1658,6 +1717,12 @@ @SideOnly(Side.CLIENT) public Vec3 drawClouds(float par1) { @@ -129,7 +172,7 @@ float var2 = this.getCelestialAngle(par1); float var3 = MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F; -@@ -1736,7 +1785,7 @@ +@@ -1736,7 +1801,7 @@ { int var5 = var3.getBlockID(par1, var4, par2); @@ -138,7 +181,7 @@ { return var4 + 1; } -@@ -1751,6 +1800,12 @@ +@@ -1751,6 +1816,12 @@ * How bright are stars in the sky */ public float getStarBrightness(float par1) @@ -151,7 +194,7 @@ { float var2 = this.getCelestialAngle(par1); float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.25F); -@@ -1893,7 +1948,7 @@ +@@ -1893,7 +1964,7 @@ if (var8 != null) { @@ -160,7 +203,7 @@ } } } -@@ -1903,6 +1958,10 @@ +@@ -1903,6 +1974,10 @@ if (!this.entityRemoval.isEmpty()) { @@ -171,7 +214,7 @@ this.loadedTileEntityList.removeAll(this.entityRemoval); this.entityRemoval.clear(); } -@@ -1923,7 +1982,9 @@ +@@ -1923,7 +1998,9 @@ { this.loadedTileEntityList.add(var9); } @@ -182,7 +225,7 @@ if (this.chunkExists(var9.xCoord >> 4, var9.zCoord >> 4)) { Chunk var10 = this.getChunkFromChunkCoords(var9.xCoord >> 4, var9.zCoord >> 4); -@@ -1933,8 +1994,6 @@ +@@ -1933,8 +2010,6 @@ var10.setChunkBlockTileEntity(var9.xCoord & 15, var9.yCoord, var9.zCoord & 15, var9); } } @@ -191,7 +234,7 @@ } } -@@ -1947,13 +2006,13 @@ +@@ -1947,13 +2022,13 @@ public void addTileEntity(Collection par1Collection) { @@ -212,7 +255,7 @@ } } -@@ -1973,9 +2032,17 @@ +@@ -1973,9 +2048,17 @@ { int var3 = MathHelper.floor_double(par1Entity.posX); int var4 = MathHelper.floor_double(par1Entity.posZ); @@ -233,7 +276,7 @@ { par1Entity.lastTickPosX = par1Entity.posX; par1Entity.lastTickPosY = par1Entity.posY; -@@ -2210,6 +2277,14 @@ +@@ -2210,6 +2293,14 @@ { return true; } @@ -248,7 +291,7 @@ } } } -@@ -2516,25 +2591,21 @@ +@@ -2516,25 +2607,21 @@ */ public void setBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity) { @@ -289,7 +332,7 @@ } } -@@ -2543,27 +2614,10 @@ +@@ -2543,27 +2630,10 @@ */ public void removeBlockTileEntity(int par1, int par2, int par3) { @@ -321,7 +364,7 @@ } } -@@ -2589,7 +2643,8 @@ +@@ -2589,7 +2659,8 @@ */ public boolean isBlockNormalCube(int par1, int par2, int par3) { @@ -331,7 +374,7 @@ } /** -@@ -2597,8 +2652,7 @@ +@@ -2597,8 +2668,7 @@ */ public boolean doesBlockHaveSolidTopSurface(int par1, int par2, int par3) { @@ -341,7 +384,7 @@ } /** -@@ -2614,7 +2668,7 @@ +@@ -2614,7 +2684,7 @@ if (var5 != null && !var5.isEmpty()) { Block var6 = Block.blocksList[this.getBlockId(par1, par2, par3)]; @@ -350,7 +393,7 @@ } else { -@@ -2645,8 +2699,7 @@ +@@ -2645,8 +2715,7 @@ */ public void setAllowedSpawnTypes(boolean par1, boolean par2) { @@ -360,7 +403,7 @@ } /** -@@ -2662,6 +2715,11 @@ +@@ -2662,6 +2731,11 @@ */ private void calculateInitialWeather() { @@ -372,7 +415,7 @@ if (this.worldInfo.isRaining()) { this.rainingStrength = 1.0F; -@@ -2677,6 +2735,11 @@ +@@ -2677,6 +2751,11 @@ * Updates all weather states. */ protected void updateWeather() @@ -384,7 +427,7 @@ { if (!this.provider.hasNoSky) { -@@ -2779,12 +2842,14 @@ +@@ -2779,12 +2858,14 @@ public void toggleRain() { @@ -400,7 +443,7 @@ this.theProfiler.startSection("buildList"); int var1; EntityPlayer var2; -@@ -2891,6 +2956,11 @@ +@@ -2891,6 +2972,11 @@ */ public boolean canBlockFreeze(int par1, int par2, int par3, boolean par4) { @@ -412,7 +455,7 @@ BiomeGenBase var5 = this.getBiomeGenForCoords(par1, par3); float var6 = var5.getFloatTemperature(); -@@ -2948,6 +3018,11 @@ +@@ -2948,6 +3034,11 @@ * Tests whether or not snow can be placed at a given location */ public boolean canSnowAt(int par1, int par2, int par3) @@ -424,7 +467,7 @@ { BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3); float var5 = var4.getFloatTemperature(); -@@ -3041,7 +3116,7 @@ +@@ -3041,7 +3132,7 @@ private int computeBlockLightValue(int par1, int par2, int par3, int par4, int par5, int par6) { @@ -433,7 +476,7 @@ int var8 = this.getSavedLightValue(EnumSkyBlock.Block, par2 - 1, par3, par4) - par6; int var9 = this.getSavedLightValue(EnumSkyBlock.Block, par2 + 1, par3, par4) - par6; int var10 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 - 1, par4) - par6; -@@ -3176,7 +3251,7 @@ +@@ -3176,7 +3267,7 @@ int var21 = var24 + (var18 / 2 + 1) % 3 / 2 * var19; int var22 = var12 + (var18 / 2 + 2) % 3 / 2 * var19; var14 = this.getSavedLightValue(par1EnumSkyBlock, var20, var21, var22); @@ -442,7 +485,7 @@ if (var23 == 0) { -@@ -3207,7 +3282,7 @@ +@@ -3207,7 +3298,7 @@ var12 = (var9 >> 12 & 63) - 32 + par4; var13 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12); var14 = this.getBlockId(var10, var24, var12); @@ -451,7 +494,7 @@ if (var15 == 0) { -@@ -3309,10 +3384,10 @@ +@@ -3309,10 +3400,10 @@ public List getEntitiesWithinAABBExcludingEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB) { this.entitiesWithinAABBExcludingEntity.clear(); @@ -466,7 +509,7 @@ for (int var7 = var3; var7 <= var4; ++var7) { -@@ -3333,10 +3408,10 @@ +@@ -3333,10 +3424,10 @@ */ public List getEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB) { @@ -481,7 +524,7 @@ ArrayList var7 = new ArrayList(); for (int var8 = var3; var8 <= var4; ++var8) -@@ -3425,11 +3500,14 @@ +@@ -3425,11 +3516,14 @@ */ public void addLoadedEntities(List par1List) { @@ -499,7 +542,7 @@ } } -@@ -3466,7 +3544,10 @@ +@@ -3466,7 +3560,10 @@ { var9 = null; } @@ -511,7 +554,7 @@ return par1 > 0 && var9 == null && var10.canPlaceBlockOnSide(this, par2, par3, par4, par6); } } -@@ -3656,7 +3737,7 @@ +@@ -3656,7 +3753,7 @@ */ public void setWorldTime(long par1) { @@ -520,7 +563,7 @@ } /** -@@ -3664,12 +3745,12 @@ +@@ -3664,12 +3761,12 @@ */ public long getSeed() { @@ -535,7 +578,7 @@ } /** -@@ -3677,13 +3758,13 @@ +@@ -3677,13 +3774,13 @@ */ public ChunkCoordinates getSpawnPoint() { @@ -551,7 +594,7 @@ } @SideOnly(Side.CLIENT) -@@ -3707,7 +3788,10 @@ +@@ -3707,7 +3804,10 @@ if (!this.loadedEntityList.contains(par1Entity)) { @@ -563,7 +606,7 @@ } } -@@ -3715,6 +3799,11 @@ +@@ -3715,6 +3815,11 @@ * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here. */ public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4) @@ -575,7 +618,7 @@ { return true; } -@@ -3827,8 +3916,7 @@ +@@ -3827,8 +3932,7 @@ */ public boolean isBlockHighHumidity(int par1, int par2, int par3) { @@ -585,7 +628,7 @@ } /** -@@ -3882,7 +3970,7 @@ +@@ -3882,7 +3986,7 @@ */ public int getHeight() { @@ -594,7 +637,7 @@ } /** -@@ -3890,7 +3978,7 @@ +@@ -3890,7 +3994,7 @@ */ public int getActualHeight() { @@ -603,7 +646,7 @@ } /** -@@ -3936,7 +4024,7 @@ +@@ -3936,7 +4040,7 @@ */ public double getHorizon() { @@ -612,7 +655,7 @@ } /** -@@ -3964,4 +4052,75 @@ +@@ -3964,4 +4068,75 @@ var7.destroyBlockPartially(par1, par2, par3, par4, par5); } } diff --git a/patches/minecraft/net/minecraft/src/WorldClient.java.patch b/patches/minecraft/net/minecraft/src/WorldClient.java.patch index f4ab05d48..d2c70e486 100644 --- a/patches/minecraft/net/minecraft/src/WorldClient.java.patch +++ b/patches/minecraft/net/minecraft/src/WorldClient.java.patch @@ -9,15 +9,20 @@ @SideOnly(Side.CLIENT) public class WorldClient extends World -@@ -40,6 +42,7 @@ +@@ -38,8 +40,11 @@ + super(new SaveHandlerMP(), "MpServer", WorldProvider.getProviderForDimension(par3), par2WorldSettings, par5Profiler); + this.sendQueue = par1NetClientHandler; this.difficultySetting = par4; ++ this.mapStorage = par1NetClientHandler.mapStorage; ++ this.isRemote = true; ++ finishSetup(); this.setSpawnLocation(8, 64, 8); - this.mapStorage = par1NetClientHandler.mapStorage; +- this.mapStorage = par1NetClientHandler.mapStorage; + MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(this)); } /** -@@ -265,6 +268,12 @@ +@@ -265,6 +270,12 @@ */ protected void updateWeather() { From e53595f1f526e75014e08a4a7f01e1ce649675ea Mon Sep 17 00:00:00 2001 From: XCompWiz Date: Wed, 3 Oct 2012 02:42:40 +0300 Subject: [PATCH 4/5] Lighting Time fix score_under's lighting fix that limits and fairly distributes the amount of time spent on recalculating lighting --- .../net/minecraft/src/WorldServer.java.patch | 61 +++++++++++++++---- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/patches/common/net/minecraft/src/WorldServer.java.patch b/patches/common/net/minecraft/src/WorldServer.java.patch index 63f63bfec..9df3ad353 100644 --- a/patches/common/net/minecraft/src/WorldServer.java.patch +++ b/patches/common/net/minecraft/src/WorldServer.java.patch @@ -21,7 +21,17 @@ public class WorldServer extends World { -@@ -71,6 +78,7 @@ +@@ -50,6 +57,9 @@ + /** An IntHashMap of entity IDs (integers) to their Entity objects. */ + private IntHashMap entityIdMap; + ++ /** Stores the recently processed (lighting) chunks */ ++ protected Set doneChunks = new HashSet(); ++ + public WorldServer(MinecraftServer par1MinecraftServer, ISaveHandler par2ISaveHandler, String par3Str, int par4, WorldSettings par5WorldSettings, Profiler par6Profiler) + { + super(par2ISaveHandler, par3Str, par5WorldSettings, WorldProvider.getProviderForDimension(par4), par6Profiler); +@@ -71,6 +81,7 @@ { this.pendingTickListEntries = new TreeSet(); } @@ -29,7 +39,7 @@ } /** -@@ -179,10 +187,7 @@ +@@ -179,10 +190,7 @@ private void resetRainAndThunder() { @@ -41,7 +51,32 @@ } public boolean areAllPlayersAsleep() -@@ -270,7 +275,7 @@ +@@ -253,6 +261,14 @@ + int var1 = 0; + int var2 = 0; + Iterator var3 = this.activeChunkSet.iterator(); ++ ++ doneChunks.retainAll(activeChunkSet); ++ if (doneChunks.size() == activeChunkSet.size()) ++ { ++ doneChunks.clear(); ++ } ++ ++ final long time = -System.currentTimeMillis(); + + while (var3.hasNext()) + { +@@ -263,14 +279,16 @@ + Chunk var7 = this.getChunkFromChunkCoords(var4.chunkXPos, var4.chunkZPos); + this.moodSoundAndLightCheck(var5, var6, var7); + this.theProfiler.endStartSection("tickChunk"); +- var7.updateSkylight(); ++ if (System.currentTimeMillis() + time <= 4 && doneChunks.add(var4)) { //Limits and evenly distributes the lighting update time ++ var7.updateSkylight(); ++ } + this.theProfiler.endStartSection("thunder"); + int var8; + int var9; int var10; int var11; @@ -50,7 +85,7 @@ { this.updateLCG = this.updateLCG * 3 + 1013904223; var8 = this.updateLCG >> 2; -@@ -288,7 +293,7 @@ +@@ -288,7 +306,7 @@ this.theProfiler.endStartSection("iceandsnow"); int var13; @@ -59,7 +94,7 @@ { this.updateLCG = this.updateLCG * 3 + 1013904223; var8 = this.updateLCG >> 2; -@@ -362,7 +367,8 @@ +@@ -362,7 +380,8 @@ public void scheduleBlockUpdate(int par1, int par2, int par3, int par4, int par5) { NextTickListEntry var6 = new NextTickListEntry(par1, par2, par3, par4); @@ -69,7 +104,7 @@ if (this.scheduledUpdatesAreImmediate) { -@@ -418,7 +424,7 @@ +@@ -418,7 +437,7 @@ */ public void updateEntities() { @@ -78,7 +113,7 @@ { if (this.updateEntityTick++ >= 60) { -@@ -462,7 +468,8 @@ +@@ -462,7 +481,8 @@ this.pendingTickListEntries.remove(var4); this.field_73064_N.remove(var4); @@ -88,7 +123,7 @@ if (this.checkChunksExist(var4.xCoord - var5, var4.yCoord - var5, var4.zCoord - var5, var4.xCoord + var5, var4.yCoord + var5, var4.zCoord + var5)) { -@@ -559,15 +566,27 @@ +@@ -559,15 +579,27 @@ public List getAllTileEntityInBox(int par1, int par2, int par3, int par4, int par5, int par6) { ArrayList var7 = new ArrayList(); @@ -125,7 +160,7 @@ } } -@@ -578,6 +597,11 @@ +@@ -578,6 +610,11 @@ * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here. */ public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4) @@ -137,7 +172,7 @@ { int var5 = MathHelper.abs_int(par2 - this.worldInfo.getSpawnX()); int var6 = MathHelper.abs_int(par4 - this.worldInfo.getSpawnZ()); -@@ -587,7 +611,7 @@ +@@ -587,7 +624,7 @@ var6 = var5; } @@ -146,7 +181,7 @@ } protected void initialize(WorldSettings par1WorldSettings) -@@ -670,7 +694,7 @@ +@@ -670,7 +707,7 @@ */ protected void createBonusChest() { @@ -155,7 +190,7 @@ for (int var2 = 0; var2 < 10; ++var2) { -@@ -713,6 +737,7 @@ +@@ -713,6 +750,7 @@ } this.chunkProvider.saveChunks(par1, par2IProgressUpdate); @@ -163,7 +198,7 @@ } } -@@ -971,4 +996,9 @@ +@@ -971,4 +1009,9 @@ { return this.thePlayerManager; } From a50abc514f030a7c339c2c97d95a7f961db00b80 Mon Sep 17 00:00:00 2001 From: XCompWiz Date: Wed, 3 Oct 2012 02:45:36 +0300 Subject: [PATCH 5/5] Server player concurrency fix Fixes an issue where the server can move a player while the player is moving, process the player's last move (putting the player back where they were before the teleport), and then complain about the player moving too fast when the client catches up to it's new position. Also fixes this issue while riding an entity. Only affects player client/server movement sync. --- .../minecraft/src/NetServerHandler.java.patch | 58 ++++++++++++++++--- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/patches/common/net/minecraft/src/NetServerHandler.java.patch b/patches/common/net/minecraft/src/NetServerHandler.java.patch index 8d3989870..2f931547f 100644 --- a/patches/common/net/minecraft/src/NetServerHandler.java.patch +++ b/patches/common/net/minecraft/src/NetServerHandler.java.patch @@ -11,7 +11,39 @@ public class NetServerHandler extends NetHandler { -@@ -310,7 +314,7 @@ +@@ -193,6 +197,11 @@ + if (this.playerEntity.ridingEntity != null) + { + this.playerEntity.ridingEntity.updateRiderPosition(); ++ } ++ ++ if (!this.hasMoved) //Fixes teleportation kick while riding entities ++ { ++ return; + } + + this.mcServer.getConfigurationManager().serverUpdateMountedMovingPlayer(this.playerEntity); +@@ -285,6 +294,11 @@ + this.playerEntity.addExhaustion(0.2F); + } + ++ if (!this.hasMoved) //Fixes "Moved Too Fast" kick when being teleported while moving ++ { ++ return; ++ } ++ + this.playerEntity.moveEntity(var13, var15, var17); + this.playerEntity.onGround = par1Packet10Flying.onGround; + this.playerEntity.addMovementStat(var13, var15, var17); +@@ -307,10 +321,15 @@ + logger.warning(this.playerEntity.username + " moved wrongly!"); + } + ++ if (!this.hasMoved) //Fixes "Moved Too Fast" kick when being teleported while moving ++ { ++ return; ++ } ++ this.playerEntity.setPositionAndRotation(var5, var7, var9, var11, var12); boolean var32 = var2.getCollidingBoundingBoxes(this.playerEntity, this.playerEntity.boundingBox.copy().contract((double)var27, (double)var27, (double)var27)).isEmpty(); @@ -20,7 +52,7 @@ { this.setPlayerLocation(this.lastPosX, this.lastPosY, this.lastPosZ, var11, var12); return; -@@ -318,7 +322,7 @@ +@@ -318,7 +337,7 @@ AxisAlignedBB var33 = this.playerEntity.boundingBox.copy().expand((double)var27, (double)var27, (double)var27).addCoord(0.0D, -0.55D, 0.0D); @@ -29,7 +61,19 @@ { if (var29 >= -0.03125D) { -@@ -395,7 +399,10 @@ +@@ -337,6 +356,11 @@ + this.ticksForFloatKick = 0; + } + ++ if (!this.hasMoved) //Fixes "Moved Too Fast" kick when being teleported while moving ++ { ++ return; ++ } ++ + this.playerEntity.onGround = par1Packet10Flying.onGround; + this.mcServer.getConfigurationManager().serverUpdateMountedMovingPlayer(this.playerEntity); + this.playerEntity.updateFlyingState(this.playerEntity.posY - var3, par1Packet10Flying.onGround); +@@ -395,7 +419,10 @@ double var12 = this.playerEntity.posZ - ((double)var7 + 0.5D); double var14 = var8 * var8 + var10 * var10 + var12 * var12; @@ -41,7 +85,7 @@ { return; } -@@ -417,8 +424,9 @@ +@@ -417,8 +444,9 @@ if (par1Packet14BlockDig.status == 0) { @@ -53,7 +97,7 @@ this.playerEntity.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(var5, var6, var7, var2)); } else -@@ -479,7 +487,11 @@ +@@ -479,7 +507,11 @@ return; } @@ -66,7 +110,7 @@ } else if (par1Packet15Place.getYPosition() >= this.mcServer.getBuildLimit() - 1 && (par1Packet15Place.getDirection() == 1 || par1Packet15Place.getYPosition() >= this.mcServer.getBuildLimit())) { -@@ -497,7 +509,9 @@ +@@ -497,7 +529,9 @@ var12 = var11; } @@ -77,7 +121,7 @@ { this.playerEntity.theItemInWorldManager.activateBlockOrUseItem(this.playerEntity, var2, var3, var5, var6, var7, var8, par1Packet15Place.getXOffset(), par1Packet15Place.getYOffset(), par1Packet15Place.getZOffset()); } -@@ -798,7 +812,7 @@ +@@ -798,7 +832,7 @@ return; }