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.item.Item;
008    import net.minecraft.nbt.NBTTagCompound;
009    import net.minecraft.nbt.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            FMLLog.fine("The difference set is %s", difference);
078            if (!difference.entriesDiffering().isEmpty() || !difference.entriesOnlyOnLeft().isEmpty())
079            {
080                FMLLog.severe("FML has detected item discrepancies");
081                FMLLog.severe("Missing items : %s", difference.entriesOnlyOnLeft());
082                FMLLog.severe("Mismatched items : %s", difference.entriesDiffering());
083                isSaveValid = false;
084                serverValidationLatch.countDown();
085            }
086            else
087            {
088                isSaveValid = true;
089                serverValidationLatch.countDown();
090            }
091            try
092            {
093                clientValidationLatch.await();
094                if (!shouldContinue)
095                {
096                    throw new RuntimeException("This server instance is going to stop abnormally because of a fatal ID mismatch");
097                }
098            }
099            catch (InterruptedException e)
100            {
101            }
102        }
103    
104        public static void writeItemData(NBTTagList itemList)
105        {
106            for (ItemData dat : idMap.values())
107            {
108                itemList.appendTag(dat.toNBT());
109            }
110        }
111    
112        /**
113         * Initialize the server gate
114         * @param gateCount the countdown amount. If it's 2 we're on the client and the client and server
115         * will wait at the latch. 1 is a server and the server will proceed
116         */
117        public static void initializeServerGate(int gateCount)
118        {
119            serverValidationLatch = new CountDownLatch(gateCount - 1);
120            clientValidationLatch = new CountDownLatch(gateCount - 1);
121        }
122    
123        public static MapDifference<Integer, ItemData> gateWorldLoadingForValidation()
124        {
125            try
126            {
127                serverValidationLatch.await();
128                if (!isSaveValid)
129                {
130                    return difference;
131                }
132            }
133            catch (InterruptedException e)
134            {
135            }
136            difference = null;
137            return null;
138        }
139    
140    
141        public static void releaseGate(boolean carryOn)
142        {
143            shouldContinue = carryOn;
144            clientValidationLatch.countDown();
145        }
146    
147        public static Set<ItemData> buildWorldItemData(NBTTagList modList)
148        {
149            Set<ItemData> worldSaveItems = Sets.newHashSet();
150            for (int i = 0; i < modList.tagCount(); i++)
151            {
152                NBTTagCompound mod = (NBTTagCompound) modList.tagAt(i);
153                ItemData dat = new ItemData(mod);
154                worldSaveItems.add(dat);
155            }
156            return worldSaveItems;
157        }
158    
159    
160    
161    }