Giant registry fixup

This commit is contained in:
cpw 2015-11-28 03:01:31 -05:00
parent 5549b06f96
commit 97ef6a5d1f
21 changed files with 801 additions and 1303 deletions

View file

@ -375,6 +375,11 @@ public abstract class FluidRegistry
return name;
}
@Override
public ResourceLocation getResourceName() {
return new ResourceLocation(name);
}
@Override
public Class<Fluid> type()
{

View file

@ -87,8 +87,8 @@ import net.minecraftforge.fml.common.WrongMinecraftVersionException;
import net.minecraftforge.fml.common.eventhandler.EventBus;
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
import net.minecraftforge.fml.common.network.internal.FMLNetworkHandler;
import net.minecraftforge.fml.common.registry.GameData;
import net.minecraftforge.fml.common.registry.LanguageRegistry;
import net.minecraftforge.fml.common.registry.PersistentRegistryManager;
import net.minecraftforge.fml.common.toposort.ModSortingException;
import net.minecraftforge.fml.relauncher.Side;
@ -651,7 +651,7 @@ public class FMLClientHandler implements IFMLSidedHandler
// ONLY revert a non-local connection
if (client != null && !client.isLocalChannel())
{
GameData.revertToFrozen();
PersistentRegistryManager.revertToFrozen();
}
}

View file

@ -24,6 +24,7 @@ import java.util.Set;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.SaveHandler;
import net.minecraft.world.storage.WorldInfo;
import net.minecraftforge.fml.client.FMLFileResourcePack;
@ -35,6 +36,7 @@ import net.minecraftforge.fml.common.network.NetworkCheckHandler;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.internal.FMLNetworkHandler;
import net.minecraftforge.fml.common.registry.GameData;
import net.minecraftforge.fml.common.registry.PersistentRegistryManager;
import net.minecraftforge.fml.common.registry.VillagerRegistry;
import net.minecraftforge.fml.relauncher.Side;
@ -109,38 +111,38 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
NBTTagCompound registries = new NBTTagCompound();
fmlData.setTag("Registries", registries);
FMLLog.fine("Gathering id map for writing to world save %s", info.getWorldName());
GameData.GameDataSnapshot dataSnapshot = GameData.takeSnapshot();
PersistentRegistryManager.GameDataSnapshot dataSnapshot = PersistentRegistryManager.takeSnapshot();
for (Map.Entry<String, GameData.GameDataSnapshot.Entry> e : dataSnapshot.entries.entrySet())
for (Map.Entry<ResourceLocation, PersistentRegistryManager.GameDataSnapshot.Entry> e : dataSnapshot.entries.entrySet())
{
NBTTagCompound data = new NBTTagCompound();
registries.setTag(e.getKey(), data);
registries.setTag(e.getKey().toString(), data);
NBTTagList ids = new NBTTagList();
for (Entry<String, Integer> item : e.getValue().ids.entrySet())
for (Entry<ResourceLocation, Integer> item : e.getValue().ids.entrySet())
{
NBTTagCompound tag = new NBTTagCompound();
tag.setString("K", item.getKey());
tag.setString("K", item.getKey().toString());
tag.setInteger("V", item.getValue());
ids.appendTag(tag);
}
data.setTag("ids", ids);
NBTTagList aliases = new NBTTagList();
for (Entry<String, String> entry : e.getValue().aliases.entrySet())
for (Entry<ResourceLocation, ResourceLocation> entry : e.getValue().aliases.entrySet())
{
NBTTagCompound tag = new NBTTagCompound();
tag.setString("K", entry.getKey());
tag.setString("V", entry.getValue());
tag.setString("K", entry.getKey().toString());
tag.setString("V", entry.getValue().toString());
aliases.appendTag(tag);
}
data.setTag("aliases", aliases);
NBTTagList subs = new NBTTagList();
for (String entry : e.getValue().substitutions)
for (ResourceLocation entry : e.getValue().substitutions)
{
NBTTagCompound tag = new NBTTagCompound();
tag.setString("K", entry);
tag.setString("K", entry.toString());
subs.appendTag(tag);
}
data.setTag("substitutions", subs);
@ -184,39 +186,21 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
if (tag.hasKey("ModItemData")) // Pre 1.7
{
GameData.GameDataSnapshot snapshot = new GameData.GameDataSnapshot();
GameData.GameDataSnapshot.Entry items = new GameData.GameDataSnapshot.Entry();
snapshot.entries.put("fml:blocks", new GameData.GameDataSnapshot.Entry());
snapshot.entries.put("fml:items", items);
FMLLog.info("Attempting to convert old world data to new system. This may be trouble!");
NBTTagList modList = tag.getTagList("ModItemData", (byte)10);
for (int i = 0; i < modList.tagCount(); i++)
{
NBTTagCompound data = modList.getCompoundTagAt(i);
String forcedModId = data.hasKey("ForcedModId") ? data.getString("ForcedModId") : null;
String forcedName = data.hasKey("ForcedName") ? data.getString("ForcedName") : null;
if (forcedName == null)
{
FMLLog.warning("Found unlabelled item in world save, this may cause problems. The item type %s:%d will not be present", data.getString("ItemType"), data.getInteger("ordinal"));
}
else
{
// all entries are Items, blocks were only saved through their ItemBlock
String itemLabel = String.format("%s:%s", forcedModId != null ? forcedModId : data.getString("ModId"), forcedName);
items.ids.put(itemLabel, data.getInteger("ItemId"));
}
}
failedElements = GameData.injectSnapshot(snapshot, true, true);
StartupQuery.notify("This save predates 1.7.10, it can no longer be loaded here. Please load in 1.7.10 or 1.8 first");
StartupQuery.abort();
}
else if (tag.hasKey("ItemData")) // 1.7
{
GameData.GameDataSnapshot snapshot = new GameData.GameDataSnapshot();
GameData.GameDataSnapshot.Entry blocks = new GameData.GameDataSnapshot.Entry();
GameData.GameDataSnapshot.Entry items = new GameData.GameDataSnapshot.Entry();
snapshot.entries.put("fml:blocks", blocks);
snapshot.entries.put("fml:items", items);
if (!tag.hasKey("BlockedItemIds")) // no blocked id info -> old 1.7 save
{
StartupQuery.notify("This save predates 1.7.10, it can no longer be loaded here. Please load in 1.7.10 or 1.8 first");
StartupQuery.abort();
}
PersistentRegistryManager.GameDataSnapshot snapshot = new PersistentRegistryManager.GameDataSnapshot();
PersistentRegistryManager.GameDataSnapshot.Entry blocks = new PersistentRegistryManager.GameDataSnapshot.Entry();
PersistentRegistryManager.GameDataSnapshot.Entry items = new PersistentRegistryManager.GameDataSnapshot.Entry();
snapshot.entries.put(PersistentRegistryManager.BLOCKS, blocks);
snapshot.entries.put(PersistentRegistryManager.ITEMS, items);
NBTTagList list = tag.getTagList("ItemData", 10);
for (int i = 0; i < list.tagCount(); i++)
@ -225,24 +209,15 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
String name = e.getString("K");
if (name.charAt(0) == '\u0001')
blocks.ids.put(name.substring(1), e.getInteger("V"));
blocks.ids.put(new ResourceLocation(name.substring(1)), e.getInteger("V"));
else if (name.charAt(0) == '\u0002')
items.ids.put(name.substring(1), e.getInteger("V"));
items.ids.put(new ResourceLocation(name.substring(1)), e.getInteger("V"));
}
Set<Integer> blockedIds = new HashSet<Integer>();
if (!tag.hasKey("BlockedItemIds")) // no blocked id info -> old 1.7 save
for (int id : tag.getIntArray("BlockedItemIds"))
{
// old early 1.7 save potentially affected by the registry mapping bug
// fix the ids the best we can...
GameData.fixBrokenIds(blocks, items, blockedIds);
}
else
{
for (int id : tag.getIntArray("BlockedItemIds"))
{
blockedIds.add(id);
}
blockedIds.add(id);
}
blocks.blocked.addAll(blockedIds);
items.blocked.addAll(blockedIds);
@ -251,7 +226,7 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
for (int i = 0; i < list.tagCount(); i++)
{
NBTTagCompound dataTag = list.getCompoundTagAt(i);
blocks.aliases.put(dataTag.getString("K"), dataTag.getString("V"));
blocks.aliases.put(new ResourceLocation(dataTag.getString("K")), new ResourceLocation(dataTag.getString("V")));
}
if (tag.hasKey("BlockSubstitutions", 9))
@ -260,7 +235,7 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
for (int i = 0; i < list.tagCount(); i++)
{
NBTTagCompound dataTag = list.getCompoundTagAt(i);
blocks.substitutions.add(dataTag.getString("K"));
blocks.substitutions.add(new ResourceLocation(dataTag.getString("K")));
}
}
@ -268,7 +243,7 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
for (int i = 0; i < list.tagCount(); i++)
{
NBTTagCompound dataTag = list.getCompoundTagAt(i);
items.aliases.put(dataTag.getString("K"), dataTag.getString("V"));
items.aliases.put(new ResourceLocation(dataTag.getString("K")), new ResourceLocation(dataTag.getString("V")));
}
if (tag.hasKey("ItemSubstitutions", 9))
@ -277,39 +252,42 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
for (int i = 0; i < list.tagCount(); i++)
{
NBTTagCompound dataTag = list.getCompoundTagAt(i);
items.substitutions.add(dataTag.getString("K"));
items.substitutions.add(new ResourceLocation(dataTag.getString("K")));
}
}
failedElements = GameData.injectSnapshot(snapshot, true, true);
failedElements = PersistentRegistryManager.injectSnapshot(snapshot, true, true);
}
else if (tag.hasKey("Registries")) // 1.8, genericed out the 'registries' list
{
GameData.GameDataSnapshot snapshot = new GameData.GameDataSnapshot();
PersistentRegistryManager.GameDataSnapshot snapshot = new PersistentRegistryManager.GameDataSnapshot();
NBTTagCompound regs = tag.getCompoundTag("Registries");
for (String key : (Set<String>)regs.getKeySet())
for (String key : regs.getKeySet())
{
GameData.GameDataSnapshot.Entry entry = new GameData.GameDataSnapshot.Entry();
snapshot.entries.put(key, entry);
PersistentRegistryManager.GameDataSnapshot.Entry entry = new PersistentRegistryManager.GameDataSnapshot.Entry();
if ("fml:blocks".equals(key)) key = "minecraft:blocks";
if ("fml:items".equals(key)) key = "minecraft:items";
if ("fmlgr:villagerprofessions".equals(key)) key = "minecraft:villagerprofessions";
snapshot.entries.put(new ResourceLocation(key), entry);
NBTTagList list = regs.getCompoundTag(key).getTagList("ids", 10);
for (int x = 0; x < list.tagCount(); x++)
{
NBTTagCompound e = list.getCompoundTagAt(x);
entry.ids.put(e.getString("K"), e.getInteger("V"));
entry.ids.put(new ResourceLocation(e.getString("K")), e.getInteger("V"));
}
list = regs.getCompoundTag(key).getTagList("aliases", 10);
for (int x = 0; x < list.tagCount(); x++)
{
NBTTagCompound e = list.getCompoundTagAt(x);
entry.aliases.put(e.getString("K"), e.getString("V"));
entry.aliases.put(new ResourceLocation(e.getString("K")), new ResourceLocation(e.getString("V")));
}
list = regs.getCompoundTag(key).getTagList("substitutions", 10);
for (int x = 0; x < list.tagCount(); x++)
{
NBTTagCompound e = list.getCompoundTagAt(x);
entry.substitutions.add(e.getString("K"));
entry.substitutions.add(new ResourceLocation(e.getString("K")));
}
int[] blocked = regs.getCompoundTag(key).getIntArray("blocked");
@ -318,7 +296,7 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
entry.blocked.add(i);
}
}
failedElements = GameData.injectSnapshot(snapshot, true, true);
failedElements = PersistentRegistryManager.injectSnapshot(snapshot, true, true);
}
if (failedElements != null && !failedElements.isEmpty())

