Fluids are now tracked internally by mod. This allows for the server and the world to specify a "default"

in the case of a possible alternative fluid implementation. If you always called registerFluid, things
should work pretty seamlessly, but if you didn't (gating with an isFluidRegistered check for example)
you should change to register anyway. This way, even if you're not default in the overall instance, you may
become default if you're the only mod present on a server, for example, or in a world save.

This should radically decrease the mixups caused by mod load ordering problems, and other issues around fluid
tracking.
This commit is contained in:
cpw 2015-04-11 17:18:53 -04:00
parent eb12936a52
commit 9671179453
5 changed files with 145 additions and 12 deletions

View File

@ -26,6 +26,7 @@ import net.minecraftforge.classloading.FMLForgePlugin;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.common.network.ForgeNetworkHandler;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.RecipeSorter;
import net.minecraftforge.server.command.ForgeCommand;
@ -309,6 +310,7 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
NBTTagCompound forgeData = new NBTTagCompound();
NBTTagCompound dimData = DimensionManager.saveDimensionDataMap();
forgeData.setTag("DimensionData", dimData);
FluidRegistry.writeDefaultFluidList(forgeData);
return forgeData;
}
@ -316,6 +318,7 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
public void readData(SaveHandler handler, WorldInfo info, Map<String, NBTBase> propertyMap, NBTTagCompound tag)
{
DimensionManager.loadDimensionDataMap(tag.hasKey("DimensionData") ? tag.getCompoundTag("DimensionData") : null);
FluidRegistry.loadFluidDefaults(tag);
}
@Subscribe

View File

