From d21e3ae218f566b69f1a445a2cb0dd36da09fcdb Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 9 Sep 2012 23:47:07 -0400 Subject: [PATCH] Simple chunkloading implementation --- .../net/minecraftforge/common/ForgeHooks.java | 56 +++++++++++++++++++ .../minecraftforge/common/MinecraftForge.java | 41 ++++++++++++++ .../src/ChunkProviderServer.java.patch | 14 +++++ .../common/net/minecraft/src/World.java.patch | 22 +++++++- .../net/minecraft/src/WorldInfo.java.patch | 38 +++++++++++++ .../net/minecraft/src/WorldServer.java.patch | 29 ++++++++++ 6 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 patches/common/net/minecraft/src/ChunkProviderServer.java.patch create mode 100644 patches/common/net/minecraft/src/WorldInfo.java.patch diff --git a/common/net/minecraftforge/common/ForgeHooks.java b/common/net/minecraftforge/common/ForgeHooks.java index 05ca957db..49ba9c76e 100644 --- a/common/net/minecraftforge/common/ForgeHooks.java +++ b/common/net/minecraftforge/common/ForgeHooks.java @@ -1,8 +1,13 @@ package net.minecraftforge.common; import java.util.*; +import java.util.Map.Entry; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.Loader; import net.minecraft.src.*; import net.minecraftforge.event.entity.item.ItemTossEvent; @@ -354,4 +359,55 @@ public class ForgeHooks player.joinEntityItemWithWorld(event.entityItem); return event.entityItem; } + public static void dumpPersistentChunks(WorldInfo worldInfo, ListMultimap persistentChunks) + { + worldInfo.forgeWorldData = new NBTTagCompound(); + + NBTTagList chunkDataList = new NBTTagList(); + for (Entry> entry : persistentChunks.asMap().entrySet()) + { + NBTTagCompound dataList = new NBTTagCompound(); + dataList.setIntArray("Chunk", new int[] { entry.getKey().chunkXPos, entry.getKey().chunkZPos }); + NBTTagList modList = new NBTTagList(); + for (String modId : entry.getValue()) + { + modList.appendTag(new NBTTagString(modId, "")); + } + dataList.setTag("Mods", modList); + chunkDataList.appendTag(dataList); + } + worldInfo.forgeWorldData.setTag("PersistentChunks", chunkDataList); + } + + public static ListMultimap loadPersistentChunkData(WorldInfo worldInfo) + { + ArrayListMultimap chunkList = ArrayListMultimap.create(); + + if (worldInfo == null || worldInfo.forgeWorldData == null) + { + return chunkList; + } + + NBTTagList chunkDataList = worldInfo.forgeWorldData.getTagList("PersistentChunks"); + for (int i = 0; i < chunkDataList.tagCount(); i++) + { + NBTTagCompound dataList = (NBTTagCompound) chunkDataList.tagAt(i); + int[] ccpairint = dataList.getIntArray("Chunk"); + ChunkCoordIntPair ccpair = new ChunkCoordIntPair(ccpairint[0], ccpairint[1]); + NBTTagList modList = dataList.getTagList("Mods"); + for (int j = 0; j < modList.tagCount(); j++) + { + String modId = modList.tagAt(j).getName(); + if (Loader.isModLoaded(modId)) + { + chunkList.put(ccpair, modId); + } + else + { + FMLLog.warning("The mod %s is not present - it's chunks will not be persisted any longer", modId); + } + } + } + return chunkList; + } } diff --git a/common/net/minecraftforge/common/MinecraftForge.java b/common/net/minecraftforge/common/MinecraftForge.java index fe1dc8323..46c138803 100644 --- a/common/net/minecraftforge/common/MinecraftForge.java +++ b/common/net/minecraftforge/common/MinecraftForge.java @@ -3,7 +3,10 @@ package net.minecraftforge.common; import java.lang.reflect.Constructor; import java.util.*; +import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.ModContainer; import net.minecraft.src.*; import net.minecraftforge.common.ForgeHooks.GrassEntry; @@ -199,4 +202,42 @@ public class MinecraftForge { return "Minecraft Forge "+ ForgeVersion.getVersion(); } + + /** + * Force a chunk to remain loaded by the supplied mod + * + * @param chunk the chunk to keep loaded + * @param world the world holding the chunk + * @param mod the mod (either {@link Mod} or {@link BaseMod}) that wishes to force the load + */ + public static void forceChunkLoaded(ChunkCoordIntPair chunk, World world, Object mod) + { + ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod); + if (mc == null) + { + FMLLog.warning("Attempt to force chunk load for a non-existent mod %s", mod.getClass().getName()); + return; + } + String modId = mc.getModId(); + world.getPersistentChunks().put(chunk, modId); + } + + /** + * Stop forcing the chunk to remain loaded by the supplied mod (other mods may still + * keep the chunk loaded, however) + * @param chunk the chunk to keep loaded + * @param world the world holding the chunk + * @param mod the mod (either {@link Mod} or {@link BaseMod}) that wishes to unforce the load + */ + public static void unforceChunkLoaded(ChunkCoordIntPair chunk, World world, Object mod) + { + ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod); + if (mc == null) + { + FMLLog.warning("Attempt to unforce chunk load for a non-existent mod %s", mod.getClass().getName()); + return; + } + String modId = mc.getModId(); + world.getPersistentChunks().remove(chunk, modId); + } } diff --git a/patches/common/net/minecraft/src/ChunkProviderServer.java.patch b/patches/common/net/minecraft/src/ChunkProviderServer.java.patch new file mode 100644 index 000000000..dd1190aa3 --- /dev/null +++ b/patches/common/net/minecraft/src/ChunkProviderServer.java.patch @@ -0,0 +1,14 @@ +--- ../src_base/common/net/minecraft/src/ChunkProviderServer.java ++++ ../src_work/common/net/minecraft/src/ChunkProviderServer.java +@@ -274,6 +274,11 @@ + { + if (!this.currentServer.canNotSave) + { ++ for (ChunkCoordIntPair forced : currentServer.persistentChunks.keySet()) ++ { ++ this.chunksToUnload.remove(ChunkCoordIntPair.chunkXZ2Int(forced.chunkXPos, forced.chunkZPos)); ++ } ++ + for (int var1 = 0; var1 < 100; ++var1) + { + if (!this.chunksToUnload.isEmpty()) diff --git a/patches/common/net/minecraft/src/World.java.patch b/patches/common/net/minecraft/src/World.java.patch index a2f80ae6a..1281acb8a 100644 --- a/patches/common/net/minecraft/src/World.java.patch +++ b/patches/common/net/minecraft/src/World.java.patch @@ -4,6 +4,10 @@ import java.util.Random; import java.util.Set; ++import com.google.common.collect.ArrayListMultimap; ++import com.google.common.collect.ListMultimap; ++ ++import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.event.entity.EntityEvent; @@ -23,6 +27,12 @@ /** * boolean; if true updates scheduled by scheduleBlockUpdate happen immediately */ +@@ -128,6 +145,7 @@ + */ + public boolean isRemote; + ++ protected ListMultimap persistentChunks; + /** @@ -132,6 +146,11 @@ * Gets the biome for a given set of x/z coordinates */ @@ -47,6 +57,9 @@ this.calculateInitialSkylight(); this.calculateInitialWeather(); ++ ++ persistentChunks = ForgeHooks.loadPersistentChunkData(this.worldInfo); ++ + MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(this)); } @@ -226,9 +239,11 @@ @@ -1974,8 +2030,14 @@ int var3 = MathHelper.floor_double(par1Entity.posX); int var4 = MathHelper.floor_double(par1Entity.posZ); - byte var5 = 32; +- byte var5 = 32; - - if (!par2 || this.checkChunksExist(var3 - var5, 0, var4 - var5, var3 + var5, 0, var4 + var5)) ++ boolean isForced = persistentChunks.containsKey(new ChunkCoordIntPair(var3 >> 4, var4 >> 4)); ++ byte var5 = isForced ? (byte)0 : 32; + boolean canUpdate = !par2 || this.checkChunksExist(var3 - var5, 0, var4 - var5, var3 + var5, 0, var4 + var5); + if (!canUpdate) + { @@ -658,5 +673,10 @@ + } + + return block.isBlockSolidOnSide(this, X, Y, Z, side); ++ } ++ ++ public ListMultimap getPersistentChunks() ++ { ++ return persistentChunks; + } } diff --git a/patches/common/net/minecraft/src/WorldInfo.java.patch b/patches/common/net/minecraft/src/WorldInfo.java.patch new file mode 100644 index 000000000..2edcb48e5 --- /dev/null +++ b/patches/common/net/minecraft/src/WorldInfo.java.patch @@ -0,0 +1,38 @@ +--- ../src_base/common/net/minecraft/src/WorldInfo.java ++++ ../src_work/common/net/minecraft/src/WorldInfo.java +@@ -1,5 +1,6 @@ + package net.minecraft.src; + ++import net.minecraftforge.common.ForgeHooks; + import cpw.mods.fml.common.Side; + import cpw.mods.fml.common.asm.SideOnly; + +@@ -59,6 +60,8 @@ + private boolean hardcore; + private boolean allowCommands; + private boolean initialized; ++ ++ public NBTTagCompound forgeWorldData; + + protected WorldInfo() + { +@@ -139,6 +142,10 @@ + { + this.playerTag = par1NBTTagCompound.getCompoundTag("Player"); + this.dimension = this.playerTag.getInteger("Dimension"); ++ } ++ if (par1NBTTagCompound.hasKey("ForgeData")) ++ { ++ this.forgeWorldData = par1NBTTagCompound.getCompoundTag("ForgeData"); + } + } + +@@ -228,6 +235,8 @@ + { + par1NBTTagCompound.setCompoundTag("Player", par2NBTTagCompound); + } ++ ++ par1NBTTagCompound.setCompoundTag("ForgeData", forgeWorldData); + } + + /** diff --git a/patches/common/net/minecraft/src/WorldServer.java.patch b/patches/common/net/minecraft/src/WorldServer.java.patch index 41ac8ecdc..7a8e0e768 100644 --- a/patches/common/net/minecraft/src/WorldServer.java.patch +++ b/patches/common/net/minecraft/src/WorldServer.java.patch @@ -50,6 +50,26 @@ { this.updateLCG = this.updateLCG * 3 + 1013904223; var8 = this.updateLCG >> 2; +@@ -362,7 +367,8 @@ + public void scheduleBlockUpdate(int par1, int par2, int par3, int par4, int par5) + { + NextTickListEntry var6 = new NextTickListEntry(par1, par2, par3, par4); +- byte var7 = 8; ++ boolean isForced = persistentChunks.containsKey(new ChunkCoordIntPair(var6.xCoord >> 4, var6.zCoord >> 4)); ++ byte var7 = isForced ? (byte)0 : 8; + + if (this.scheduledUpdatesAreImmediate) + { +@@ -462,7 +468,8 @@ + + this.pendingTickListEntries.remove(var4); + this.field_73064_N.remove(var4); +- byte var5 = 8; ++ boolean isForced = persistentChunks.containsKey(new ChunkCoordIntPair(var4.xCoord >> 4, var4.zCoord >> 4)); ++ byte var5 = isForced ? (byte)0 : 8; + + if (this.checkChunksExist(var4.xCoord - var5, var4.yCoord - var5, var4.zCoord - var5, var4.xCoord + var5, var4.yCoord + var5, var4.zCoord + var5)) + { @@ -559,15 +562,27 @@ public List getAllTileEntityInBox(int par1, int par2, int par3, int par4, int par5, int par6) { @@ -117,6 +137,15 @@ for (int var2 = 0; var2 < 10; ++var2) { +@@ -702,6 +721,8 @@ + par2IProgressUpdate.displayProgressMessage("Saving level"); + } + ++ ForgeHooks.dumpPersistentChunks(worldInfo, persistentChunks); ++ + this.saveLevel(); + + if (par2IProgressUpdate != null) @@ -713,6 +733,7 @@ }