Fixing id map generation - should validate correctly now

This commit is contained in:
Christian 2012-12-09 22:24:16 -05:00
parent bccad16ea6
commit aee1a3f24d
10 changed files with 217 additions and 160 deletions

View file

@ -64,6 +64,7 @@ import cpw.mods.fml.common.network.EntitySpawnAdjustmentPacket;
import cpw.mods.fml.common.network.EntitySpawnPacket;
import cpw.mods.fml.common.network.ModMissingPacket;
import cpw.mods.fml.common.registry.EntityRegistry.EntityRegistration;
import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
import cpw.mods.fml.common.registry.IThrowableEntity;
@ -479,13 +480,13 @@ public class FMLClientHandler implements IFMLSidedHandler
if (response)
{
serverShouldBeKilledQuietly = false;
GameRegistry.releaseGate(true);
GameData.releaseGate(true);
client.continueWorldLoading();
}
else
{
serverShouldBeKilledQuietly = true;
GameRegistry.releaseGate(false);
GameData.releaseGate(false);
// Reset and clear the client state
client.func_71403_a((WorldClient)null);
client.func_71373_a(null);

View file

@ -30,6 +30,7 @@ import com.google.common.collect.MapMaker;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.ItemData;
@ -79,7 +80,7 @@ public class FMLDummyContainer extends DummyModContainer implements WorldAccessC
}
fmlData.func_74782_a("ModList", list);
NBTTagList itemList = new NBTTagList();
GameRegistry.writeItemData(itemList);
GameData.writeItemData(itemList);
fmlData.func_74782_a("ModItemData", itemList);
return fmlData;
}
@ -110,12 +111,12 @@ public class FMLDummyContainer extends DummyModContainer implements WorldAccessC
if (tag.func_74764_b("ModItemData"))
{
NBTTagList modList = tag.func_74761_m("ModItemData");
Set<ItemData> worldSaveItems = GameRegistry.buildWorldItemData(modList);
GameRegistry.validateWorldSave(worldSaveItems);
Set<ItemData> worldSaveItems = GameData.buildWorldItemData(modList);
GameData.validateWorldSave(worldSaveItems);
}
else
{
GameRegistry.validateWorldSave(null);
GameData.validateWorldSave(null);
}
}

View file

@ -0,0 +1,23 @@
--- common/cpw/mods/fml/common/FMLDummyContainer.java
+++ common/cpw/mods/fml/common/FMLDummyContainer.java
@@ -17,16 +17,16 @@
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
-import net.minecraft.nbt.*;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.storage.SaveHandler;
import net.minecraft.world.storage.WorldInfo;
-import com.google.common.collect.MapMaker;
-import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
+import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.ItemData;

View file