View file

@ -21,12 +21,12 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.LoaderState.ModState;
import net.minecraftforge.fml.common.ModContainer.Disableable;
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
@ -38,10 +38,7 @@ import net.minecraftforge.fml.common.event.FMLModIdMappingEvent;
import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent.MissingMapping;
import net.minecraftforge.fml.common.functions.ArtifactVersionNameFunction;
import net.minecraftforge.fml.common.functions.ModIdFunction;
import net.minecraftforge.fml.common.registry.GameData;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.common.registry.ItemStackHolderInjector;
import net.minecraftforge.fml.common.registry.ObjectHolderRegistry;
import net.minecraftforge.fml.common.registry.*;
import net.minecraftforge.fml.common.registry.GameRegistry.Type;
import net.minecraftforge.fml.common.toposort.ModSorter;
import net.minecraftforge.fml.common.toposort.ModSortingException;
@ -738,7 +735,7 @@ public class Loader
progressBar.step("Finishing up");
modController.transition(LoaderState.AVAILABLE, false);
modController.distributeStateMessage(LoaderState.AVAILABLE);
GameData.freezeData();
PersistentRegistryManager.freezeData();
FMLLog.info("Forge Mod Loader has successfully loaded %d mod%s", mods.size(), mods.size() == 1 ? "" : "s");
progressBar.step("Completing Minecraft initialization");
}
@ -839,7 +836,7 @@ public class Loader
public void serverStopped()
{
GameData.revertToFrozen();
PersistentRegistryManager.revertToFrozen();
modController.distributeStateMessage(LoaderState.SERVER_STOPPED);
modController.transition(LoaderState.SERVER_STOPPED, true);
modController.transition(LoaderState.AVAILABLE, true);
@ -914,8 +911,7 @@ public class Loader
* @param gameData GameData instance where the new map's config is to be loaded into.
* @return List with the mapping results.
*/
public List<String> fireMissingMappingEvent(LinkedHashMap<String, Integer> missingBlocks, LinkedHashMap<String, Integer> missingItems,
boolean isLocalWorld, GameData gameData, Map<String, Integer[]> remapBlocks, Map<String, Integer[]> remapItems)
public List<String> fireMissingMappingEvent(Map<ResourceLocation, Integer> missingBlocks, Map<ResourceLocation, Integer> missingItems, boolean isLocalWorld, Map<ResourceLocation, Integer[]> remapBlocks, Map<ResourceLocation, Integer[]> remapItems)
{
if (missingBlocks.isEmpty() && missingItems.isEmpty()) // nothing to do
{
@ -925,15 +921,15 @@ public class Loader
FMLLog.fine("There are %d mappings missing - attempting a mod remap", missingBlocks.size() + missingItems.size());
ArrayListMultimap<String, MissingMapping> missingMappings = ArrayListMultimap.create();
for (Map.Entry<String, Integer> mapping : missingBlocks.entrySet())
for (Map.Entry<ResourceLocation, Integer> mapping : missingBlocks.entrySet())
{
MissingMapping m = new MissingMapping(GameRegistry.Type.BLOCK, mapping.getKey(), mapping.getValue());
missingMappings.put(m.name.substring(0, m.name.indexOf(':')), m);
missingMappings.put(m.resourceLocation.getResourceDomain(), m);
}
for (Map.Entry<String, Integer> mapping : missingItems.entrySet())
for (Map.Entry<ResourceLocation, Integer> mapping : missingItems.entrySet())
{
MissingMapping m = new MissingMapping(GameRegistry.Type.ITEM, mapping.getKey(), mapping.getValue());
missingMappings.put(m.name.substring(0, m.name.indexOf(':')), m);
missingMappings.put(m.resourceLocation.getResourceDomain(), m);
}
FMLMissingMappingsEvent missingEvent = new FMLMissingMappingsEvent(missingMappings);
@ -975,12 +971,12 @@ public class Loader
}
}
return GameData.processIdRematches(missingMappings.values(), isLocalWorld, gameData, remapBlocks, remapItems);
return PersistentRegistryManager.processIdRematches(missingMappings.values(), isLocalWorld, remapBlocks, remapItems);
}
public void fireRemapEvent(Map<String, Integer[]> remapBlocks, Map<String, Integer[]> remapItems)
public void fireRemapEvent(Map<ResourceLocation, Integer[]> remapBlocks, Map<ResourceLocation, Integer[]> remapItems)
{
modController.propogateStateMessage(new FMLModIdMappingEvent(remapBlocks, remapItems));
modController.propogateStateMessage(new FMLModIdMappingEvent(remapBlocks, remapItems));
}
public void runtimeDisableMod(String modId)

View file

