001 package cpw.mods.fml.common.registry; 002 003 import java.util.Map; 004 import java.util.Set; 005 import java.util.concurrent.CountDownLatch; 006 007 import net.minecraft.src.Item; 008 import net.minecraft.src.NBTTagCompound; 009 import net.minecraft.src.NBTTagList; 010 011 import com.google.common.base.Function; 012 import com.google.common.collect.MapDifference; 013 import com.google.common.collect.Maps; 014 import com.google.common.collect.Sets; 015 016 import cpw.mods.fml.common.FMLLog; 017 import cpw.mods.fml.common.Loader; 018 import cpw.mods.fml.common.LoaderState; 019 import cpw.mods.fml.common.ModContainer; 020 021 public class GameData { 022 private static Map<Integer, ItemData> idMap = Maps.newHashMap(); 023 private static CountDownLatch serverValidationLatch; 024 private static CountDownLatch clientValidationLatch; 025 private static MapDifference<Integer, ItemData> difference; 026 private static boolean shouldContinue = true; 027 private static boolean isSaveValid = true; 028 029 public static void newItemAdded(Item item) 030 { 031 ModContainer mc = Loader.instance().activeModContainer(); 032 if (mc == null) 033 { 034 mc = Loader.instance().getMinecraftModContainer(); 035 if (Loader.instance().hasReachedState(LoaderState.AVAILABLE)) 036 { 037 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."); 038 } 039 } 040 String itemType = item.getClass().getName(); 041 ItemData itemData = new ItemData(item, mc); 042 if (idMap.containsKey(item.shiftedIndex)) 043 { 044 ItemData id = idMap.get(item.shiftedIndex); 045 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); 046 } 047 idMap.put(item.shiftedIndex, itemData); 048 FMLLog.fine("[ItemTracker] Adding item %s(%d) owned by %s", item.getClass().getName(), item.shiftedIndex, mc.getModId()); 049 } 050 051 public static void validateWorldSave(Set<ItemData> worldSaveItems) 052 { 053 isSaveValid = true; 054 shouldContinue = true; 055 // allow ourselves to continue if there's no saved data 056 if (worldSaveItems == null) 057 { 058 serverValidationLatch.countDown(); 059 try 060 { 061 clientValidationLatch.await(); 062 } 063 catch (InterruptedException e) 064 { 065 } 066 return; 067 } 068 069 Function<? super ItemData, Integer> idMapFunction = new Function<ItemData, Integer>() { 070 public Integer apply(ItemData input) { 071 return input.itemId; 072 }; 073 }; 074 075 Map<Integer,ItemData> worldMap = Maps.uniqueIndex(worldSaveItems,idMapFunction); 076 difference = Maps.difference(worldMap, idMap); 077 if (!difference.entriesDiffering().isEmpty() || !difference.entriesOnlyOnLeft().isEmpty()) 078 { 079 isSaveValid = false; 080 serverValidationLatch.countDown(); 081 } 082 else 083 { 084 isSaveValid = true; 085 serverValidationLatch.countDown(); 086 } 087 try 088 { 089 clientValidationLatch.await(); 090 if (!shouldContinue) 091 { 092 throw new RuntimeException("This server instance is going to stop abnormally because of a fatal ID mismatch"); 093 } 094 } 095 catch (InterruptedException e) 096 { 097 } 098 } 099 100 public static void writeItemData(NBTTagList itemList) 101 { 102 for (ItemData dat : idMap.values()) 103 { 104 itemList.appendTag(dat.toNBT()); 105 } 106 } 107 108 /** 109 * Initialize the server gate 110 * @param gateCount the countdown amount. If it's 2 we're on the client and the client and server 111 * will wait at the latch. 1 is a server and the server will proceed 112 */ 113 public static void initializeServerGate(int gateCount) 114 { 115 serverValidationLatch = new CountDownLatch(gateCount - 1); 116 clientValidationLatch = new CountDownLatch(gateCount - 1); 117 } 118 119 public static MapDifference<Integer, ItemData> gateWorldLoadingForValidation() 120 { 121 try 122 { 123 serverValidationLatch.await(); 124 if (!isSaveValid) 125 { 126 return difference; 127 } 128 } 129 catch (InterruptedException e) 130 { 131 } 132 difference = null; 133 return null; 134 } 135 136 137 public static void releaseGate(boolean carryOn) 138 { 139 shouldContinue = carryOn; 140 clientValidationLatch.countDown(); 141 } 142 143 public static Set<ItemData> buildWorldItemData(NBTTagList modList) 144 { 145 Set<ItemData> worldSaveItems = Sets.newHashSet(); 146 for (int i = 0; i < modList.tagCount(); i++) 147 { 148 NBTTagCompound mod = (NBTTagCompound) modList.tagAt(i); 149 ItemData dat = new ItemData(mod); 150 worldSaveItems.add(dat); 151 } 152 return worldSaveItems; 153 } 154 155 156 157 }