@ -15,6 +15,7 @@ import com.google.common.primitives.UnsignedBytes;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.ItemData;
import net.minecraft.src.CompressedStreamTools;
@ -77,14 +78,14 @@ public class ModIdMapPacket extends FMLPacket {
public void execute(INetworkManager network, FMLNetworkHandler handler, NetHandler netHandler, String userName)
{
byte[] allData = Bytes.concat(partials);
GameRegistry.initializeServerGate(1);
GameData.initializeServerGate(1);
try
{
NBTTagCompound serverList = CompressedStreamTools.func_74792_a(allData);
NBTTagList list = serverList.func_74761_m("List");
Set<ItemData> itemData = GameRegistry.buildWorldItemData(list);
GameRegistry.validateWorldSave(itemData);
MapDifference<Integer, ItemData> serverDifference = GameRegistry.gateWorldLoadingForValidation();
Set<ItemData> itemData = GameData.buildWorldItemData(list);
GameData.validateWorldSave(itemData);
MapDifference<Integer, ItemData> serverDifference = GameData.gateWorldLoadingForValidation();
if (serverDifference!=null)
{
FMLCommonHandler.instance().disconnectIDMismatch(serverDifference, netHandler, network);

View file

@ -25,6 +25,7 @@ import com.google.common.io.ByteStreams;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistry;
public class ModListResponsePacket extends FMLPacket
@ -127,7 +128,7 @@ public class ModListResponsePacket extends FMLPacket
pkt.field_73628_b = pkt.field_73629_c.length;
network.func_74429_a(pkt);
NBTTagList itemList = new NBTTagList();
GameRegistry.writeItemData(itemList);
GameData.writeItemData(itemList);
byte[][] registryPackets = FMLPacket.makePacketSet(MOD_IDMAP, itemList);
for (int i = 0; i < registryPackets.length; i++)
{

View file

@ -0,0 +1,157 @@
package cpw.mods.fml.common.registry;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import net.minecraft.src.Item;
import net.minecraft.src.NBTTagCompound;
import net.minecraft.src.NBTTagList;
import com.google.common.base.Function;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.LoaderState;
import cpw.mods.fml.common.ModContainer;
public class GameData {
private static Map<Integer, ItemData> idMap = Maps.newHashMap();
private static CountDownLatch serverValidationLatch;
private static CountDownLatch clientValidationLatch;
private static MapDifference<Integer, ItemData> difference;
private static boolean shouldContinue = true;
private static boolean isSaveValid = true;
public static void newItemAdded(Item item)
{
ModContainer mc = Loader.instance().activeModContainer();
if (mc == null)
{
mc = Loader.instance().getMinecraftModContainer();
if (Loader.instance().hasReachedState(LoaderState.AVAILABLE))
{
FMLLog.severe("It appears something has tried to allocate an Item outside of the initialization phase of Minecraft, this could be very bad for your network connectivity.");
}
}
String itemType = item.getClass().getName();
ItemData itemData = new ItemData(item, mc);
if (idMap.containsKey(item.field_77779_bT))
{
ItemData id = idMap.get(item.field_77779_bT);
FMLLog.warning("[ItemTracker] The mod %s is attempting to overwrite existing item at %d (%s from %s) with %s", mc.getModId(), id.itemId, id.itemType, id.modId, itemType);
}
idMap.put(item.field_77779_bT, itemData);
FMLLog.fine("[ItemTracker] Adding item %s(%d) owned by %s", item.getClass().getName(), item.field_77779_bT, mc.getModId());
}
public static void validateWorldSave(Set<ItemData> worldSaveItems)
{
isSaveValid = true;
shouldContinue = true;
// allow ourselves to continue if there's no saved data
if (worldSaveItems == null)
{
serverValidationLatch.countDown();
try
{
clientValidationLatch.await();
}
catch (InterruptedException e)
{
}
return;
}
Function<? super ItemData, Integer> idMapFunction = new Function<ItemData, Integer>() {
public Integer apply(ItemData input) {
return input.itemId;
};
};
Map<Integer,ItemData> worldMap = Maps.uniqueIndex(worldSaveItems,idMapFunction);
difference = Maps.difference(worldMap, idMap);
if (!difference.entriesDiffering().isEmpty() || !difference.entriesOnlyOnLeft().isEmpty())
{
isSaveValid = false;
serverValidationLatch.countDown();
}
else
{
isSaveValid = true;
serverValidationLatch.countDown();
}
try
{
clientValidationLatch.await();
if (!shouldContinue)
{
throw new RuntimeException("This server instance is going to stop abnormally because of a fatal ID mismatch");
}
}
catch (InterruptedException e)
{
}
}
public static void writeItemData(NBTTagList itemList)
{
for (ItemData dat : idMap.values())
{
itemList.func_74742_a(dat.toNBT());
}
}
/**
* Initialize the server gate
* @param gateCount the countdown amount. If it's 2 we're on the client and the client and server
* will wait at the latch. 1 is a server and the server will proceed
*/
public static void initializeServerGate(int gateCount)
{
serverValidationLatch = new CountDownLatch(gateCount - 1);
clientValidationLatch = new CountDownLatch(gateCount - 1);
}
public static MapDifference<Integer, ItemData> gateWorldLoadingForValidation()
{
try
{
serverValidationLatch.await();
if (!isSaveValid)
{
return difference;
}
}
catch (InterruptedException e)
{
}
difference = null;
return null;
}
public static void releaseGate(boolean carryOn)
{
shouldContinue = carryOn;
clientValidationLatch.countDown();
}
public static Set<ItemData> buildWorldItemData(NBTTagList modList)
{
Set<ItemData> worldSaveItems = Sets.newHashSet();
for (int i = 0; i < modList.func_74745_c(); i++)
{
NBTTagCompound mod = (NBTTagCompound) modList.func_74743_b(i);
ItemData dat = new ItemData(mod);
worldSaveItems.add(dat);
}
return worldSaveItems;
}
}

View file

@ -52,7 +52,6 @@ import cpw.mods.fml.common.ModContainer;
public class GameRegistry
{
private static Multimap<ModContainer, BlockProxy> blockRegistry = ArrayListMultimap.create();
private static Set<ItemData> itemRegistry = Sets.newHashSet();
private static Set<IWorldGenerator> worldGenerators = Sets.newHashSet();
private static List<IFuelHandler> fuelHandlers = Lists.newArrayList();
private static List<ICraftingHandler> craftingHandlers = Lists.newArrayList();
@ -302,133 +301,4 @@ public class GameRegistry
tracker.onPlayerRespawn(player);
}
public static void newItemAdded(Item item)
{
ModContainer mc = Loader.instance().activeModContainer();
if (mc == null)
{
mc = Loader.instance().getMinecraftModContainer();
if (Loader.instance().hasReachedState(LoaderState.AVAILABLE))
{
FMLLog.severe("It appears something has tried to allocate an Item outside of the initialization phase of Minecraft, this could be very bad for your network connectivity.");
}
}
String itemType = item.getClass().getName();
itemRegistry.add(new ItemData(item, mc));
System.out.printf("Adding item %s(%d) owned by %s\n", item.getClass().getName(), item.field_77779_bT, mc);
}
public static void validateWorldSave(Set<ItemData> worldSaveItems)
{
isSaveValid = true;
shouldContinue = true;
// allow ourselves to continue if there's no saved data
if (worldSaveItems == null)
{
serverValidationLatch.countDown();
try
{
clientValidationLatch.await();
}
catch (InterruptedException e)
{
}
return;
}
Function<? super ItemData, Integer> idMapFunction = new Function<ItemData, Integer>() {
public Integer apply(ItemData input) {
return input.itemId;
};
};
Map<Integer,ItemData> worldMap = Maps.uniqueIndex(worldSaveItems,idMapFunction);
Map<Integer,ItemData> gameMap = Maps.uniqueIndex(itemRegistry, idMapFunction);
difference = Maps.difference(worldMap, gameMap);
if (!difference.entriesDiffering().isEmpty() || !difference.entriesOnlyOnLeft().isEmpty())
{
isSaveValid = false;
serverValidationLatch.countDown();
}
else
{
isSaveValid = true;
serverValidationLatch.countDown();
}
try
{
clientValidationLatch.await();
if (!shouldContinue)
{
throw new RuntimeException("This server instance is going to stop abnormally because of a fatal ID mismatch");
}
}
catch (InterruptedException e)
{
}
}
public static void writeItemData(NBTTagList itemList)
{
for (ItemData dat : itemRegistry)
{
itemList.func_74742_a(dat.toNBT());
}
}
/**
* Initialize the server gate
* @param gateCount the countdown amount. If it's 2 we're on the client and the client and server
* will wait at the latch. 1 is a server and the server will proceed
*/
public static void initializeServerGate(int gateCount)
{
serverValidationLatch = new CountDownLatch(gateCount - 1);
clientValidationLatch = new CountDownLatch(gateCount - 1);
}
public static MapDifference<Integer, ItemData> gateWorldLoadingForValidation()
{
try
{
serverValidationLatch.await();
if (!isSaveValid)
{
return difference;
}
}
catch (InterruptedException e)
{
}
difference = null;
return null;
}
public static void releaseGate(boolean carryOn)
{
shouldContinue = carryOn;
clientValidationLatch.countDown();
}
public static Set<ItemData> buildWorldItemData(NBTTagList modList)
{
Set<ItemData> worldSaveItems = Sets.newHashSet();
for (int i = 0; i < modList.func_74745_c(); i++)
{
NBTTagCompound mod = (NBTTagCompound) modList.func_74743_b(i);
ItemData dat = new ItemData(mod);
worldSaveItems.add(dat);
}
return worldSaveItems;
}
private static CountDownLatch serverValidationLatch;
private static CountDownLatch clientValidationLatch;
private static MapDifference<Integer, ItemData> difference;
private static boolean shouldContinue = true;
private static boolean isSaveValid = true;
}

View file

@ -34,6 +34,7 @@ import cpw.mods.fml.common.network.EntitySpawnAdjustmentPacket;
import cpw.mods.fml.common.network.EntitySpawnPacket;
import cpw.mods.fml.common.network.ModMissingPacket;
import cpw.mods.fml.common.registry.EntityRegistry.EntityRegistration;
import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.ItemData;
import cpw.mods.fml.common.registry.LanguageRegistry;
@ -93,7 +94,7 @@ public class FMLServerHandler implements IFMLSidedHandler
{
Loader.instance().initializeMods();
LanguageRegistry.reloadLanguageTable();
GameRegistry.initializeServerGate(1);
GameData.initializeServerGate(1);
}
@Override

View file

@ -1,19 +1,20 @@
--- ../src-base/common/net/minecraft/src/Item.java
+++ ../src-work/common/net/minecraft/src/Item.java
@@ -2,6 +2,8 @@
@@ -2,6 +2,9 @@
import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.asm.SideOnly;
+import cpw.mods.fml.common.registry.GameData;
+import cpw.mods.fml.common.registry.GameRegistry;
+
import java.util.List;
import java.util.Random;
@@ -187,6 +189,7 @@
@@ -187,6 +190,7 @@
}
field_77698_e[256 + p_i3659_1_] = this;
+ GameRegistry.newItemAdded(this);
+ GameData.newItemAdded(this);
}
public Item func_77665_c(int p_77665_1_)

View file

@ -1,16 +1,17 @@
--- ../src-base/minecraft/net/minecraft/client/Minecraft.java
+++ ../src-work/minecraft/net/minecraft/client/Minecraft.java
@@ -2,6 +2,9 @@
@@ -2,6 +2,10 @@
import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.asm.SideOnly;
+import cpw.mods.fml.common.registry.GameData;
+import cpw.mods.fml.common.registry.GameRegistry;
+import cpw.mods.fml.common.registry.ItemData;
+
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
@@ -15,7 +18,9 @@
@@ -15,7 +19,9 @@
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
@ -20,7 +21,7 @@
import net.minecraft.src.AchievementList;
import net.minecraft.src.AnvilSaveConverter;
import net.minecraft.src.AxisAlignedBB;
@@ -122,6 +127,7 @@
@@ -122,6 +128,7 @@
import net.minecraft.src.WorldInfo;
import net.minecraft.src.WorldRenderer;
import net.minecraft.src.WorldSettings;
@ -28,7 +29,7 @@
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
@@ -134,6 +140,14 @@
@@ -134,6 +141,14 @@
import org.lwjgl.opengl.GLContext;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.util.glu.GLU;
@ -43,7 +44,7 @@
@SideOnly(Side.CLIENT)
public abstract class Minecraft implements Runnable, IPlayerUsage
@@ -316,7 +330,7 @@
@@ -316,7 +331,7 @@
this.func_71357_I();
this.field_71466_p = new FontRenderer(this.field_71474_y, "/font/default.png", this.field_71446_o, false);
this.field_71464_q = new FontRenderer(this.field_71474_y, "/font/alternate.png", this.field_71446_o, false);
@ -52,7 +53,7 @@
if (this.field_71474_y.field_74363_ab != null)
{
StringTranslate.func_74808_a().func_74810_a(this.field_71474_y.field_74363_ab);
@@ -361,6 +375,8 @@
@@ -361,6 +376,8 @@
GL11.glViewport(0, 0, this.field_71443_c, this.field_71440_d);
this.field_71452_i = new EffectRenderer(this.field_71441_e, this.field_71446_o);
@ -61,7 +62,7 @@
try
{
this.field_71430_V = new ThreadDownloadResources(this.field_71412_D, this);
@@ -389,6 +405,7 @@
@@ -389,6 +406,7 @@
{
this.func_71352_k();
}
@ -69,7 +70,7 @@
}
private void func_71357_I() throws LWJGLException
@@ -747,9 +764,11 @@
@@ -747,9 +765,11 @@
if (!this.field_71454_w)
{
@ -81,7 +82,7 @@
}
GL11.glFlush();
@@ -1279,11 +1298,13 @@
@@ -1279,11 +1299,13 @@
public void func_71407_l()
{
@ -95,7 +96,7 @@
this.field_71424_I.func_76320_a("stats");
this.field_71413_E.func_77449_e();
this.field_71424_I.func_76318_c("gui");
@@ -1739,6 +1760,7 @@
@@ -1739,6 +1761,7 @@
this.field_71453_ak.func_74428_b();
}
@ -103,21 +104,21 @@
this.field_71424_I.func_76319_b();
this.field_71423_H = func_71386_F();
}
@@ -1777,8 +1799,23 @@
@@ -1777,8 +1800,23 @@
}
this.field_71413_E.func_77450_a(StatList.field_75936_f, 1);
+ GameRegistry.initializeServerGate(2);
+ GameData.initializeServerGate(2);
this.field_71437_Z = new IntegratedServer(this, p_71371_1_, p_71371_2_, p_71371_3_);
this.field_71437_Z.func_71256_s();
+ MapDifference<Integer, ItemData> idDifferences = GameRegistry.gateWorldLoadingForValidation();
+ MapDifference<Integer, ItemData> idDifferences = GameData.gateWorldLoadingForValidation();
+ if (idDifferences!=null)
+ {
+ FMLClientHandler.instance().warnIDMismatch(idDifferences, true);
+ }
+ else
+ {
+ GameRegistry.releaseGate(true);
+ GameData.releaseGate(true);
+ continueWorldLoading();
+ }
+
@ -127,7 +128,7 @@
this.field_71455_al = true;
this.field_71461_s.func_73720_a(StatCollector.func_74838_a("menu.loadingLevel"));
@@ -1993,6 +2030,12 @@
@@ -1993,6 +2031,12 @@
public static void main(String[] p_main_0_)
{