@ -4,6 +4,7 @@ import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.registry.GameData;
import net.minecraftforge.fml.common.registry.GameRegistry;
@ -63,14 +64,16 @@ public class FMLMissingMappingsEvent extends FMLEvent {
public final GameRegistry.Type type;
public final String name;
public final int id;
public final ResourceLocation resourceLocation;
private Action action = Action.DEFAULT;
private Object target;
public MissingMapping(GameRegistry.Type type, String name, int id)
public MissingMapping(GameRegistry.Type type, ResourceLocation name, int id)
{
this.type = type;
this.name = name;
this.name = name.toString();
this.id = id;
this.resourceLocation = name;
}
/**

View file

@ -8,6 +8,7 @@ import java.util.Map.Entry;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import net.minecraft.util.ResourceLocation;
/**
* Called whenever the ID mapping might have changed. If you register for this event, you
@ -30,25 +31,28 @@ public class FMLModIdMappingEvent extends FMLEvent {
public final int newId;
public final String tag;
public final RemapTarget remapTarget;
public ModRemapping(int oldId, int newId, String tag, RemapTarget type)
public final ResourceLocation resourceLocation;
public ModRemapping(int oldId, int newId, ResourceLocation tag, RemapTarget type)
{
this.oldId = oldId;
this.newId = newId;
this.tag = tag;
this.tag = tag.toString();
this.remapTarget = type;
this.resourceLocation = tag;
}
}
public final ImmutableList<ModRemapping> remappedIds;
public FMLModIdMappingEvent(Map<String, Integer[]> blocks, Map<String, Integer[]> items)
public FMLModIdMappingEvent(Map<ResourceLocation, Integer[]> blocks, Map<ResourceLocation, Integer[]> items)
{
List<ModRemapping> remappings = Lists.newArrayList();
for (Entry<String, Integer[]> mapping : blocks.entrySet())
for (Entry<ResourceLocation, Integer[]> mapping : blocks.entrySet())
{
remappings.add(new ModRemapping(mapping.getValue()[0], mapping.getValue()[1], mapping.getKey(), RemapTarget.BLOCK));
}
for (Entry<String, Integer[]> mapping : items.entrySet())
for (Entry<ResourceLocation, Integer[]> mapping : items.entrySet())
{
remappings.add(new ModRemapping(mapping.getValue()[0], mapping.getValue()[1], mapping.getKey(), RemapTarget.ITEM));
}

View file

@ -2,6 +2,7 @@ package net.minecraftforge.fml.common.network.handshake;
import java.util.List;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.network.NetworkRegistry;
@ -9,6 +10,7 @@ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage.Serve
import net.minecraftforge.fml.common.network.internal.FMLMessage;
import net.minecraftforge.fml.common.network.internal.FMLNetworkHandler;
import net.minecraftforge.fml.common.registry.GameData;
import net.minecraftforge.fml.common.registry.PersistentRegistryManager;
import net.minecraftforge.fml.relauncher.Side;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
@ -94,14 +96,14 @@ enum FMLHandshakeClientState implements IHandshakeState<FMLHandshakeClientState>
public FMLHandshakeClientState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg)
{
FMLHandshakeMessage.RegistryData pkt = (FMLHandshakeMessage.RegistryData)msg;
GameData.GameDataSnapshot snap = ctx.channel().attr(NetworkDispatcher.FML_GAMEDATA_SNAPSHOT).get();
PersistentRegistryManager.GameDataSnapshot snap = ctx.channel().attr(NetworkDispatcher.FML_GAMEDATA_SNAPSHOT).get();
if (snap == null)
{
snap = new GameData.GameDataSnapshot();
snap = new PersistentRegistryManager.GameDataSnapshot();
ctx.channel().attr(NetworkDispatcher.FML_GAMEDATA_SNAPSHOT).set(snap);
}
GameData.GameDataSnapshot.Entry entry = new GameData.GameDataSnapshot.Entry();
PersistentRegistryManager.GameDataSnapshot.Entry entry = new PersistentRegistryManager.GameDataSnapshot.Entry();
entry.ids.putAll(pkt.getIdMap());
entry.substitutions.addAll(pkt.getSubstitutions());
snap.entries.put(pkt.getName(), entry);
@ -114,7 +116,7 @@ enum FMLHandshakeClientState implements IHandshakeState<FMLHandshakeClientState>
ctx.channel().attr(NetworkDispatcher.FML_GAMEDATA_SNAPSHOT).remove();
List<String> locallyMissing = GameData.injectSnapshot(snap, false, false);
List<String> locallyMissing = PersistentRegistryManager.injectSnapshot(snap, false, false);
if (!locallyMissing.isEmpty())
{
NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
@ -156,7 +158,7 @@ enum FMLHandshakeClientState implements IHandshakeState<FMLHandshakeClientState>
{
if (msg instanceof FMLHandshakeMessage.HandshakeReset)
{
GameData.revertToFrozen();
PersistentRegistryManager.revertToFrozen();
return HELLO;
}
return this;

View file

@ -10,6 +10,7 @@ import java.util.Map.Entry;
import java.util.Set;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.network.ByteBufUtils;
@ -22,6 +23,7 @@ import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import net.minecraftforge.fml.common.registry.PersistentRegistryManager;
public abstract class FMLHandshakeMessage {
public static FMLProxyPacket makeCustomChannelRegistration(Set<String> channels)
@ -158,7 +160,7 @@ public abstract class FMLHandshakeMessage {
}
public RegistryData(boolean hasMore, String name, GameData.GameDataSnapshot.Entry entry)
public RegistryData(boolean hasMore, ResourceLocation name, PersistentRegistryManager.GameDataSnapshot.Entry entry)
{
this.hasMore = hasMore;
this.name = name;
@ -167,22 +169,22 @@ public abstract class FMLHandshakeMessage {
}
private boolean hasMore;
private String name;
private Map<String,Integer> ids;
private Set<String> substitutions;
private ResourceLocation name;
private Map<ResourceLocation, Integer> ids;
private Set<ResourceLocation> substitutions;
@Override
public void fromBytes(ByteBuf buffer)
{
this.hasMore = buffer.readBoolean();
this.name = ByteBufUtils.readUTF8String(buffer);
this.name = new ResourceLocation(ByteBufUtils.readUTF8String(buffer));
int length = ByteBufUtils.readVarInt(buffer, 3);
ids = Maps.newHashMap();
for (int i = 0; i < length; i++)
{
ids.put(ByteBufUtils.readUTF8String(buffer), ByteBufUtils.readVarInt(buffer, 3));
ids.put(new ResourceLocation(ByteBufUtils.readUTF8String(buffer)), ByteBufUtils.readVarInt(buffer, 3));
}
length = ByteBufUtils.readVarInt(buffer, 3);
@ -190,7 +192,7 @@ public abstract class FMLHandshakeMessage {
for (int i = 0; i < length; i++)
{
substitutions.add(ByteBufUtils.readUTF8String(buffer));
substitutions.add(new ResourceLocation(ByteBufUtils.readUTF8String(buffer)));
}
//if (!buffer.isReadable()) return; // In case we expand
}
@ -199,31 +201,31 @@ public abstract class FMLHandshakeMessage {
public void toBytes(ByteBuf buffer)
{
buffer.writeBoolean(this.hasMore);
ByteBufUtils.writeUTF8String(buffer, this.name);
ByteBufUtils.writeUTF8String(buffer, this.name.toString());
ByteBufUtils.writeVarInt(buffer, ids.size(), 3);
for (Entry<String, Integer> entry: ids.entrySet())
for (Entry<ResourceLocation, Integer> entry: ids.entrySet())
{
ByteBufUtils.writeUTF8String(buffer, entry.getKey());
ByteBufUtils.writeUTF8String(buffer, entry.getKey().toString());
ByteBufUtils.writeVarInt(buffer, entry.getValue(), 3);
}
ByteBufUtils.writeVarInt(buffer, substitutions.size(), 3);
for (String entry: substitutions)
for (ResourceLocation entry: substitutions)
{
ByteBufUtils.writeUTF8String(buffer, entry);
ByteBufUtils.writeUTF8String(buffer, entry.toString());
}
}
public Map<String,Integer> getIdMap()
public Map<ResourceLocation,Integer> getIdMap()
{
return ids;
}
public Set<String> getSubstitutions()
public Set<ResourceLocation> getSubstitutions()
{
return substitutions;
}
public String getName()
public ResourceLocation getName()
{
return this.name;
}

View file

@ -4,12 +4,14 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.internal.FMLMessage;
import net.minecraftforge.fml.common.network.internal.FMLNetworkHandler;
import net.minecraftforge.fml.common.registry.GameData;
import net.minecraftforge.fml.common.registry.PersistentRegistryManager;
import net.minecraftforge.fml.relauncher.Side;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
@ -61,11 +63,11 @@ enum FMLHandshakeServerState implements IHandshakeState<FMLHandshakeServerState>
{
if (!ctx.channel().attr(NetworkDispatcher.IS_LOCAL).get())
{
GameData.GameDataSnapshot snapshot = GameData.takeSnapshot();
Iterator<Map.Entry<String, GameData.GameDataSnapshot.Entry>> itr = snapshot.entries.entrySet().iterator();
PersistentRegistryManager.GameDataSnapshot snapshot = PersistentRegistryManager.takeSnapshot();
Iterator<Map.Entry<ResourceLocation, PersistentRegistryManager.GameDataSnapshot.Entry>> itr = snapshot.entries.entrySet().iterator();
while (itr.hasNext())
{
Entry<String, GameData.GameDataSnapshot.Entry> e = itr.next();
Entry<ResourceLocation, PersistentRegistryManager.GameDataSnapshot.Entry> e = itr.next();
ctx.writeAndFlush(new FMLHandshakeMessage.RegistryData(itr.hasNext(), e.getKey(), e.getValue())).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
}
}

View file

@ -18,6 +18,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import net.minecraftforge.fml.common.registry.PersistentRegistryManager;
import org.apache.logging.log4j.Level;
import net.minecraft.entity.player.EntityPlayerMP;
@ -82,7 +83,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
public static final AttributeKey<NetworkDispatcher> FML_DISPATCHER = AttributeKey.valueOf("fml:dispatcher");
public static final AttributeKey<Boolean> IS_LOCAL = AttributeKey.valueOf("fml:isLocal");
public static final AttributeKey<GameData.GameDataSnapshot> FML_GAMEDATA_SNAPSHOT = AttributeKey.valueOf("fml:gameDataSnapshot");
public static final AttributeKey<PersistentRegistryManager.GameDataSnapshot> FML_GAMEDATA_SNAPSHOT = AttributeKey.valueOf("fml:gameDataSnapshot");
public final NetworkManager manager;
private final ServerConfigurationManager scm;
private EntityPlayerMP player;

View file

@ -1,7 +1,9 @@
package net.minecraftforge.fml.common.registry;
import net.minecraft.util.ResourceLocation;
public class ExistingSubstitutionException extends Exception {
public ExistingSubstitutionException(String fromName, Object toReplace) {
public ExistingSubstitutionException(ResourceLocation fromName, Object toReplace) {
}
private static final long serialVersionUID = 1L;

View file

@ -1,5 +1,6 @@
package net.minecraftforge.fml.common.registry;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
@ -8,7 +9,10 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import com.google.common.base.Throwables;
import com.google.common.collect.*;
import org.apache.commons.lang3.Validate;
import org.apache.logging.log4j.Level;
@ -17,128 +21,128 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemBanner;
import net.minecraft.item.ItemBlock;
import net.minecraft.util.ObjectIntIdentityMap;
import net.minecraft.util.RegistryNamespaced;
import net.minecraft.util.RegistryNamespacedDefaultedByKey;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.functions.GenericIterableFactory;
import net.minecraftforge.fml.common.registry.RegistryDelegate.Delegate;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Iterators;
import com.google.common.base.Function;
@SuppressWarnings({"rawtypes", "unchecked"}) // cpw is working on these classes just shut them up for now.
public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaultedByKey {
public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaultedByKey<ResourceLocation,I> {
public static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("fml.debugRegistryEntries", "false"));
private final Class<I> superType;
private Object optionalDefaultKey;
private final boolean isDelegated;
private final Field delegateAccessor;
private ResourceLocation optionalDefaultKey;
private I optionalDefaultObject;
private int maxId;
private int minId;
// aliases redirecting legacy names to the actual name, may need recursive application to find the final name.
// these need to be registry specific, it's possible to only have a loosely linked item for a block which may get renamed by itself.
private final Map<String, String> aliases = new HashMap<String, String>();
private BiMap<String, I> persistentSubstitutions;
private BiMap<String, I> activeSubstitutions = HashBiMap.create();
/**
* Aliases are resource location to resource location pointers, allowing for alternative names to be supplied
* pointing at the same thing. They are used to allow programmatic migration of an ID.
*/
private final Map <ResourceLocation, ResourceLocation> aliases = Maps.newHashMap();
/**
* Persistent substitutions are the mechanism to allow mods to override specific behaviours with new behaviours.
*/
private final BiMap<ResourceLocation, I> persistentSubstitutions = HashBiMap.create();
/**
* This is the current active substitution set for a particular world. It will change as worlds come and go.
*/
private final BiMap<ResourceLocation, I> activeSubstitutions = HashBiMap.create();
/**
* The list of IDs blocked for this world. IDs will never be allocated in this set.
*/
private final Set<Integer> blockedIds = Sets.newHashSet();
FMLControlledNamespacedRegistry(Object defaultKey, int maxIdValue, int minIdValue, Class<I> type)
private final BitSet availabilityMap;
FMLControlledNamespacedRegistry(ResourceLocation defaultKey, int maxIdValue, int minIdValue, Class<I> type, boolean isDelegated)
{
super(defaultKey);
this.superType = type;
this.optionalDefaultKey = defaultKey;
this.maxId = maxIdValue;
this.minId = minIdValue;
this.availabilityMap = new BitSet(maxIdValue + 1);
this.isDelegated = isDelegated;
if (this.isDelegated) {
try {
this.delegateAccessor = type.getField("delegate");
} catch (NoSuchFieldException e) {
FMLLog.log(Level.ERROR, e, "Delegate class identified with missing delegate field");
throw Throwables.propagate(e);
}
} else {
this.delegateAccessor = null;
}
}
void validateContent(int maxId, String type, BitSet availabilityMap, Set<Integer> blockedIds, FMLControlledNamespacedRegistry<Block> iBlockRegistry)
void validateContent(ResourceLocation registryName)
{
for (I obj : typeSafeIterable())
{
int id = getId(obj);
Object name = getNameForObject(obj);
ResourceLocation name = getNameForObject(obj);
boolean isSubstituted = activeSubstitutions.containsKey(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));
ResourceLocation loc = (name instanceof ResourceLocation) ? (ResourceLocation)name : null;
String nameS = (name instanceof String) ? (String)name : (loc != null ? name.toString() : null);
if (loc == null && nameS == null) throw new IllegalStateException(String.format("Registry entry for %s %s name is invalid, must be a String or ResourceLocation %s", type, obj, name));
if (name == null) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, doesn't yield a name.", registryName, obj, id));
// id lookup failed -> obj is not in the obj<->id map
if (!isSubstituted && id < 0) throw new IllegalStateException(String.format("Registry entry for %s %s, name %s, doesn't yield an id.", type, obj, name));
if (!isSubstituted && id < 0) throw new IllegalStateException(String.format("Registry entry for %s %s, name %s, doesn't yield an id.", registryName, 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));
// empty name
if (name.toString().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.toString().indexOf(':') == -1) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, has the non-prefixed name %s.", type, obj, id, name));
if (id > maxId) throw new IllegalStateException(String.format("Registry entry for %s %s, name %s uses the too large id %d.", registryName, obj, name, id));
// the rest of the tests don't really work for substituted items or blocks
if (isSubstituted) continue;
// 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));
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, registryName, obj));
// name -> obj lookup is inconsistent
if (getRaw(nameS) != obj ) throw new IllegalStateException(String.format("Registry entry for name %s, id %d, doesn't yield the expected %s %s.", name, id, type, obj));
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, registryName, obj));
// name -> id lookup is inconsistent
if (getId(nameS) != 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));
if (getId(name) != id) throw new IllegalStateException(String.format("Registry entry for name %s doesn't yield the expected id %d.", name, id));
// 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 && !(obj instanceof ItemBanner)) //Dammet Mojang not linking Banners
{
Block block = ((ItemBlock) obj).block;
// 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));
}
if (blockedIds.contains(id)) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, name %s, marked as dangling.", registryName, obj, id, name));
}
}
void setFrom(FMLControlledNamespacedRegistry<?> registry) {
set((FMLControlledNamespacedRegistry<I>) registry);
}
void set(FMLControlledNamespacedRegistry<I> registry)
@SuppressWarnings("unchecked")
void set(FMLControlledNamespacedRegistry<I> otherRegistry)
{
if (this.superType != registry.superType) throw new IllegalArgumentException("incompatible registry");
if (this.superType != otherRegistry.superType) throw new IllegalArgumentException("incompatible registry");
this.optionalDefaultKey = registry.optionalDefaultKey;
this.maxId = registry.maxId;
this.minId = registry.minId;
this.optionalDefaultKey = otherRegistry.optionalDefaultKey;
this.maxId = otherRegistry.maxId;
this.minId = otherRegistry.minId;
this.aliases.clear();
this.aliases.putAll(registry.aliases);
this.aliases.putAll(otherRegistry.aliases);
this.activeSubstitutions.clear();
underlyingIntegerMap = new ObjectIntIdentityMap();
underlyingIntegerMap = new ObjectIntIdentityMap<I>();
registryObjects.clear();
for (I thing : registry.typeSafeIterable())
for (I thing : otherRegistry.typeSafeIterable())
{
addObjectRaw(registry.getId(thing), registry.getNameForObject(thing), thing);
addObjectRaw(otherRegistry.getId(thing), otherRegistry.getNameForObject(thing), thing);
}
this.activeSubstitutions.putAll(registry.activeSubstitutions);
this.activeSubstitutions.putAll(otherRegistry.activeSubstitutions);
}
// public api
/**
* Add an object to the registry, trying to use the specified id.
* This is required, to re-route vanilla block and item registration through to
* the {@link #add} method.
*
* @deprecated register through {@link GameRegistry} instead.
*/
@Override
@Deprecated
public void register(int id, Object name, Object thing)
public void register(int id, ResourceLocation name, I thing)
{
Validate.isInstanceOf(ResourceLocation.class, name);
GameData.getMain().register(thing, name.toString(), id);
add(id, name, thing);
}
/**
@ -148,17 +152,13 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
*/
@Override
@Deprecated
public void putObject(Object objName, Object obj)
public void putObject(ResourceLocation name, I thing)
{
String name = objName.toString();
I thing = superType.cast(obj);
if (name == null) throw new NullPointerException("Can't use a null-name for the registry.");
if (name.isEmpty()) throw new IllegalArgumentException("Can't use an empty name for the registry.");
if (thing == null) throw new NullPointerException("Can't add null-object to the registry.");
name = new ResourceLocation(name).toString();
Object existingName = getNameForObject(thing);
ResourceLocation existingName = getNameForObject(thing);
if (existingName == null)
{
@ -171,7 +171,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
else
{
FMLLog.bigWarning("Ignoring putObject(%s, %s), adding alias to %s instead", name, thing, existingName);
addAlias(name, existingName.toString());
addAlias(name, existingName);
}
}
@ -184,11 +184,9 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
* @return Registered object of the default object if it wasn't found-
*/
@Override
public I getObject(Object name)
public I getObject(ResourceLocation name)
{
I object = null;
if (name instanceof ResourceLocation) object = getRaw((ResourceLocation)name);
if (name instanceof String) object = getRaw((String)name);
I object = getRaw(name);
return object == null ? this.optionalDefaultObject : object;
}
@ -207,24 +205,6 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
return object == null ? this.optionalDefaultObject : object;
}
/**
* @deprecated use getObjectById instead
*/
@Deprecated
public I get(int id)
{
return getObjectById(id);
}
/**
* @deprecated use getObject instead
*/
@Deprecated
public I get(String name)
{
return getObject(name);
}
/**
* Get the id for the specified object.
*
@ -249,27 +229,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
*/
public I getRaw(int id)
{
return cast(super.getObjectById(id));
}
/**
* superType.cast appears to be expensive. Skip it for speed?
* @param obj
* @return
*/
private I cast(Object obj)
{
return (I)(obj);
}
/**
* Get the object identified by the specified name.
*
* @param name Block/Item name.
* @return Block/Item object or null if it wasn't found.
*/
public I getRaw(String name)
{
return getRaw(new ResourceLocation(name));
return super.getObjectById(id);
}
/**
@ -278,13 +238,13 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
* @param name Block/Item name.
* @return Block/Item object or null if it wasn't found.
*/
private I getRaw(ResourceLocation loc)
private I getRaw(ResourceLocation name)
{
I ret = superType.cast(super.getObject(loc));
I ret = super.getObject(name);
if (ret == null) // no match, try aliases recursively
{
String name = aliases.get(loc.toString());
name = aliases.get(name);
if (name != null) return getRaw(name);
}
@ -301,7 +261,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
* @return true if a matching entry was found.
*/
@Override
public boolean containsKey(Object name)
public boolean containsKey(ResourceLocation name)
{
boolean ret = super.containsKey(name);
@ -326,7 +286,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
* @param itemName Block/Item registry name.
* @return Block/Item id or -1 if it wasn't found.
*/
public int getId(String itemName)
public int getId(ResourceLocation itemName)
{
I obj = getRaw(itemName);
if (obj == null) return -1;
@ -334,15 +294,6 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
return getId(obj);
}
/**
* @deprecated use containsKey instead
*/
@Deprecated
public boolean contains(String itemName)
{
return containsKey(itemName);
}
/*
* This iterator is used by FML to visit the actual block sets, it should use the super.iterator method instead
* Compare #iterator()
@ -354,44 +305,36 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
// internal
public void serializeInto(Map<String, Integer> idMapping) // for saving
public void serializeIds(Map<ResourceLocation, Integer> idMapping) // for saving
{
for (I thing : this.typeSafeIterable())
{
idMapping.put(getNameForObject(thing).toString(), getId(thing));
idMapping.put(getNameForObject(thing), getId(thing));
}
}
public void serializeAliases(Map<String, String> map)
public void serializeAliases(Map<ResourceLocation, ResourceLocation> map)
{
map.putAll(this.aliases);
}
public void serializeSubstitutions(Set<String> set)
public void serializeSubstitutions(Set<ResourceLocation> set)
{
set.addAll(activeSubstitutions.keySet());
}
private BitSet internalAvailabilityMap = new BitSet();
int add(int id, String name, Object thing) {
return add(id, name, superType.cast(thing), internalAvailabilityMap);
}
/**
* Add the specified object to the registry.
*
* @param id ID to use if available, auto-assigned otherwise.
* @param name Name to use, prefixed by the mod id.
* @param thing Object to add.
* @param availabilityMap Map marking available IDs for auto assignment.
* @return ID eventually allocated.
*/
int add(int id, String name, I thing, BitSet availabilityMap)
int add(int id, ResourceLocation name, I thing)
{
if (name == null) throw new NullPointerException(String.format("Can't use a null-name for the registry, object %s.", thing));
if (name.isEmpty()) throw new IllegalArgumentException(String.format("Can't use an empty name for the registry, object %s.", thing));
if (name.indexOf(':') == -1) throw new IllegalArgumentException(String.format("Can't add the name (%s) without a prefix, object %s", name, thing));
if (thing == null) throw new NullPointerException(String.format("Can't add null-object to the registry, name %s.", name));
if (optionalDefaultKey != null && optionalDefaultKey.toString().equals(name) && this.optionalDefaultObject == null)
if (optionalDefaultKey != null && optionalDefaultKey.equals(name) && this.optionalDefaultObject == null)
{
this.optionalDefaultObject = thing;
}
@ -421,43 +364,50 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
if (getId(thing) >= 0) // duplicate object - but only if it's not being substituted
{
int foundId = getId(thing);
Object otherThing = getRaw(foundId);
I otherThing = getRaw(foundId);
throw new IllegalArgumentException(String.format("The object %s{%x} has been registered twice, using the names %s and %s. (Other object at this id is %s{%x})", thing, System.identityHashCode(thing), getNameForObject(thing), name, otherThing, System.identityHashCode(otherThing)));
}
if (GameData.isFrozen(this))
if (PersistentRegistryManager.isFrozen(this))
{
FMLLog.bigWarning("The object %s (name %s) is being added too late.", thing, name);
}
if (activeSubstitutions.containsKey(name))
{
I oldThing = thing;
thing = activeSubstitutions.get(name);
if (DEBUG) FMLLog.getLogger().log(Level.DEBUG, "Active substitution: {} {}@{} -> {}@{}",name, oldThing.getClass().getName(), System.identityHashCode(oldThing), thing.getClass().getName(), System.identityHashCode(thing));
}
addObjectRaw(idToUse, new ResourceLocation(name), thing);
addObjectRaw(idToUse, name, thing);
if (isDelegated)
{
getExistingDelegate(thing).setResourceName(name);
}
if (DEBUG)
FMLLog.finer("Registry add: %s %d %s (req. id %d)", name, idToUse, thing, id);
return idToUse;
}
void addAlias(String from, String to)
void addAlias(ResourceLocation from, ResourceLocation to)
{
aliases.put(from, to);
if (DEBUG)
FMLLog.finer("Registry alias: %s -> %s", from, to);
}
Map<String,Integer> getEntriesNotIn(FMLControlledNamespacedRegistry<I> registry)
Map<ResourceLocation,Integer> getEntriesNotIn(FMLControlledNamespacedRegistry<I> registry)
{
Map<String,Integer> ret = new HashMap<String, Integer>();
Map<ResourceLocation,Integer> ret = new HashMap<ResourceLocation, Integer>();
for (I thing : this.typeSafeIterable())
{
if (!registry.inverseObjectRegistry.containsKey(thing))
{
if (!registry.activeSubstitutions.containsKey(getNameForObject(thing).toString()))
if (!registry.activeSubstitutions.containsKey(getNameForObject(thing)))
{
ret.put(getNameForObject(thing).toString(), getId(thing));
ret.put(getNameForObject(thing), getId(thing));
}
}
}
@ -465,7 +415,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
return ret;
}
void dump()
void dump(ResourceLocation registryName)
{
if (!DEBUG)
return;
@ -479,7 +429,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
// sort by id
Collections.sort(ids);
FMLLog.finer("Registry Name : {}", registryName);
for (int id : ids)
{
I thing = getRaw(id);
@ -490,7 +440,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
/**
* Version of addObject not using the API restricting overrides.
*/
private void addObjectRaw(int id, Object name, I thing)
private void addObjectRaw(int id, ResourceLocation name, I thing)
{
if (name == null) throw new NullPointerException("The name to be added to the registry is null. This can only happen with a corrupted registry state. Reflection/ASM hackery? Registry bug?");
if (thing == null) throw new NullPointerException("The object to be added to the registry is null. This can only happen with a corrupted registry state. Reflection/ASM hackery? Registry bug?");
@ -498,6 +448,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
underlyingIntegerMap.put(thing, id); // obj <-> id
super.putObject(name, thing); // name <-> obj
availabilityMap.set(id);
}
public I getDefaultValue()
@ -506,37 +457,35 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
}
public RegistryDelegate<I> getDelegate(I thing, Class<I> clazz) {
return GameData.buildDelegate(thing, clazz);
return new RegistryDelegate.Delegate<I>(thing, clazz);
}
void activateSubstitution(String nameToReplace)
@SuppressWarnings("unchecked")
public Delegate<I> getExistingDelegate(I thing) {
try {
return (Delegate<I>) delegateAccessor.get(thing);
} catch (IllegalAccessException e) {
FMLLog.log(Level.ERROR, e, "Illegal attempt to access delegate");
throw Throwables.propagate(e);
}
}
void activateSubstitution(ResourceLocation nameToReplace)
{
if (getPersistentSubstitutions().containsKey(nameToReplace))
{
I original = getRaw(nameToReplace);
if (superType == Item.class) {
Item sub = (Item) getPersistentSubstitutions().get(nameToReplace);
if (original == null) {
// When we're activated from the server side, we need to set the delegate on the original instance to
// point to us. Go to the "default state" registry to get it
original = (I)GameData.getItemRegistry().getRaw(nameToReplace);
}
FMLLog.log(Level.DEBUG, "Replacing %s with %s (name %s)", original, sub, nameToReplace);
Delegate<Item> delegate = (Delegate<Item>)((Item)original).delegate;
delegate.changeReference(sub);
((Delegate<Item>)sub.delegate).setName(nameToReplace);
}
activeSubstitutions.put(nameToReplace, getPersistentSubstitutions().get(nameToReplace));
I sub = getPersistentSubstitutions().get(nameToReplace);
getExistingDelegate(original).changeReference(sub);
activeSubstitutions.put(nameToReplace, sub);
}
}
void addSubstitutionAlias(String modId, String nameToReplace, Object toReplace) throws ExistingSubstitutionException {
if (getPersistentSubstitutions().containsKey(nameToReplace) || getPersistentSubstitutions().containsValue(toReplace))
void addSubstitutionAlias(String modId, ResourceLocation nameToReplace, I replacement) throws ExistingSubstitutionException {
if (getPersistentSubstitutions().containsKey(nameToReplace) || getPersistentSubstitutions().containsValue(replacement))
{
FMLLog.severe("The substitution of %s has already occured. You cannot duplicate substitutions", nameToReplace);
throw new ExistingSubstitutionException(nameToReplace, toReplace);
FMLLog.severe("The substitution of %s has already occurred. You cannot duplicate substitutions", nameToReplace);
throw new ExistingSubstitutionException(nameToReplace, replacement);
}
I replacement = cast(toReplace);
I original = getRaw(nameToReplace);
if (original == null)
{
@ -557,12 +506,8 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
getPersistentSubstitutions().put(nameToReplace, replacement);
}
private BiMap<String, I> getPersistentSubstitutions()
private BiMap<ResourceLocation, I> getPersistentSubstitutions()
{
if (persistentSubstitutions == null)
{
persistentSubstitutions = GameData.getMain().getPersistentSubstitutionMap(superType);
}
return persistentSubstitutions;
}
@ -576,6 +521,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
* This iterator is used by some regular MC methods to visit all blocks, we need to include substitutions
* Compare #typeSafeIterable()
*/
@SuppressWarnings("unchecked")
@Override
public Iterator<I> iterator()
{
@ -585,14 +531,72 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespacedDefaul
FMLControlledNamespacedRegistry<I> makeShallowCopy() {
return new FMLControlledNamespacedRegistry<I>(optionalDefaultKey, maxId, minId, superType);
return new FMLControlledNamespacedRegistry<I>(optionalDefaultKey, maxId, minId, superType, isDelegated);
}
// ONLY CALLED ON ITEM registry
void resetSubstitutionDelegates()
{
for (I item: typeSafeIterable()) {
Delegate<Item> delegate = (Delegate<Item>)((Item)item).delegate;
delegate.changeReference((Item)item);
if (!isDelegated) return;
for (I obj: typeSafeIterable()) {
Delegate<I> delegate = getExistingDelegate(obj);
delegate.changeReference(obj);
}
}
@SuppressWarnings("unchecked")
public <T> FMLControlledNamespacedRegistry<T> asType(Class<? extends T> type)
{
return (FMLControlledNamespacedRegistry<T>) this;
}
public void serializeBlockList(Set<Integer> blocked) {
blocked.addAll(this.blockedIds);
}
public Set<? extends ResourceLocation> getActiveSubstitutions() {
return activeSubstitutions.keySet();
}
public void loadAliases(Map<ResourceLocation, ResourceLocation> aliases) {
for (Map.Entry<ResourceLocation, ResourceLocation> alias : aliases.entrySet()) {
addAlias(alias.getKey(), alias.getValue());
}
}
public void loadSubstitutions(Set<ResourceLocation> substitutions) {
for (ResourceLocation rl : substitutions) {
activateSubstitution(rl);
}
}
public void loadBlocked(Set<Integer> blocked) {
for (Integer id : blocked) {
blockedIds.add(id);
availabilityMap.set(id);
}
}
public void loadIds(Map<ResourceLocation, Integer> ids, Map<ResourceLocation, Integer> missingIds, Map<ResourceLocation, Integer[]> remappedIds, FMLControlledNamespacedRegistry<I> currentRegistry, ResourceLocation registryName) {
for (Map.Entry<ResourceLocation, Integer> entry : ids.entrySet()) {
ResourceLocation itemName = entry.getKey();
int newId = entry.getValue();
int currId = currentRegistry.getId(itemName);
if (currId == -1) {
FMLLog.info("Found a missing id from the world %s", itemName);
missingIds.put(entry.getKey(), newId);
continue; // no block/item -> nothing to add
} else if (currId != newId) {
FMLLog.fine("Fixed %s id mismatch %s: %d (init) -> %d (map).", registryName, itemName, currId, newId);
remappedIds.put(itemName, new Integer[]{currId, newId});
}
I obj = currentRegistry.getRaw(itemName);
add(newId, itemName, obj);
}
}
public void blockId(int id) {
blockedIds.add(id);
}
}

View file

@ -392,22 +392,8 @@ public class GameRegistry
}
public enum Type {
BLOCK
{
@Override
public FMLControlledNamespacedRegistry<?> getRegistry() {
return GameData.getBlockRegistry();
}
},
ITEM
{
@Override
public FMLControlledNamespacedRegistry<?> getRegistry() {
return GameData.getItemRegistry();
}
};
public abstract FMLControlledNamespacedRegistry<?> getRegistry();
BLOCK,
ITEM;
}
/**
* Look up the mod identifier data for a block.
@ -505,7 +491,7 @@ public class GameRegistry
public static ItemStack makeItemStack(String itemName, int meta, int stackSize, String nbtString)
{
if (itemName == null) throw new IllegalArgumentException("The itemName cannot be null");
Item item = GameData.getItemRegistry().getObject(itemName);
Item item = GameData.getItemRegistry().getObject(new ResourceLocation(itemName));
if (item == null) {
FMLLog.getLogger().log(Level.TRACE, "Unable to find item with name {}", itemName);
return null;

View file

@ -1,7 +1,9 @@
package net.minecraftforge.fml.common.registry;
import net.minecraft.util.ResourceLocation;
public class IncompatibleSubstitutionException extends RuntimeException {
public IncompatibleSubstitutionException(String fromName, Object replacement, Object original)
public IncompatibleSubstitutionException(ResourceLocation fromName, Object replacement, Object original)
{
super(String.format("The substitute %s for %s (type %s) is type incompatible.", replacement.getClass().getName(), fromName, original.getClass().getName()));
}

View file

@ -4,6 +4,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import net.minecraft.util.ResourceLocation;
import org.apache.logging.log4j.Level;
import com.google.common.base.Throwables;
@ -23,12 +24,12 @@ import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder;
*/
class ObjectHolderRef {
private Field field;
private String injectedObject;
private ResourceLocation injectedObject;
private boolean isBlock;
private boolean isItem;
ObjectHolderRef(Field field, String injectedObject, boolean extractFromExistingValues)
ObjectHolderRef(Field field, ResourceLocation injectedObject, boolean extractFromExistingValues)
{
this.field = field;
this.isBlock = Block.class.isAssignableFrom(field.getType());
@ -49,10 +50,9 @@ class ObjectHolderRef {
}
else
{
@SuppressWarnings("unchecked")
Object tmp = isBlock ? GameData.getBlockRegistry().getNameForObject(existing) :
isItem ? GameData.getItemRegistry().getNameForObject(existing) : null;
this.injectedObject = tmp != null ? tmp.toString() : null;
ResourceLocation tmp = isBlock ? GameData.getBlockRegistry().getNameForObject((Block)existing) :
isItem ? GameData.getItemRegistry().getNameForObject((Item)existing) : null;
this.injectedObject = tmp;
}
} catch (Exception e)
{

View file

@ -6,6 +6,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.discovery.ASMDataTable;
import net.minecraftforge.fml.common.discovery.ASMDataTable.ASMData;
@ -97,7 +98,7 @@ public enum ObjectHolderRegistry {
try
{
Field f = clazz.getField(annotationTarget);
addHolderReference(new ObjectHolderRef(f, value, extractFromValue));
addHolderReference(new ObjectHolderRef(f, new ResourceLocation(value), extractFromValue));
}
catch (Exception ex)
{
@ -118,7 +119,7 @@ public enum ObjectHolderRegistry {
{
continue;
}
addHolderReference(new ObjectHolderRef(f, value + ":"+ f.getName(), extractFromExistingValues));
addHolderReference(new ObjectHolderRef(f, new ResourceLocation(value, f.getName()), extractFromExistingValues));
}
}

View file

@ -0,0 +1,407 @@
package net.minecraftforge.fml.common.registry;
import java.io.IOException;
import java.util.*;
import com.google.common.base.Function;
import com.google.common.collect.*;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraftforge.fml.common.*;
import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent;
import org.apache.logging.log4j.Level;
import com.google.common.collect.Sets.SetView;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nullable;
/**
* Persistent registry manager. Manages the registries loading from disk, and from network. Handles staging
* registry data before loading uniformly into the active registry, and keeps a frozen registry instance
* for reversion after connection.
* @author cpw
*/
public class PersistentRegistryManager
{
private enum PersistentRegistry {
ACTIVE, FROZEN, STAGING;
private final BiMap<ResourceLocation,FMLControlledNamespacedRegistry<?>> registries = HashBiMap.create();
private final BiMap<Class<?>,ResourceLocation> registrySuperTypes = HashBiMap.create();
@SuppressWarnings("unchecked")
<T> FMLControlledNamespacedRegistry<T> getRegistry(ResourceLocation key, Class<T> regType)
{
return (FMLControlledNamespacedRegistry<T>) registries.get(key);
}
<T> FMLControlledNamespacedRegistry<T> getOrShallowCopyRegistry(ResourceLocation key, Class<T> regType, FMLControlledNamespacedRegistry<T> other)
{
if (!registries.containsKey(key)) {
registries.put(key, other.makeShallowCopy());
registrySuperTypes.put(regType, key);
}
return getRegistry(key, regType);
}
private <T> FMLControlledNamespacedRegistry<T> createRegistry(ResourceLocation registryName, Class<T> type, ResourceLocation defaultObjectKey, int minId, int maxId, boolean isDelegated) {
Set<Class<?>> parents = Sets.newHashSet();
findSuperTypes(type, parents);
SetView<Class<?>> overlappedTypes = Sets.intersection(parents, registrySuperTypes.keySet());
if (!overlappedTypes.isEmpty()) {
Class<?> foundType = overlappedTypes.iterator().next();
FMLLog.severe("Found existing registry of type %1s named %2s, you cannot create a new registry (%3s) with type %4s, as %4s has a parent of that type", foundType, registrySuperTypes.get(foundType), registryName, type);
throw new IllegalArgumentException("Duplicate registry parent type found - you can only have one registry for a particular super type");
}
FMLControlledNamespacedRegistry<T> fmlControlledNamespacedRegistry = new FMLControlledNamespacedRegistry<T>(defaultObjectKey, maxId, minId, type, isDelegated);
registries.put(registryName, fmlControlledNamespacedRegistry);
registrySuperTypes.put(type, registryName);
return getRegistry(registryName, type);
}
private void findSuperTypes(Class<?> type, Set<Class<?>> types)
{
if (type == null || type == Object.class) {
return;
}
types.add(type);
for (Class<?> interfac : type.getInterfaces()) {
findSuperTypes(interfac, types);
}
findSuperTypes(type.getSuperclass(),types);
}
void clean() {
registries.clear();
registrySuperTypes.clear();
}
boolean isPopulated() {
return !registries.isEmpty();
}
boolean containsRegistry(FMLControlledNamespacedRegistry<?> registry) {
return registries.containsValue(registry);
}
public <T> FMLControlledNamespacedRegistry<T> getRegistry(Class<T> rootClass) {
ResourceLocation rl = registrySuperTypes.get(rootClass);
return getRegistry(rl, rootClass);
}
}
public static final ResourceLocation BLOCKS = new ResourceLocation("minecraft:blocks");
public static final ResourceLocation ITEMS = new ResourceLocation("minecraft:items");
public static <T> FMLControlledNamespacedRegistry<T> createRegistry(ResourceLocation registryName, Class<T> registryType, ResourceLocation optionalDefaultKey, int maxId, int minId, boolean hasDelegates) {
return PersistentRegistry.ACTIVE.createRegistry(registryName,registryType,optionalDefaultKey,minId, maxId, hasDelegates);
}
public static List<String> injectSnapshot(GameDataSnapshot snapshot, boolean injectFrozenData, boolean isLocalWorld) {
FMLLog.info("Injecting existing block and item data into this {} instance", FMLCommonHandler.instance().getEffectiveSide().isServer() ? "server" : "client");
final Map<ResourceLocation, Map<ResourceLocation,Integer[]>> remaps = Maps.newHashMap();
final LinkedHashMap<ResourceLocation, Map<ResourceLocation,Integer>> missing = Maps.newLinkedHashMap();
forAllRegistries(PersistentRegistry.ACTIVE, ValidateRegistryFunction.OPERATION);
forAllRegistries(PersistentRegistry.ACTIVE, DumpRegistryFunction.OPERATION);
forAllRegistries(PersistentRegistry.ACTIVE, ResetDelegatesFunction.OPERATION);
// Load the snapshot into the "STAGING" registry
for (Map.Entry<ResourceLocation, GameDataSnapshot.Entry> snapshotEntry : snapshot.entries.entrySet())
{
loadPersistentDataToStagingRegistry(injectFrozenData, remaps, missing, snapshotEntry, PersistentRegistry.ACTIVE.registrySuperTypes.inverse().get(snapshotEntry.getKey()));
}
// If we have missed data, fire the missing mapping event
List<String> missedMappings = Loader.instance().fireMissingMappingEvent(missing.get(BLOCKS), missing.get(ITEMS), isLocalWorld, remaps.get(BLOCKS), remaps.get(ITEMS));
// If there's still missed mappings, we return, because that's an error
if (!missedMappings.isEmpty()) return missedMappings;
// If we're loading up the world from disk, we want to add in the new data that might have been provisioned by mods
if (injectFrozenData)
{
// So we load it from the frozen persistent registry
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet()) {
loadFrozenDataToStagingRegistry(remaps, r.getKey(), PersistentRegistry.ACTIVE.registrySuperTypes.inverse().get(r.getKey()));
}
}
// Validate that all the STAGING data is good
forAllRegistries(PersistentRegistry.STAGING, ValidateRegistryFunction.OPERATION);
// Load the STAGING registry into the ACTIVE registry
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet()) {
loadRegistry(r.getKey(), PersistentRegistry.STAGING, PersistentRegistry.ACTIVE, PersistentRegistry.ACTIVE.registrySuperTypes.inverse().get(r.getKey()));
}
// Dump the active registry
forAllRegistries(PersistentRegistry.ACTIVE, DumpRegistryFunction.OPERATION);
// Tell mods that the ids have changed
Loader.instance().fireRemapEvent(remaps.get(BLOCKS), remaps.get(ITEMS));
// The id map changed, ensure we apply object holders
ObjectHolderRegistry.INSTANCE.applyObjectHolders();
// Return an empty list, because we're good
return ImmutableList.of();
}
private static void forAllRegistries(PersistentRegistry registrySet, Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void> operation) {
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : registrySet.registries.entrySet())
{
operation.apply(r);
}
}
private static <T> void loadRegistry(ResourceLocation registryName, PersistentRegistry from, PersistentRegistry to, Class<T> regType) {
FMLControlledNamespacedRegistry<T> fromRegistry = from.getRegistry(registryName, regType);
FMLControlledNamespacedRegistry<T> toRegistry = to.getOrShallowCopyRegistry(registryName, regType, fromRegistry);
toRegistry.set(fromRegistry);
}
private static <T> void loadFrozenDataToStagingRegistry(Map<ResourceLocation, Map<ResourceLocation, Integer[]>> remaps, ResourceLocation registryName, Class<T> regType) {
FMLControlledNamespacedRegistry<T> newRegistry = PersistentRegistry.STAGING.getRegistry(registryName, regType);
FMLControlledNamespacedRegistry<T> frozenRegistry = PersistentRegistry.FROZEN.getRegistry(registryName, regType);
newRegistry.loadIds(frozenRegistry.getEntriesNotIn(newRegistry), Maps.<ResourceLocation, Integer>newLinkedHashMap(), remaps.get(registryName), frozenRegistry, registryName);
}
private static <T> void loadPersistentDataToStagingRegistry(boolean injectFrozenData, Map<ResourceLocation, Map<ResourceLocation, Integer[]>> remaps, LinkedHashMap<ResourceLocation, Map<ResourceLocation, Integer>> missing, Map.Entry<ResourceLocation, GameDataSnapshot.Entry> snapEntry, Class<T> regType) {
ResourceLocation registryName = snapEntry.getKey();
FMLControlledNamespacedRegistry<T> currentRegistry = PersistentRegistry.ACTIVE.getRegistry(registryName, regType);
if (currentRegistry == null) {
FMLLog.severe("An unknown persistent registry type {} has been encountered. This Forge instance cannot understand it.", registryName);
StartupQuery.abort();
}
FMLControlledNamespacedRegistry<T> newRegistry = PersistentRegistry.STAGING.getOrShallowCopyRegistry(registryName, regType, currentRegistry);
GameDataSnapshot.Entry snapshotEntry = snapEntry.getValue();
Set<ResourceLocation> substitutions = snapshotEntry.substitutions;
if (injectFrozenData)
{
substitutions = Sets.union(snapshotEntry.substitutions, currentRegistry.getActiveSubstitutions());
}
newRegistry.loadAliases(snapshotEntry.aliases);
newRegistry.loadSubstitutions(substitutions);
newRegistry.loadBlocked(snapshotEntry.blocked);
missing.put(registryName, Maps.<ResourceLocation, Integer>newLinkedHashMap());
remaps.put(registryName, Maps.<ResourceLocation, Integer[]>newHashMap());
newRegistry.loadIds(snapshotEntry.ids, missing.get(registryName), remaps.get(registryName), currentRegistry, registryName);
}
public static boolean isFrozen(FMLControlledNamespacedRegistry<?> registry) {
return PersistentRegistry.FROZEN.containsRegistry(registry);
}
public static void revertToFrozen() {
if (!PersistentRegistry.FROZEN.isPopulated()) {
FMLLog.warning("Can't revert to frozen GameData state without freezing first.");
} else {
FMLLog.fine("Reverting to frozen data state.");
}
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet()) {
loadRegistry(r.getKey(), PersistentRegistry.FROZEN, PersistentRegistry.ACTIVE, PersistentRegistry.ACTIVE.registrySuperTypes.inverse().get(r.getKey()));
}
// the id mapping has reverted, fire remap events for those that care about id changes
Loader.instance().fireRemapEvent(ImmutableMap.<ResourceLocation, Integer[]>of(), ImmutableMap.<ResourceLocation, Integer[]>of());
// the id mapping has reverted, ensure we sync up the object holders
ObjectHolderRegistry.INSTANCE.applyObjectHolders();
}
public static void freezeData() {
FMLLog.fine("Freezing block and item id maps");
for (Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> r : PersistentRegistry.ACTIVE.registries.entrySet()) {
loadRegistry(r.getKey(), PersistentRegistry.ACTIVE, PersistentRegistry.FROZEN, PersistentRegistry.ACTIVE.registrySuperTypes.inverse().get(r.getKey()));
}
forAllRegistries(PersistentRegistry.FROZEN, ValidateRegistryFunction.OPERATION);
}
public static List<String> processIdRematches(Iterable<FMLMissingMappingsEvent.MissingMapping> missedMappings, boolean isLocalWorld, Map<ResourceLocation, Integer[]> remapBlocks, Map<ResourceLocation, Integer[]> remapItems) {
List<String> failed = Lists.newArrayList();
List<String> ignored = Lists.newArrayList();
List<String> warned = Lists.newArrayList();
List<String> defaulted = Lists.newArrayList();
final PersistentRegistry staging = PersistentRegistry.STAGING;
final PersistentRegistry active = PersistentRegistry.ACTIVE;
for (FMLMissingMappingsEvent.MissingMapping remap : missedMappings) {
FMLMissingMappingsEvent.Action action = remap.getAction();
if (action == FMLMissingMappingsEvent.Action.REMAP) {
// block/item re-mapped, finish the registration with the new name/object, but the old id
int currId = -1, newId = -1;
ResourceLocation newName;
if (remap.type == GameRegistry.Type.BLOCK) {
currId = staging.getRegistry(BLOCKS, Block.class).getId((Block) remap.getTarget());
newName = active.getRegistry(BLOCKS, Block.class).getNameForObject((Block)remap.getTarget());
FMLLog.fine("The Block %s is being remapped to %s.", remap.name, newName);
newId = staging.getRegistry(BLOCKS,Block.class).add(remap.id, newName, (Block) remap.getTarget());
staging.getRegistry(BLOCKS,Block.class).addAlias(remap.resourceLocation, newName);
} else if (remap.type == GameRegistry.Type.ITEM) {
currId = staging.getRegistry(ITEMS, Item.class).getId((Item) remap.getTarget());
newName = active.getRegistry(ITEMS, Item.class).getNameForObject((Item)remap.getTarget());
FMLLog.fine("The Item %s is being remapped to %s.", remap.name, newName);
newId = staging.getRegistry(ITEMS,Item.class).add(remap.id, newName, (Item) remap.getTarget());
staging.getRegistry(ITEMS,Item.class).addAlias(remap.resourceLocation, newName);
} else {
// currently not remapping non-blocks and items
continue;
}
if (newId != remap.id) throw new IllegalStateException();
if (currId != newId) {
FMLLog.info("Fixed %s id mismatch %s: %d (init) -> %d (map).", remap.type == GameRegistry.Type.BLOCK ? "block" : "item", newName, currId, newId);
(remap.type == GameRegistry.Type.BLOCK ? remapBlocks : remapItems).put(newName, new Integer[]{currId, newId});
}
} else if (action == FMLMissingMappingsEvent.Action.BLOCKONLY) {
// Pulled out specifically so the block doesn't get reassigned a new ID just because it's
// Item block has gone away
FMLLog.fine("The ItemBlock %s is no longer present in the game. The residual block will remain", remap.name);
} else {
// block item missing, warn as requested and block the id
if (action == FMLMissingMappingsEvent.Action.DEFAULT) {
defaulted.add(remap.name);
} else if (action == FMLMissingMappingsEvent.Action.IGNORE) {
ignored.add(remap.name);
} else if (action == FMLMissingMappingsEvent.Action.FAIL) {
failed.add(remap.name);
} else if (action == FMLMissingMappingsEvent.Action.WARN) {
warned.add(remap.name);
}
// prevent the id from being reused later
if (remap.type == GameRegistry.Type.BLOCK) {
staging.getRegistry(BLOCKS, Block.class).blockId(remap.id);
} else if (remap.type == GameRegistry.Type.ITEM) {
staging.getRegistry(ITEMS, Item.class).blockId(remap.id);
}
}
}
if (!defaulted.isEmpty()) {
String text = "Forge Mod Loader detected missing blocks/items.\n\n" +
"There are " + defaulted.size() + " missing blocks and items in this save.\n" +
"If you continue the missing blocks/items will get removed.\n" +
"A world backup will be automatically created in your saves directory.\n\n" +
"Missing Blocks/Items:\n";
for (String s : defaulted) text += s + "\n";
boolean confirmed = StartupQuery.confirm(text);
if (!confirmed) StartupQuery.abort();
try {
String skip = System.getProperty("fml.doNotBackup");
if (skip == null || !"true".equals(skip)) {
ZipperUtil.backupWorld();
} else {
for (int x = 0; x < 10; x++)
FMLLog.severe("!!!!!!!!!! UPDATING WORLD WITHOUT DOING BACKUP !!!!!!!!!!!!!!!!");
}
} catch (IOException e) {
StartupQuery.notify("The world backup couldn't be created.\n\n" + e);
StartupQuery.abort();
}
warned.addAll(defaulted);
}
if (!failed.isEmpty()) {
FMLLog.severe("This world contains blocks and items that refuse to be remapped. The world will not be loaded");
return failed;
}
if (!warned.isEmpty()) {
FMLLog.warning("This world contains block and item mappings that may cause world breakage");
return failed;
} else if (!ignored.isEmpty()) {
FMLLog.fine("There were %d missing mappings that have been ignored", ignored.size());
}
return failed;
}
public static GameDataSnapshot takeSnapshot() {
final GameDataSnapshot snap = new GameDataSnapshot();
forAllRegistries(PersistentRegistry.ACTIVE, new Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void>() {
@Override
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input) {
snap.entries.put(input.getKey(), new GameDataSnapshot.Entry(input.getValue()));
return null;
}
});
return snap;
}
public static class GameDataSnapshot {
public static class Entry {
public final Map<ResourceLocation, Integer> ids;
public final Set<ResourceLocation> substitutions;
public final Map<ResourceLocation, ResourceLocation> aliases;
public final Set<Integer> blocked;
public Entry() {
this(new HashMap<ResourceLocation, Integer>(), new HashSet<ResourceLocation>(), new HashMap<ResourceLocation, ResourceLocation>(), new HashSet<Integer>());
}
public Entry(Map<ResourceLocation, Integer> ids, Set<ResourceLocation> substitutions, Map<ResourceLocation, ResourceLocation> aliases, Set<Integer> blocked) {
this.ids = ids;
this.substitutions = substitutions;
this.aliases = aliases;
this.blocked = blocked;
}
public Entry(FMLControlledNamespacedRegistry<?> registry) {
this.ids = Maps.newHashMap();
this.substitutions = Sets.newHashSet();
this.aliases = Maps.newHashMap();
this.blocked = Sets.newHashSet();
registry.serializeIds(this.ids);
registry.serializeSubstitutions(this.substitutions);
registry.serializeAliases(this.aliases);
registry.serializeBlockList(this.blocked);
}
}
public final Map<ResourceLocation, Entry> entries = Maps.newHashMap();
}
public static <T> RegistryDelegate<T> makeDelegate(T obj, Class<T> rootClass) {
return PersistentRegistry.ACTIVE.getRegistry(rootClass).getDelegate(obj, rootClass);
}
private static class DumpRegistryFunction implements Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void> {
static final DumpRegistryFunction OPERATION = new DumpRegistryFunction();
@Override
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input) {
input.getValue().dump(input.getKey());
return null;
}
}
private static class ValidateRegistryFunction implements Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void> {
static final ValidateRegistryFunction OPERATION = new ValidateRegistryFunction();
@Override
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input) {
input.getValue().validateContent(input.getKey());
return null;
}
}
private static class ResetDelegatesFunction implements Function<Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>>, Void> {
static final ResetDelegatesFunction OPERATION = new ResetDelegatesFunction();
@Override
public Void apply(Map.Entry<ResourceLocation, FMLControlledNamespacedRegistry<?>> input) {
input.getValue().resetSubstitutionDelegates();
return null;
}
}
}

View file

@ -1,6 +1,7 @@
package net.minecraftforge.fml.common.registry;
import com.google.common.base.Objects;
import net.minecraft.util.ResourceLocation;
/**
@ -24,12 +25,24 @@ public interface RegistryDelegate<T> {
/**
* Get the name of this delegate. This is completely static after registration has completed and will never change.
*
* Deprecated in favour of the resource location.
*
* @see #getResourceName()
* @return The name
*/
@Deprecated
String name();
/**
* Get the delegate type. It will be Item or Block.
* Get the unique resource location for this delegate. Completely static after registration has completed, and
* will never change.
* @return The name
*/
ResourceLocation getResourceName();
/**
* Get the delegate type. It will be dependent on the registry this delegate is sourced from.
* @return The type of delegate
*/
Class<T> type();
@ -40,7 +53,7 @@ public interface RegistryDelegate<T> {
final class Delegate<T> implements RegistryDelegate<T>
{
private T referant;
private String name;
private ResourceLocation name;
private final Class<T> type;
public Delegate(T referant, Class<T> type) {
@ -55,9 +68,12 @@ public interface RegistryDelegate<T> {
@Override
public String name() {
return name;
return name.toString();
}
@Override
public ResourceLocation getResourceName() { return name; }
@Override
public Class<T> type()
{
@ -69,10 +85,7 @@ public interface RegistryDelegate<T> {
this.referant = newTarget;
}
void setName(String name)
{
this.name = name;
}
void setResourceName(ResourceLocation name) { this.name = name; }
@Override
public boolean equals(Object obj)

View file

@ -17,6 +17,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.apache.commons.lang3.Validate;
import net.minecraft.entity.passive.EntityVillager;
@ -191,14 +193,13 @@ public class VillagerRegistry
{
register(prof, -1);
}
@SuppressWarnings("deprecation")
private void register(VillagerProfession prof, int id)
{
professions.register(id, prof.name, prof);
}
private boolean hasInit = false;
private FMLControlledNamespacedRegistry<VillagerProfession> professions = GameData.createRegistry("villagerprofessions", VillagerProfession.class, 0, 1024);
private FMLControlledNamespacedRegistry<VillagerProfession> professions = PersistentRegistryManager.createRegistry(new ResourceLocation("minecraft:villagerprofessions"), VillagerProfession.class, null, 1024, 0, true);
private void init()
@ -242,22 +243,22 @@ public class VillagerRegistry
public static class VillagerProfession
{
private ResourceLocation name;
//private ResourceLocation texture;
private ResourceLocation texture;
private List<VillagerCareer> careers = Lists.newArrayList();
private RegistryDelegate<VillagerProfession> delegate = GameData.getRegistry("villagerprofessions", VillagerProfession.class).getDelegate(this, VillagerProfession.class);
public final RegistryDelegate<VillagerProfession> delegate = PersistentRegistryManager.makeDelegate(this, VillagerProfession.class);
public VillagerProfession(String name, String texture)
{
this.name = new ResourceLocation(name);
//this.texture = new ResourceLocation(texture);
((RegistryDelegate.Delegate<VillagerProfession>)delegate).setName(name);
this.texture = new ResourceLocation(texture);
((RegistryDelegate.Delegate<VillagerProfession>)delegate).setResourceName(this.name);
}
private void register(VillagerCareer career)
{
Validate.isTrue(!careers.contains(career), "Attempted to register career that is already registered.");
Validate.isTrue(career.profession == this, "Attempted to register career for the wrong profession.");
//career.id = careers.size();
career.id = careers.size();
careers.add(career);
}
}
@ -266,7 +267,7 @@ public class VillagerRegistry
{
private VillagerProfession profession;
private String name;
//private int id;
private int id;
public VillagerCareer(VillagerProfession parent, String name)
{
this.profession = parent;
@ -297,8 +298,8 @@ public class VillagerRegistry
*/
public static void setRandomProfession(EntityVillager entity, Random rand)
{
//int count = INSTANCE.professions.getKeys().size();
//int prof = rand.nextInt(count);
Set<ResourceLocation> entries = INSTANCE.professions.getKeys();
int prof = rand.nextInt(entries.size());
//TODO: Grab id range from internal registry
entity.setProfession(rand.nextInt(5));
}

View file

@ -8,6 +8,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.util.ResourceLocation;
import org.apache.logging.log4j.Level;
import net.minecraft.block.Block;
@ -325,7 +326,7 @@ public class OreDictionary
// HACK: use the registry name's ID. It is unique and it knows about substitutions. Fallback to a -1 value (what Item.getIDForItem would have returned) in the case where the registry is not aware of the item yet
// IT should be noted that -1 will fail the gate further down, if an entry already exists with value -1 for this name. This is what is broken and being warned about.
// APPARENTLY it's quite common to do this. OreDictionary should be considered alongside Recipes - you can't make them properly until you've registered with the game.
String registryName = stack.getItem().delegate.name();
ResourceLocation registryName = stack.getItem().delegate.getResourceName();
int id;
if (registryName == null)
{
@ -449,7 +450,7 @@ public class OreDictionary
// HACK: use the registry name's ID. It is unique and it knows about substitutions. Fallback to a -1 value (what Item.getIDForItem would have returned) in the case where the registry is not aware of the item yet
// IT should be noted that -1 will fail the gate further down, if an entry already exists with value -1 for this name. This is what is broken and being warned about.
// APPARENTLY it's quite common to do this. OreDictionary should be considered alongside Recipes - you can't make them properly until you've registered with the game.
String registryName = ore.getItem().delegate.name();
ResourceLocation registryName = ore.getItem().delegate.getResourceName();
int hash;
if (registryName == null)
{
@ -506,7 +507,7 @@ public class OreDictionary
for (ItemStack ore : ores)
{
// HACK: use the registry name's ID. It is unique and it knows about substitutions
String name = ore.getItem().delegate.name();
ResourceLocation name = ore.getItem().delegate.getResourceName();
int hash;
if (name == null)
{