diff --git a/common/cpw/mods/fml/common/FMLCommonHandler.java b/common/cpw/mods/fml/common/FMLCommonHandler.java index 01b5a865d7..1fb809f16a 100644 --- a/common/cpw/mods/fml/common/FMLCommonHandler.java +++ b/common/cpw/mods/fml/common/FMLCommonHandler.java @@ -15,7 +15,9 @@ package cpw.mods.fml.common; import java.util.EnumSet; import java.util.List; +import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -25,11 +27,15 @@ import net.minecraft.src.DedicatedServer; import net.minecraft.src.Entity; import net.minecraft.src.EntityPlayer; import net.minecraft.src.EntityPlayerMP; +import net.minecraft.src.NBTBase; +import net.minecraft.src.NBTTagCompound; import net.minecraft.src.NetHandler; import net.minecraft.src.Packet131MapData; +import net.minecraft.src.SaveHandler; import net.minecraft.src.ServerListenThread; import net.minecraft.src.ThreadServerApplication; import net.minecraft.src.World; +import net.minecraft.src.WorldInfo; import com.google.common.base.Objects; import com.google.common.base.Strings; @@ -37,6 +43,9 @@ import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.Lists; +import com.google.common.collect.MapMaker; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import cpw.mods.fml.common.network.EntitySpawnAdjustmentPacket; import cpw.mods.fml.common.network.EntitySpawnPacket; @@ -75,6 +84,8 @@ public class FMLCommonHandler private boolean noForge; private List brandings; private List crashCallables = Lists.newArrayList(Loader.instance().getCallableCrashInformation()); + private Set handlerSet = Sets.newSetFromMap(new MapMaker().weakKeys().makeMap()); + public void beginLoading(IFMLSidedHandler handler) @@ -385,4 +396,46 @@ public class FMLCommonHandler { sidedDelegate.handleTinyPacket(handler, mapData); } + + public void handleWorldDataSave(SaveHandler handler, WorldInfo worldInfo, NBTTagCompound tagCompound) + { + for (ModContainer mc : Loader.instance().getModList()) + { + if (mc instanceof InjectedModContainer) + { + WorldAccessContainer wac = ((InjectedModContainer)mc).getWrappedWorldAccessContainer(); + if (wac != null) + { + NBTTagCompound dataForWriting = wac.getDataForWriting(handler, worldInfo); + tagCompound.func_74766_a(mc.getModId(), dataForWriting); + } + } + } + } + + public void handleWorldDataLoad(SaveHandler handler, WorldInfo worldInfo, NBTTagCompound tagCompound) + { + if (getEffectiveSide()!=Side.SERVER) + { + return; + } + if (handlerSet.contains(handler)) + { + return; + } + handlerSet.add(handler); + Map additionalProperties = Maps.newHashMap(); + worldInfo.setAdditionalProperties(additionalProperties); + for (ModContainer mc : Loader.instance().getModList()) + { + if (mc instanceof InjectedModContainer) + { + WorldAccessContainer wac = ((InjectedModContainer)mc).getWrappedWorldAccessContainer(); + if (wac != null) + { + wac.readData(handler, worldInfo, additionalProperties, tagCompound.func_74775_l(mc.getModId())); + } + } + } + } } diff --git a/common/cpw/mods/fml/common/FMLDummyContainer.java b/common/cpw/mods/fml/common/FMLDummyContainer.java index c70c859a92..364f580466 100644 --- a/common/cpw/mods/fml/common/FMLDummyContainer.java +++ b/common/cpw/mods/fml/common/FMLDummyContainer.java @@ -15,14 +15,26 @@ package cpw.mods.fml.common; import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import net.minecraft.src.NBTBase; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.NBTTagList; +import net.minecraft.src.NBTTagString; +import net.minecraft.src.SaveHandler; +import net.minecraft.src.WorldInfo; + +import com.google.common.collect.MapMaker; +import com.google.common.collect.Sets; import com.google.common.eventbus.EventBus; /** * @author cpw * */ -public class FMLDummyContainer extends DummyModContainer +public class FMLDummyContainer extends DummyModContainer implements WorldAccessContainer { public FMLDummyContainer() { @@ -49,4 +61,45 @@ public class FMLDummyContainer extends DummyModContainer { return true; } + + @Override + public NBTTagCompound getDataForWriting(SaveHandler handler, WorldInfo info) + { + NBTTagCompound fmlData = new NBTTagCompound(); + NBTTagList list = new NBTTagList(); + for (ModContainer mc : Loader.instance().getActiveModList()) + { + NBTTagCompound mod = new NBTTagCompound(); + mod.func_74778_a("ModId", mc.getModId()); + mod.func_74778_a("ModVersion", mc.getVersion()); + list.func_74742_a(mod); + } + fmlData.func_74782_a("ModList", list); + return fmlData; + } + + @Override + public void readData(SaveHandler handler, WorldInfo info, Map propertyMap, NBTTagCompound tag) + { + if (tag.func_74764_b("ModList")) + { + NBTTagList modList = tag.func_74761_m("ModList"); + for (int i = 0; i < modList.func_74745_c(); i++) + { + NBTTagCompound mod = (NBTTagCompound) modList.func_74743_b(i); + String modId = mod.func_74779_i("ModId"); + String modVersion = mod.func_74779_i("ModVersion"); + ModContainer container = Loader.instance().getIndexedModList().get(modId); + if (container == null) + { + FMLLog.severe("This world was saved with mod %s which appears to be missing, things may not work well", modId); + continue; + } + if (!modVersion.equals(container.getVersion())) + { + FMLLog.info("This world was saved with mod %s version %s and it is now at version %s, things may not work well", modId, modVersion, container.getVersion()); + } + } + } + } } diff --git a/common/cpw/mods/fml/common/InjectedModContainer.java b/common/cpw/mods/fml/common/InjectedModContainer.java index 6af15dbe52..68ef3cd479 100644 --- a/common/cpw/mods/fml/common/InjectedModContainer.java +++ b/common/cpw/mods/fml/common/InjectedModContainer.java @@ -117,4 +117,16 @@ public class InjectedModContainer implements ModContainer { return wrappedContainer.acceptableMinecraftVersionRange(); } + + public WorldAccessContainer getWrappedWorldAccessContainer() + { + if (wrappedContainer instanceof WorldAccessContainer) + { + return (WorldAccessContainer) wrappedContainer; + } + else + { + return null; + } + } } diff --git a/common/cpw/mods/fml/common/WorldAccessContainer.java b/common/cpw/mods/fml/common/WorldAccessContainer.java new file mode 100644 index 0000000000..c8a6c8d7da --- /dev/null +++ b/common/cpw/mods/fml/common/WorldAccessContainer.java @@ -0,0 +1,14 @@ +package cpw.mods.fml.common; + +import java.util.Map; + +import net.minecraft.src.NBTBase; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.SaveHandler; +import net.minecraft.src.WorldInfo; + +public interface WorldAccessContainer +{ + public NBTTagCompound getDataForWriting(SaveHandler handler, WorldInfo info); + public void readData(SaveHandler handler, WorldInfo info, Map propertyMap, NBTTagCompound tag); +} diff --git a/patches/common/net/minecraft/src/SaveHandler.java.patch b/patches/common/net/minecraft/src/SaveHandler.java.patch new file mode 100644 index 0000000000..273db86dec --- /dev/null +++ b/patches/common/net/minecraft/src/SaveHandler.java.patch @@ -0,0 +1,59 @@ +--- ../src-base/common/net/minecraft/src/SaveHandler.java ++++ ../src-work/common/net/minecraft/src/SaveHandler.java +@@ -7,6 +7,8 @@ + import java.io.FileOutputStream; + import java.io.IOException; + import java.util.logging.Logger; ++ ++import cpw.mods.fml.common.FMLCommonHandler; + + public class SaveHandler implements ISaveHandler, IPlayerFileData + { +@@ -97,14 +99,16 @@ + File var1 = new File(this.field_75770_b, "level.dat"); + NBTTagCompound var2; + NBTTagCompound var3; +- ++ WorldInfo worldInfo = null; + if (var1.exists()) + { + try + { + var2 = CompressedStreamTools.func_74796_a(new FileInputStream(var1)); + var3 = var2.func_74775_l("Data"); +- return new WorldInfo(var3); ++ worldInfo = new WorldInfo(var3); ++ FMLCommonHandler.instance().handleWorldDataLoad(worldInfo, var2); ++ return worldInfo; + } + catch (Exception var5) + { +@@ -120,7 +124,9 @@ + { + var2 = CompressedStreamTools.func_74796_a(new FileInputStream(var1)); + var3 = var2.func_74775_l("Data"); +- return new WorldInfo(var3); ++ worldInfo = new WorldInfo(var3); ++ FMLCommonHandler.instance().handleWorldDataLoad(worldInfo, var2); ++ return worldInfo; + } + catch (Exception var4) + { +@@ -136,7 +142,7 @@ + NBTTagCompound var3 = p_75755_1_.func_76082_a(p_75755_2_); + NBTTagCompound var4 = new NBTTagCompound(); + var4.func_74782_a("Data", var3); +- ++ FMLCommonHandler.instance().handleWorldDataSave(p_75755_1_, var4); + try + { + File var5 = new File(this.field_75770_b, "level.dat_new"); +@@ -174,7 +180,7 @@ + NBTTagCompound var2 = p_75761_1_.func_76066_a(); + NBTTagCompound var3 = new NBTTagCompound(); + var3.func_74782_a("Data", var2); +- ++ FMLCommonHandler.instance().handleWorldDataSave(p_75761_1_, var3); + try + { + File var4 = new File(this.field_75770_b, "level.dat_new"); 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 0000000000..0260406f7d --- /dev/null +++ b/patches/common/net/minecraft/src/WorldInfo.java.patch @@ -0,0 +1,44 @@ +--- ../src-base/common/net/minecraft/src/WorldInfo.java ++++ ../src-work/common/net/minecraft/src/WorldInfo.java +@@ -1,4 +1,8 @@ + package net.minecraft.src; ++ ++import java.util.Map; ++ ++import com.google.common.collect.Maps; + + import cpw.mods.fml.common.Side; + import cpw.mods.fml.common.asm.SideOnly; +@@ -26,6 +30,7 @@ + private boolean field_76111_s; + private boolean field_76110_t; + private boolean field_76109_u; ++ private Map additionalProperties; + + protected WorldInfo() + { +@@ -372,4 +377,24 @@ + { + this.field_76109_u = p_76091_1_; + } ++ ++ /** ++ * Allow access to additional mod specific world based properties ++ * Used by FML to store mod list associated with a world, and maybe an id map ++ * Used by Forge to store the dimensions available to a world ++ * @param additionalProperties ++ */ ++ public void setAdditionalProperties(Map additionalProperties) ++ { ++ // one time set for this ++ if (this.additionalProperties == null) ++ { ++ this.additionalProperties = additionalProperties; ++ } ++ } ++ ++ public NBTBase getAdditionalProperty(String additionalProperty) ++ { ++ return this.additionalProperties!=null? this.additionalProperties.get(additionalProperty) : null; ++ } + }