diff --git a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java index 762711a..b335954 100644 --- a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java +++ b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java @@ -14,6 +14,7 @@ import java.io.File; import java.io.FileInputStream; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -89,6 +90,7 @@ import cpw.mods.fml.common.WrongMinecraftVersionException; import cpw.mods.fml.common.eventhandler.EventBus; import cpw.mods.fml.common.network.FMLNetworkEvent; +import cpw.mods.fml.common.network.internal.FMLNetworkHandler; import cpw.mods.fml.common.registry.GameData; import cpw.mods.fml.common.registry.LanguageRegistry; import cpw.mods.fml.common.toposort.ModSortingException; @@ -160,7 +162,7 @@ private Map extraServerListData; private Map serverDataTag; - private NetHandlerPlayClient currentPlayClient; + private WeakReference currentPlayClient; /** * Called to start the whole game off @@ -227,6 +229,10 @@ haltGame("There was a severe problem during mod loading that has caused the game to fail", le); return; } + finally + { + client.refreshResources(); + } Map> sharedModList = (Map>) Launch.blackboard.get("modList"); if (sharedModList == null) @@ -279,7 +285,8 @@ return; } - // Reload resources + // Reload resources has to happen early, or minecraft itself has resource loading issues + // This is a second refresh for mods that register stuff late! client.refreshResources(); RenderingRegistry.instance().loadEntityRenderers((Map, Render>)RenderManager.instance.entityRenderMap); guiFactories = HashBiMap.create(); @@ -564,12 +571,6 @@ } } - @Override - public void updateResourcePackList() - { - client.refreshResources(); - } - public IResourcePack getResourcePackFor(String modId) { return resourcePackMap.get(modId); @@ -596,7 +597,7 @@ @Override public INetHandler getClientPlayHandler() { - return this.currentPlayClient; + return this.currentPlayClient == null ? null : this.currentPlayClient.get(); } @Override public NetworkManager getClientToServerNetworkManager() @@ -701,7 +702,8 @@ modListBldr.put(modObj.get("modid").getAsString(), modObj.get("version").getAsString()); } - serverDataTag.put(data, new ExtendedServerListData(type, true, modListBldr.build(), !moddedClientAllowed)); + Map modListMap = modListBldr.build(); + serverDataTag.put(data, new ExtendedServerListData(type, FMLNetworkHandler.checkModList(modListMap, Side.CLIENT) == null, modListMap, !moddedClientAllowed)); } else { @@ -810,7 +812,7 @@ public void setPlayClient(NetHandlerPlayClient netHandlerPlayClient) { playClientBlock.countDown(); - this.currentPlayClient = netHandlerPlayClient; + this.currentPlayClient = new WeakReference(netHandlerPlayClient); } @Override diff --git a/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java b/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java index b99f81a..871c4aa 100644 --- a/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java +++ b/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java @@ -27,7 +27,7 @@ super(parent, "", "", 0); this.dirName = dirName; this.saveName = saveName; - this.zip = new File(FMLClientHandler.instance().getClient().mcDataDir,String.format("%s-%2$td%2$tm%2$ty%2$tH%2$tM%2$tS.zip", saveName, System.currentTimeMillis())); + this.zip = new File(FMLClientHandler.instance().getClient().mcDataDir,String.format("%s-%2$td%2$tm%2$ty%2$tH%2$tM%2$tS.zip", dirName, System.currentTimeMillis())); } @Override public void drawScreen(int par1, int par2, float par3) diff --git a/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java b/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java index 574285e..21641a2 100644 --- a/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java +++ b/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java @@ -514,11 +514,6 @@ sidedDelegate.addModAsResource(container); } - public void updateResourcePackList() - { - sidedDelegate.updateResourcePackList(); - } - public String getCurrentLanguage() { diff --git a/src/main/java/cpw/mods/fml/common/FMLContainer.java b/src/main/java/cpw/mods/fml/common/FMLContainer.java index 8ab3c2b..a872c83 100644 --- a/src/main/java/cpw/mods/fml/common/FMLContainer.java +++ b/src/main/java/cpw/mods/fml/common/FMLContainer.java @@ -22,7 +22,6 @@ import java.util.Map.Entry; import java.util.Set; -import net.minecraft.item.Item; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; diff --git a/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java b/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java index 7155e0f..0f85977 100644 --- a/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java +++ b/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java @@ -46,8 +46,6 @@ void addModAsResource(ModContainer container); - void updateResourcePackList(); - String getCurrentLanguage(); void serverStopped(); diff --git a/src/main/java/cpw/mods/fml/common/LoadController.java b/src/main/java/cpw/mods/fml/common/LoadController.java index 206da0f..cc4398f 100644 --- a/src/main/java/cpw/mods/fml/common/LoadController.java +++ b/src/main/java/cpw/mods/fml/common/LoadController.java @@ -109,7 +109,6 @@ } eventChannels = eventBus.build(); - FMLCommonHandler.instance().updateResourcePackList(); } public void distributeStateMessage(LoaderState state, Object... eventData) diff --git a/src/main/java/cpw/mods/fml/common/ZipperUtil.java b/src/main/java/cpw/mods/fml/common/ZipperUtil.java index ce513ac..98774a5 100644 --- a/src/main/java/cpw/mods/fml/common/ZipperUtil.java +++ b/src/main/java/cpw/mods/fml/common/ZipperUtil.java @@ -15,8 +15,6 @@ import com.google.common.io.Files; -import cpw.mods.fml.client.FMLClientHandler; - /** * Copied from http://stackoverflow.com/questions/1399126/java-util-zip-recreating-directory-structure * because the code looked very tidy and neat. Thanks, McDowell! @@ -64,24 +62,20 @@ public static void backupWorld() throws IOException { String dirName = FMLCommonHandler.instance().getMinecraftServerInstance().getFolderName(); - String saveName; - if (FMLCommonHandler.instance().getSide().isClient()) - { - saveName = FMLCommonHandler.instance().getMinecraftServerInstance().getWorldName(); - } - else - { - saveName = dirName; - } - - backupWorld(dirName, saveName); + backupWorld(dirName); } + @Deprecated public static void backupWorld(String dirName, String saveName) throws IOException { + backupWorld(dirName); + } + + public static void backupWorld(String dirName) throws IOException + { File dstFolder = FMLCommonHandler.instance().getSavesDirectory(); - File zip = new File(dstFolder, String.format("%s-%2$tY%2$tm%2$td-%2$tH%2$tM%2$tS.zip", saveName, System.currentTimeMillis())); + File zip = new File(dstFolder, String.format("%s-%2$tY%2$tm%2$td-%2$tH%2$tM%2$tS.zip", dirName, System.currentTimeMillis())); try { diff --git a/src/main/java/cpw/mods/fml/common/functions/GenericIterableFactory.java b/src/main/java/cpw/mods/fml/common/functions/GenericIterableFactory.java new file mode 100644 index 0000000..4623361 --- /dev/null +++ b/src/main/java/cpw/mods/fml/common/functions/GenericIterableFactory.java @@ -0,0 +1,10 @@ +package cpw.mods.fml.common.functions; + +import com.google.common.collect.Iterables; + +public class GenericIterableFactory { + public static Iterable newCastingIterable(Iterable input, Class type) + { + return Iterables.transform(input, new TypeCastFunction(type)); + } +} \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/functions/TypeCastFunction.java b/src/main/java/cpw/mods/fml/common/functions/TypeCastFunction.java new file mode 100644 index 0000000..77693b7 --- /dev/null +++ b/src/main/java/cpw/mods/fml/common/functions/TypeCastFunction.java @@ -0,0 +1,17 @@ +package cpw.mods.fml.common.functions; + +import com.google.common.base.Function; + +public class TypeCastFunction implements Function { + private Class type; + public TypeCastFunction(Class type) + { + this.type = type; + } + + @Override + public T apply(Object input) + { + return type.cast(input); + } +} \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/network/FMLIndexedMessageToMessageCodec.java b/src/main/java/cpw/mods/fml/common/network/FMLIndexedMessageToMessageCodec.java index 81cf39c..bb0a405 100644 --- a/src/main/java/cpw/mods/fml/common/network/FMLIndexedMessageToMessageCodec.java +++ b/src/main/java/cpw/mods/fml/common/network/FMLIndexedMessageToMessageCodec.java @@ -8,6 +8,7 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageCodec; import io.netty.util.AttributeKey; +import java.lang.ref.WeakReference; import java.util.List; import org.apache.logging.log4j.Level; import cpw.mods.fml.common.FMLLog; @@ -22,13 +23,13 @@ * Make this accessible to subclasses */ - protected static final AttributeKey> INBOUNDPACKETTRACKER = new AttributeKey>("fml:inboundpacket"); + public static final AttributeKey>> INBOUNDPACKETTRACKER = new AttributeKey>>("fml:inboundpacket"); @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { super.handlerAdded(ctx); - ctx.attr(INBOUNDPACKETTRACKER).set(new ThreadLocal()); + ctx.attr(INBOUNDPACKETTRACKER).set(new ThreadLocal>()); } public FMLIndexedMessageToMessageCodec addDiscriminator(int discriminator, Class type) @@ -49,7 +50,8 @@ buffer.writeByte(discriminator); encodeInto(ctx, msg, buffer); FMLProxyPacket proxy = new FMLProxyPacket(buffer.copy(), ctx.channel().attr(NetworkRegistry.FML_CHANNEL).get()); - FMLProxyPacket old = ctx.attr(INBOUNDPACKETTRACKER).get().get(); + WeakReference ref = ctx.attr(INBOUNDPACKETTRACKER).get().get(); + FMLProxyPacket old = ref == null ? null : ref.get(); if (old != null) { proxy.setDispatcher(old.getDispatcher()); @@ -71,7 +73,7 @@ throw new NullPointerException("Undefined message for discriminator " + discriminator + " in channel " + msg.channel()); } A newMsg = clazz.newInstance(); - ctx.attr(INBOUNDPACKETTRACKER).get().set(msg); + ctx.attr(INBOUNDPACKETTRACKER).get().set(new WeakReference(msg)); decodeInto(ctx, payload.slice(), newMsg); out.add(newMsg); } diff --git a/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java b/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java index eca3216..1c4def8 100644 --- a/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java +++ b/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java @@ -31,8 +31,10 @@ import net.minecraft.util.ChatComponentText; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec; import cpw.mods.fml.common.network.FMLNetworkEvent; import cpw.mods.fml.common.network.FMLNetworkException; +import cpw.mods.fml.common.network.FMLOutboundHandler; import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.common.network.internal.FMLMessage; import cpw.mods.fml.common.network.internal.FMLNetworkHandler; @@ -368,6 +370,7 @@ { FMLCommonHandler.instance().bus().post(new FMLNetworkEvent.ServerDisconnectionFromClientEvent(manager)); } + cleanAttributes(ctx); ctx.disconnect(promise); } @@ -382,6 +385,7 @@ { FMLCommonHandler.instance().bus().post(new FMLNetworkEvent.ServerDisconnectionFromClientEvent(manager)); } + cleanAttributes(ctx); ctx.close(promise); } @@ -458,4 +462,14 @@ super.exceptionCaught(ctx, cause); } + // if we add any attributes, we should force removal of them here so that + //they do not hold references to the world and causes it to leak. + private void cleanAttributes(ChannelHandlerContext ctx) + { + ctx.channel().attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).remove(); + ctx.channel().attr(NetworkRegistry.NET_HANDLER).remove(); + ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).remove(); + this.handshakeChannel.attr(FML_DISPATCHER).remove(); + this.manager.channel().attr(FML_DISPATCHER).remove(); + } } \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/network/internal/FMLNetworkHandler.java b/src/main/java/cpw/mods/fml/common/network/internal/FMLNetworkHandler.java index c9332c7..9f86dd7 100644 --- a/src/main/java/cpw/mods/fml/common/network/internal/FMLNetworkHandler.java +++ b/src/main/java/cpw/mods/fml/common/network/internal/FMLNetworkHandler.java @@ -126,10 +126,14 @@ public static String checkModList(FMLHandshakeMessage.ModList modListPacket, Side side) { Map modList = modListPacket.modList(); + return checkModList(modList, side); + } + public static String checkModList(Map listData, Side side) + { List rejects = Lists.newArrayList(); for (Entry networkMod : NetworkRegistry.INSTANCE.registry().entrySet()) { - boolean result = networkMod.getValue().check(modList, side); + boolean result = networkMod.getValue().check(listData, side); if (!result) { rejects.add(networkMod.getKey()); diff --git a/src/main/java/cpw/mods/fml/common/network/internal/NetworkModHolder.java b/src/main/java/cpw/mods/fml/common/network/internal/NetworkModHolder.java index 10d7a77..4ee6714 100644 --- a/src/main/java/cpw/mods/fml/common/network/internal/NetworkModHolder.java +++ b/src/main/java/cpw/mods/fml/common/network/internal/NetworkModHolder.java @@ -17,6 +17,7 @@ import java.util.Set; import org.apache.logging.log4j.Level; +import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.SetMultimap; @@ -33,7 +34,7 @@ public class NetworkModHolder { - private abstract class NetworkChecker { + public abstract class NetworkChecker { public abstract boolean check(Map remoteVersions, Side side); } @@ -43,6 +44,11 @@ { return true; } + @Override + public String toString() + { + return "No network checking performed"; + } } private class DefaultNetworkChecker extends NetworkChecker { @Override @@ -50,7 +56,11 @@ { return remoteVersions.containsKey(container.getModId()) ? acceptVersion(remoteVersions.get(container.getModId())) : false; } - + @Override + public String toString() + { + return acceptableRange != null ? String.format("Accepting range %s", acceptableRange) : String.format("Accepting version %s", container.getVersion()); + } } private class MethodNetworkChecker extends NetworkChecker { @Override @@ -66,6 +76,11 @@ return false; } } + @Override + public String toString() + { + return String.format("Invoking method %s", checkHandler.getName()); + } } private static int assignedIds = 1; @@ -85,6 +100,12 @@ this.localId = assignedIds++; this.networkId = this.localId; } + public NetworkModHolder(ModContainer container, NetworkChecker checker) + { + this(container); + this.checker = Preconditions.checkNotNull(checker); + FMLLog.fine("The mod %s is using a custom checker %s", container.getModId(), checker.getClass().getName()); + } public NetworkModHolder(ModContainer container, Class modClass, String acceptableVersionRange, ASMDataTable table) { this(container); @@ -144,7 +165,12 @@ if (this.checkHandler != null) { this.checker = new MethodNetworkChecker(); - } else if (!Strings.isNullOrEmpty(acceptableVersionRange) && !acceptableVersionRange.equals('*')) + } + else if (!Strings.isNullOrEmpty(acceptableVersionRange) && acceptableVersionRange.equals("*")) + { + this.checker = new IgnoredChecker(); + } + else { try { @@ -155,9 +181,8 @@ FMLLog.log(Level.WARN, e, "Invalid bounded range %s specified for network mod id %s", acceptableVersionRange, container.getModId()); } this.checker = new DefaultNetworkChecker(); - } else { - this.checker = new IgnoredChecker(); } + FMLLog.finer("Mod %s is using network checker : %s", container.getModId(), this.checker); FMLLog.finer("Testing mod %s to verify it accepts its own version in a remote connection", container.getModId()); boolean acceptsSelf = acceptVersion(container.getVersion()); if (!acceptsSelf) diff --git a/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java b/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java index 5ee7cb4..28bdbac 100644 --- a/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java +++ b/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java @@ -6,17 +6,17 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import net.minecraft.block.Block; +import net.minecraft.item.ItemBlock; import net.minecraft.util.ObjectIntIdentityMap; import net.minecraft.util.RegistryNamespaced; -import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; import cpw.mods.fml.common.FMLLog; -import cpw.mods.fml.common.Loader; -import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.functions.GenericIterableFactory; public class FMLControlledNamespacedRegistry extends RegistryNamespaced { private final Class superType; @@ -38,7 +38,49 @@ this.minId = minIdValue; } - @SuppressWarnings("unchecked") + void validateContent(int maxId, String type, BitSet availabilityMap, Set blockedIds, FMLControlledNamespacedRegistry iBlockRegistry) + { + for (I obj : typeSafeIterable()) + { + int id = getId(obj); + String name = getNameForObject(obj); + + // id lookup failed -> obj is not in the obj<->id map + if (id < 0) throw new IllegalStateException(String.format("Registry entry for %s %s, name %s, doesn't yield an id.", type, obj, name)); + // id is too high + if (id > maxId) throw new IllegalStateException(String.format("Registry entry for %s %s, name %s uses the too large id %d.", type, obj, name)); + // name lookup failed -> obj is not in the obj<->name map + if (name == null) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, doesn't yield a name.", type, obj, id)); + // empty name + if (name.isEmpty()) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, yields an empty name.", type, obj, id)); + // non-prefixed name + if (name.indexOf(':') == -1) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, has the non-prefixed name %s.", type, obj, id, name)); + // id -> obj lookup is inconsistent + if (getRaw(id) != obj) throw new IllegalStateException(String.format("Registry entry for id %d, name %s, doesn't yield the expected %s %s.", id, name, type, obj)); + // name -> obj lookup is inconsistent + if (getRaw(name) != obj) throw new IllegalStateException(String.format("Registry entry for name %s, id %d, doesn't yield the expected %s %s.", name, id, type, obj)); + // name -> id lookup is inconsistent + if (getId(name) != id) throw new IllegalStateException(String.format("Registry entry for name %s doesn't yield the expected id %d.", name, id)); + // id isn't marked as unavailable + if (!availabilityMap.get(id)) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, name %s, marked as empty.", type, obj, id, name)); + // entry is blocked, thus should be empty + if (blockedIds.contains(id)) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, name %s, marked as dangling.", type, obj, id, name)); + + if (obj instanceof ItemBlock) + { + Block block = ((ItemBlock) obj).field_150939_a; + + // verify matching block entry + if (iBlockRegistry.getId(block) != id) + { + throw new IllegalStateException(String.format("Registry entry for ItemBlock %s, id %d, is missing or uses the non-matching id %d.", obj, id, iBlockRegistry.getId(block))); + } + // verify id range + if (id > GameData.MAX_BLOCK_ID) throw new IllegalStateException(String.format("ItemBlock %s uses the id %d outside the block id range", name, id)); + } + } + + } void set(FMLControlledNamespacedRegistry registry) { if (this.superType != registry.superType) throw new IllegalArgumentException("incompatible registry"); @@ -254,12 +296,12 @@ public Iterable typeSafeIterable() { - return Iterables.transform(this, new TypeCastFunction()); + Iterable self = this; + return GenericIterableFactory.newCastingIterable(self, superType); } // internal - @SuppressWarnings("unchecked") public void serializeInto(Map idMapping) // for saving { for (I thing : this.typeSafeIterable()) @@ -333,7 +375,6 @@ FMLLog.finer("Registry alias: %s -> %s", from, to); } - @SuppressWarnings("unchecked") Map getEntriesNotIn(FMLControlledNamespacedRegistry registry) { Map ret = new HashMap(); @@ -346,7 +387,6 @@ return ret; } - @SuppressWarnings("unchecked") void dump() { List ids = new ArrayList(); @@ -378,13 +418,4 @@ underlyingIntegerMap.func_148746_a(thing, id); // obj <-> id super.putObject(name, thing); // name <-> obj } - - private class TypeCastFunction implements Function - { - @Override - public I apply(Object o) - { - return superType.cast(o); - } - } } \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/registry/GameData.java b/src/main/java/cpw/mods/fml/common/registry/GameData.java index 5e93ad3..c412ee1 100644 --- a/src/main/java/cpw/mods/fml/common/registry/GameData.java +++ b/src/main/java/cpw/mods/fml/common/registry/GameData.java @@ -14,7 +14,6 @@ import java.io.File; import java.io.IOException; -import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; import java.util.HashSet; @@ -43,7 +42,6 @@ import com.google.common.collect.Table; import com.google.common.io.Files; -import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.Loader; @@ -56,10 +54,10 @@ import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier; public class GameData { - private static final int MIN_BLOCK_ID = 0; - private static final int MAX_BLOCK_ID = 4095; - private static final int MIN_ITEM_ID = 4096; - private static final int MAX_ITEM_ID = 31999; + static final int MIN_BLOCK_ID = 0; + static final int MAX_BLOCK_ID = 4095; + static final int MIN_ITEM_ID = 4096; + static final int MAX_ITEM_ID = 31999; private static final GameData mainData = new GameData(); @@ -244,6 +242,7 @@ for (Entry entry : dataList.entrySet()) { String itemName = entry.getKey(); + @SuppressWarnings("unused") String realName = itemName.substring(1); if (itemName.charAt(0) == '\u0001') // is a block @@ -351,7 +350,7 @@ { String mod = it.next(); - if (mod.equals("minecraft") || Loader.instance().isModLoaded(mod)) it.remove(); + if (mod.equals("minecraft") || Loader.isModLoaded(mod)) it.remove(); } if (!modsMissing.isEmpty()) @@ -687,7 +686,7 @@ private GameData() { - iBlockRegistry = new FMLControlledNamespacedRegistry("air", MAX_BLOCK_ID, MIN_BLOCK_ID, Block.class,'\u0001'); + iBlockRegistry = new FMLControlledNamespacedRegistry("minecraft:air", MAX_BLOCK_ID, MIN_BLOCK_ID, Block.class,'\u0001'); iItemRegistry = new FMLControlledNamespacedRegistry(null, MAX_ITEM_ID, MIN_ITEM_ID, Item.class,'\u0002'); availabilityMap = new BitSet(MAX_ITEM_ID + 1); blockedIds = new HashSet(); @@ -907,7 +906,6 @@ } } - @SuppressWarnings("unchecked") private void testConsistency() { // test if there's an entry for every set bit in availabilityMap for (int i = availabilityMap.nextSetBit(0); i >= 0; i = availabilityMap.nextSetBit(i+1)) @@ -922,50 +920,8 @@ { boolean isBlock = pass == 0; String type = isBlock ? "block" : "item"; - FMLControlledNamespacedRegistry registry = isBlock ? iBlockRegistry : iItemRegistry; - - // test if the registry is consistent - // test if there's a bit in availabilityMap set for every entry in the registry - // make sure it's not a blocked id - for (Object obj : registry) - { - int id = registry.getId(obj); - String name = registry.getNameForObject(obj); - - // id lookup failed -> obj is not in the obj<->id map - if (id < 0) throw new IllegalStateException(String.format("Registry entry for %s %s, name %s, doesn't yield an id.", type, obj, name)); - // id is too high - if (id > (isBlock ? MAX_BLOCK_ID : MAX_ITEM_ID)) throw new IllegalStateException(String.format("Registry entry for %s %s, name %s uses the too large id %d.", type, obj, name)); - // name lookup failed -> obj is not in the obj<->name map - if (name == null) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, doesn't yield a name.", type, obj, id)); - // empty name - if (name.isEmpty()) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, yields an empty name.", type, obj, id)); - // non-prefixed name - if (name.indexOf(':') == -1) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, has the non-prefixed name %s.", type, obj, id, name)); - // id -> obj lookup is inconsistent - if (registry.getRaw(id) != obj) throw new IllegalStateException(String.format("Registry entry for id %d, name %s, doesn't yield the expected %s %s.", id, name, type, obj)); - // name -> obj lookup is inconsistent - if (registry.getRaw(name) != obj) throw new IllegalStateException(String.format("Registry entry for name %s, id %d, doesn't yield the expected %s %s.", name, id, type, obj)); - // name -> id lookup is inconsistent - if (registry.getId(name) != id) throw new IllegalStateException(String.format("Registry entry for name %s doesn't yield the expected id %d.", name, id)); - // id isn't marked as unavailable - if (!availabilityMap.get(id)) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, name %s, marked as empty.", type, obj, id, name)); - // entry is blocked, thus should be empty - if (blockedIds.contains(id)) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, name %s, marked as dangling.", type, obj, id, name)); - - if (obj instanceof ItemBlock) - { - Block block = ((ItemBlock) obj).field_150939_a; - - // verify matching block entry - if (iBlockRegistry.getId(block) != id) - { - throw new IllegalStateException(String.format("Registry entry for ItemBlock %s, id %d, is missing or uses the non-matching id %d.", obj, id, iBlockRegistry.getId(block))); - } - // verify id range - if (id > MAX_BLOCK_ID) throw new IllegalStateException(String.format("ItemBlock %s uses the id %d outside the block id range", name, id)); - } - } + FMLControlledNamespacedRegistry registry = isBlock ? iBlockRegistry : iItemRegistry; + registry.validateContent((isBlock ? MAX_BLOCK_ID : MAX_ITEM_ID), type, availabilityMap, blockedIds, iBlockRegistry); } FMLLog.fine("Registry consistency check successful"); diff --git a/src/main/java/cpw/mods/fml/server/FMLServerHandler.java b/src/main/java/cpw/mods/fml/server/FMLServerHandler.java index f541c5a..8365ca3 100644 --- a/src/main/java/cpw/mods/fml/server/FMLServerHandler.java +++ b/src/main/java/cpw/mods/fml/server/FMLServerHandler.java @@ -34,6 +34,7 @@ import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.StartupQuery; import cpw.mods.fml.common.eventhandler.EventBus; +import cpw.mods.fml.common.functions.GenericIterableFactory; import cpw.mods.fml.common.network.FMLNetworkEvent; import cpw.mods.fml.common.registry.LanguageRegistry; import cpw.mods.fml.relauncher.Side; @@ -176,7 +177,8 @@ // rudimentary command processing, check for fml confirm/cancel and stop commands synchronized (dedServer.pendingCommandList) { - for (Iterator it = dedServer.pendingCommandList.iterator(); it.hasNext(); ) + + for (Iterator it = GenericIterableFactory.newCastingIterable(dedServer.pendingCommandList, ServerCommand.class).iterator(); it.hasNext();) { String cmd = it.next().command.trim().toLowerCase(); @@ -220,11 +222,6 @@ } @Override - public void updateResourcePackList() - { - - } - @Override public String getCurrentLanguage() { return "en_US"; diff --git a/src/main/java/net/minecraft/world/gen/feature/WorldGenBigTree.java b/src/main/java/net/minecraft/world/gen/feature/WorldGenBigTree.java index 6929ab7..753de3d 100644 --- a/src/main/java/net/minecraft/world/gen/feature/WorldGenBigTree.java +++ b/src/main/java/net/minecraft/world/gen/feature/WorldGenBigTree.java @@ -446,6 +446,7 @@ if (!this.validTreeLocation()) { + this.worldObj = null; //Fix vanilla Mem leak, holds latest world return false; } else @@ -454,6 +455,7 @@ this.generateLeaves(); this.generateTrunk(); this.generateLeafNodeBases(); + this.worldObj = null; //Fix vanilla Mem leak, holds latest world return true; } } diff --git a/src/main/java/net/minecraftforge/server/command/ForgeCommand.java b/src/main/java/net/minecraftforge/server/command/ForgeCommand.java index a9e4257..724f470 100644 --- a/src/main/java/net/minecraftforge/server/command/ForgeCommand.java +++ b/src/main/java/net/minecraftforge/server/command/ForgeCommand.java @@ -1,5 +1,6 @@ package net.minecraftforge.server.command; +import java.lang.ref.WeakReference; import java.text.DecimalFormat; import net.minecraft.command.CommandBase; import net.minecraft.command.ICommandSender; @@ -11,13 +12,13 @@ public class ForgeCommand extends CommandBase { - private MinecraftServer server; + private static final DecimalFormat timeFormatter = new DecimalFormat("########0.000"); + private WeakReference server; public ForgeCommand(MinecraftServer server) { - this.server = server; + this.server = new WeakReference(server); } - private static final DecimalFormat timeFormatter = new DecimalFormat("########0.000"); @Override public String getCommandName() @@ -109,17 +110,17 @@ { for (Integer dimId : DimensionManager.getIDs()) { - double worldTickTime = ForgeCommand.mean(this.server.worldTickTimes.get(dimId)) * 1.0E-6D; + double worldTickTime = ForgeCommand.mean(this.getServer().worldTickTimes.get(dimId)) * 1.0E-6D; double worldTPS = Math.min(1000.0/worldTickTime, 20); sender.addChatMessage(new ChatComponentTranslation("commands.forge.tps.summary",String.format("Dim %d", dimId), timeFormatter.format(worldTickTime), timeFormatter.format(worldTPS))); } - double meanTickTime = ForgeCommand.mean(this.server.tickTimeArray) * 1.0E-6D; + double meanTickTime = ForgeCommand.mean(this.getServer().tickTimeArray) * 1.0E-6D; double meanTPS = Math.min(1000.0/meanTickTime, 20); sender.addChatMessage(new ChatComponentTranslation("commands.forge.tps.summary","Overall", timeFormatter.format(meanTickTime), timeFormatter.format(meanTPS))); } else { - double worldTickTime = ForgeCommand.mean(this.server.worldTickTimes.get(dim)) * 1.0E-6D; + double worldTickTime = ForgeCommand.mean(this.getServer().worldTickTimes.get(dim)) * 1.0E-6D; double worldTPS = Math.min(1000.0/worldTickTime, 20); sender.addChatMessage(new ChatComponentTranslation("commands.forge.tps.summary",String.format("Dim %d", dim), timeFormatter.format(worldTickTime), timeFormatter.format(worldTPS))); } @@ -135,4 +136,9 @@ return sum / values.length; } + + private MinecraftServer getServer() + { + return this.server.get(); + } } diff --git a/src/main/resources/fmlversion.properties b/src/main/resources/fmlversion.properties index 87a9bc9..23d62b6 100644 --- a/src/main/resources/fmlversion.properties +++ b/src/main/resources/fmlversion.properties @@ -1,6 +1,6 @@ fmlbuild.major.number=7 fmlbuild.minor.number=2 -fmlbuild.revision.number=165 -fmlbuild.build.number=26 +fmlbuild.revision.number=172 +fmlbuild.build.number=27 fmlbuild.mcversion=1.7.2 fmlbuild.mcpversion=9.03