@ -12,7 +12,7 @@ public class FluidIdRegistryMessageHandler extends SimpleChannelInboundHandler<F
@Override
protected void channelRead0(ChannelHandlerContext ctx, ForgeMessage.FluidIdMapMessage msg) throws Exception
{
FluidRegistry.initFluidIDs(msg.fluidIds);
FluidRegistry.initFluidIDs(msg.fluidIds, msg.defaultFluids);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception

View File

@ -1,10 +1,18 @@
package net.minecraftforge.common.network;
import java.util.Map;
import java.util.Set;
import org.apache.logging.log4j.Level;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Sets;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.network.ByteBufUtils;
import io.netty.buffer.ByteBuf;
@ -39,6 +47,7 @@ public abstract class ForgeMessage {
public static class FluidIdMapMessage extends ForgeMessage {
BiMap<Fluid, Integer> fluidIds = HashBiMap.create();
Set<String> defaultFluids = Sets.newHashSet();
@Override
void toBytes(ByteBuf bytes)
{
@ -49,6 +58,11 @@ public abstract class ForgeMessage {
ByteBufUtils.writeUTF8String(bytes,entry.getKey().getName());
bytes.writeInt(entry.getValue());
}
for (Map.Entry<Fluid, Integer> entry : ids.entrySet())
{
String defaultName = FluidRegistry.getDefaultFluidName(entry.getKey());
ByteBufUtils.writeUTF8String(bytes, defaultName);
}
}
@Override
@ -60,6 +74,20 @@ public abstract class ForgeMessage {
int fluidId = bytes.readInt();
fluidIds.put(FluidRegistry.getFluid(fluidName), fluidId);
}
// do we have a defaults list?
if (bytes.isReadable())
{
for (int i = 0; i < listSize; i++)
{
defaultFluids.add(ByteBufUtils.readUTF8String(bytes));
}
}
else
{
FMLLog.getLogger().log(Level.INFO, "Legacy server message contains no default fluid list - there may be problems with fluids");
defaultFluids.clear();
}
}
}

View File

@ -1,21 +1,29 @@
package net.minecraftforge.fluids;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.logging.log4j.Level;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.util.StatCollector;
import net.minecraftforge.common.MinecraftForge;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableMap;
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.ModContainer;
import cpw.mods.fml.common.eventhandler.Event;
import cpw.mods.fml.common.network.ByteBufUtils;
/**
* Handles Fluid registrations. Fluids MUST be registered in order to function.
@ -32,6 +40,10 @@ public abstract class FluidRegistry
static BiMap<Integer, String> fluidNames = HashBiMap.create(); //Caching this just makes some other calls faster
static BiMap<Block, Fluid> fluidBlocks;
// the globally unique fluid map - only used to associate non-defaults during world/server loading
static BiMap<String,Fluid> masterFluidReference = HashBiMap.create();
static BiMap<String,String> defaultFluidName = HashBiMap.create();
public static final Fluid WATER = new Fluid("water") {
@Override
public String getLocalizedName() {
@ -60,39 +72,97 @@ public abstract class FluidRegistry
* Called by Forge to prepare the ID map for server -> client sync.
* Modders, DO NOT call this.
*/
public static void initFluidIDs(BiMap<Fluid, Integer> newfluidIDs)
public static void initFluidIDs(BiMap<Fluid, Integer> newfluidIDs, Set<String> defaultNames)
{
maxID = newfluidIDs.size();
fluidIDs.clear();
fluidIDs.putAll(newfluidIDs);
fluidNames.clear();
for (Entry<Fluid, Integer> e : fluidIDs.entrySet())
for (Entry<Fluid, Integer> e : fluidIDs.entrySet()) {
fluidNames.put(e.getValue(), e.getKey().getName());
}
loadFluidDefaults(defaultNames);
}
/**
* Register a new Fluid. If a fluid with the same name already exists, registration is denied.
* Called by forge to load default fluid IDs from the world or from server -> client for syncing
* DO NOT call this and expect useful behaviour.
*/
private static void loadFluidDefaults(Set<String> defaultNames)
{
// If there's an empty set of default names, use the defaults as defined locally
if (defaultNames.isEmpty()) {
defaultNames.addAll(defaultFluidName.values());
}
for (String defaultName : defaultNames)
{
Fluid fluid = masterFluidReference.get(defaultName);
if (fluid == null) {
String derivedName = defaultName.split(":",2)[1];
String localDefault = defaultFluidName.get(derivedName);
if (localDefault == null) {
FMLLog.getLogger().log(Level.ERROR, "The fluid {} (specified as {}) is missing from this instance - it will be removed", derivedName, defaultName);
continue;
}
fluid = masterFluidReference.get(localDefault);
FMLLog.getLogger().log(Level.ERROR, "The fluid {} specified as default is not present - it will be reverted to default {}", defaultName, localDefault);
}
FMLLog.getLogger().log(Level.DEBUG, "The fluid {} has been selected as the default fluid for {}", defaultName, fluid.getName());
fluids.put(fluid.getName(), fluid);
Integer id = fluidIDs.remove(fluid);
fluidIDs.put(fluid, id);
}
fluidBlocks = null;
}
/**
* Register a new Fluid. If a fluid with the same name already exists, registration the alternative fluid is tracked
* in case it is the default in another place
*
* @param fluid
* The fluid to register.
* @return True if the fluid was successfully registered; false if there is a name clash.
* @return True if the fluid was registered as the current default fluid, false if it was only registered as an alternative
*/
public static boolean registerFluid(Fluid fluid)
{
masterFluidReference.put(uniqueName(fluid), fluid);
if (fluids.containsKey(fluid.getName()))
{
FMLLog.bigWarning("Duplicate registration attempt for fluid %s (type %s) has occurred. This is not a problem itself, but subsequent failed FluidStacks result if this is not handled properly", fluid.getName(), fluid.getClass().getName());
return false;
}
fluids.put(fluid.getName(), fluid);
maxID++;
fluidIDs.put(fluid, maxID);
fluidNames.put(maxID, fluid.getName());
defaultFluidName.put(fluid.getName(), uniqueName(fluid));
MinecraftForge.EVENT_BUS.post(new FluidRegisterEvent(fluid.getName(), maxID));
return true;
}
private static String uniqueName(Fluid fluid)
{
ModContainer activeModContainer = Loader.instance().activeModContainer();
String activeModContainerName = activeModContainer == null ? "minecraft" : activeModContainer.getModId();
return activeModContainerName+":"+fluid.getName();
}
/**
* Is the supplied fluid the current default fluid for it's name
* @param fluid the fluid we're testing
* @return if the fluid is default
*/
public static boolean isFluidDefault(Fluid fluid)
{
return fluids.containsValue(fluid);
}
/**
* Does the supplied fluid have an entry for it's name (whether or not the fluid itself is default)
* @param fluid the fluid we're testing
* @return if the fluid's name has a registration entry
*/
public static boolean isFluidRegistered(Fluid fluid)
{
return fluids.containsKey(fluid.getName());
@ -207,4 +277,40 @@ public abstract class FluidRegistry
{
return maxID;
}
public static String getDefaultFluidName(Fluid key)
{
return masterFluidReference.inverse().get(key);
}
public static void loadFluidDefaults(NBTTagCompound tag)
{
Set<String> defaults = Sets.newHashSet();
if (tag.hasKey("DefaultFluidList",9))
{
FMLLog.getLogger().log(Level.DEBUG, "Loading persistent fluid defaults from world");
NBTTagList tl = tag.getTagList("DefaultFluidList", 8);
for (int i = 0; i < tl.tagCount(); i++)
{
defaults.add(tl.getStringTagAt(i));
}
}
else
{
FMLLog.getLogger().log(Level.DEBUG, "World is missing persistent fluid defaults - using local defaults");
}
loadFluidDefaults(defaults);
}
public static void writeDefaultFluidList(NBTTagCompound forgeData)
{
NBTTagList tagList = new NBTTagList();
for (Entry<String, Fluid> def : fluids.entrySet())
{
tagList.appendTag(new NBTTagString(getDefaultFluidName(def.getValue())));
}
forgeData.setTag("DefaultFluidList", tagList);
}
}

View File

@ -1,10 +1,6 @@
package net.minecraftforge.fluids;
import java.util.Locale;
import com.google.common.base.Strings;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;