From 955101d74b2562ed9485276d8ab053d965ddd0cb Mon Sep 17 00:00:00 2001 From: Robert Seifert Date: Fri, 17 May 2013 14:37:51 -0400 Subject: [PATCH] Added hydraulic Lib --- src/minecraft/dark/library/IDarkMod.java | 6 - .../library/access/GlobalAccessManager.java | 18 +- src/minecraft/dark/library/helpers/Time.java | 15 + .../dark/library/npc/IAdvancedNpc.java | 11 + .../dark/library/npc/prefab/EntityNpc.java | 37 +- .../dark/library/team/FactionInstance.java | 107 +++ src/minecraft/hydraulic/Credits | 1 + src/minecraft/hydraulic/INFO.java | 15 + src/minecraft/hydraulic/api/ColorCode.java | 65 ++ .../api/FluidRestrictionHandler.java | 65 ++ src/minecraft/hydraulic/api/IColorCoded.java | 14 + src/minecraft/hydraulic/api/IDrain.java | 44 ++ .../hydraulic/api/IHeatProducer.java | 16 + .../hydraulic/api/IPipeConnection.java | 18 + src/minecraft/hydraulic/api/IPsiReciever.java | 16 + src/minecraft/hydraulic/api/IReadOut.java | 17 + .../fluidnetwork/FluidPressurePack.java | 31 + .../fluidnetwork/HydraulicNetwork.java | 700 ++++++++++++++++++ .../fluidnetwork/HydraulicNetworkHelper.java | 42 ++ .../fluidnetwork/IFluidNetworkPart.java | 45 ++ .../hydraulic/fluidnetwork/INetworkPath.java | 31 + .../fluidnetwork/PathfinderCheckerPipes.java | 59 ++ .../hydraulic/helpers/FillDrainHelper.java | 55 ++ .../hydraulic/helpers/FluidHelper.java | 186 +++++ .../prefab/tile/TileEntityFluidDevice.java | 43 ++ .../prefab/tile/TileEntityFluidStorage.java | 149 ++++ 26 files changed, 1789 insertions(+), 17 deletions(-) delete mode 100644 src/minecraft/dark/library/IDarkMod.java create mode 100644 src/minecraft/dark/library/helpers/Time.java create mode 100644 src/minecraft/dark/library/npc/IAdvancedNpc.java create mode 100644 src/minecraft/dark/library/team/FactionInstance.java create mode 100644 src/minecraft/hydraulic/Credits create mode 100644 src/minecraft/hydraulic/INFO.java create mode 100644 src/minecraft/hydraulic/api/ColorCode.java create mode 100644 src/minecraft/hydraulic/api/FluidRestrictionHandler.java create mode 100644 src/minecraft/hydraulic/api/IColorCoded.java create mode 100644 src/minecraft/hydraulic/api/IDrain.java create mode 100644 src/minecraft/hydraulic/api/IHeatProducer.java create mode 100644 src/minecraft/hydraulic/api/IPipeConnection.java create mode 100644 src/minecraft/hydraulic/api/IPsiReciever.java create mode 100644 src/minecraft/hydraulic/api/IReadOut.java create mode 100644 src/minecraft/hydraulic/fluidnetwork/FluidPressurePack.java create mode 100644 src/minecraft/hydraulic/fluidnetwork/HydraulicNetwork.java create mode 100644 src/minecraft/hydraulic/fluidnetwork/HydraulicNetworkHelper.java create mode 100644 src/minecraft/hydraulic/fluidnetwork/IFluidNetworkPart.java create mode 100644 src/minecraft/hydraulic/fluidnetwork/INetworkPath.java create mode 100644 src/minecraft/hydraulic/fluidnetwork/PathfinderCheckerPipes.java create mode 100644 src/minecraft/hydraulic/helpers/FillDrainHelper.java create mode 100644 src/minecraft/hydraulic/helpers/FluidHelper.java create mode 100644 src/minecraft/hydraulic/prefab/tile/TileEntityFluidDevice.java create mode 100644 src/minecraft/hydraulic/prefab/tile/TileEntityFluidStorage.java diff --git a/src/minecraft/dark/library/IDarkMod.java b/src/minecraft/dark/library/IDarkMod.java deleted file mode 100644 index ee09537f..00000000 --- a/src/minecraft/dark/library/IDarkMod.java +++ /dev/null @@ -1,6 +0,0 @@ -package dark.library; - -public interface IDarkMod -{ - -} diff --git a/src/minecraft/dark/library/access/GlobalAccessManager.java b/src/minecraft/dark/library/access/GlobalAccessManager.java index ed590749..4bda0e4a 100644 --- a/src/minecraft/dark/library/access/GlobalAccessManager.java +++ b/src/minecraft/dark/library/access/GlobalAccessManager.java @@ -31,7 +31,7 @@ public class GlobalAccessManager * @param owner - the player's name to be used to create a new list * @return - UserAccess list */ - public List getOrCreateList(String name, String owner) + public static List getOrCreateList(String name, String owner) { if (name.toCharArray().length < 5 || owner.isEmpty() || name.startsWith("Default#")) { @@ -40,7 +40,7 @@ public class GlobalAccessManager List list = getList(name); if (list == null) { - list = this.createList(name, owner); + list = createList(name, owner); } return list; } @@ -48,7 +48,7 @@ public class GlobalAccessManager /** * gets all the access list by name the user can edit */ - public List getUsersLists(String username) + public static List getUsersLists(String username) { List lists = new ArrayList(); Iterator>> it = GlobalAccessManager.globalUserLists.entrySet().iterator(); @@ -77,7 +77,7 @@ public class GlobalAccessManager * @param owner * @return */ - public List createList(String name, String owner) + public static List createList(String name, String owner) { /*** Creates a new List if one doesn't exist ***/ List list = new ArrayList(); @@ -85,7 +85,7 @@ public class GlobalAccessManager globalUserLists.put(name, list); saveList(name, list); - this.needsSaving = true; + needsSaving = true; return list; } @@ -95,7 +95,7 @@ public class GlobalAccessManager * @param name - name of the list * @return - the list */ - public List getList(String name) + public static List getList(String name) { if (globalUserLists.containsKey(name)) { @@ -183,7 +183,7 @@ public class GlobalAccessManager * @param name - name given to the list for reference * @return - the list of user access levels to be used */ - private List loadList(String name) + private static List loadList(String name) { NBTTagCompound masterSave = getMasterSaveFile(); if (masterSave != null && masterSave.hasKey(name)) @@ -200,14 +200,14 @@ public class GlobalAccessManager * @param name - name to save the list as * @param list - list to be saved */ - private void saveList(String name, List list) + private static void saveList(String name, List list) { NBTTagCompound masterSave = getMasterSaveFile(); if (masterSave != null) { NBTTagCompound accessSave = masterSave.getCompoundTag(name); UserAccess.writeListToNBT(accessSave, list); - this.getMasterSaveFile().setCompoundTag(name, accessSave); + masterSave.setCompoundTag(name, accessSave); } } diff --git a/src/minecraft/dark/library/helpers/Time.java b/src/minecraft/dark/library/helpers/Time.java new file mode 100644 index 00000000..74f10b0b --- /dev/null +++ b/src/minecraft/dark/library/helpers/Time.java @@ -0,0 +1,15 @@ +package dark.library.helpers; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Time +{ + public static Pair getCurrentTimeStamp() + { + SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + String strDate = sdfDate.format(now); + return new Pair(strDate,now); + } +} diff --git a/src/minecraft/dark/library/npc/IAdvancedNpc.java b/src/minecraft/dark/library/npc/IAdvancedNpc.java new file mode 100644 index 00000000..a09b57ca --- /dev/null +++ b/src/minecraft/dark/library/npc/IAdvancedNpc.java @@ -0,0 +1,11 @@ +package dark.library.npc; + +import dark.library.team.FactionInstance; +import net.minecraft.entity.INpc; + +public interface IAdvancedNpc extends INpc +{ + public FactionInstance getFaction(); + + public String getName(); +} diff --git a/src/minecraft/dark/library/npc/prefab/EntityNpc.java b/src/minecraft/dark/library/npc/prefab/EntityNpc.java index 8d25a4c0..fe6db27d 100644 --- a/src/minecraft/dark/library/npc/prefab/EntityNpc.java +++ b/src/minecraft/dark/library/npc/prefab/EntityNpc.java @@ -1,11 +1,16 @@ package dark.library.npc.prefab; +import net.minecraft.entity.EntityCreature; import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.INpc; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; +import dark.library.npc.IAdvancedNpc; +import dark.library.team.FactionInstance; -public class EntityNpc extends EntityLiving implements INpc +public class EntityNpc extends EntityCreature implements IAdvancedNpc { + private FactionInstance faction; + private String humanName = ""; public EntityNpc(World par1World) { @@ -18,4 +23,32 @@ public class EntityNpc extends EntityLiving implements INpc return 20; } + @Override + public FactionInstance getFaction() + { + return this.faction; + } + + @Override + public String getName() + { + return humanName; + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbt) + { + super.writeEntityToNBT(nbt); + nbt.setString("humanName", this.humanName); + nbt.setTag("faction", faction.write()); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbt) + { + super.readEntityFromNBT(nbt); + + + } + } diff --git a/src/minecraft/dark/library/team/FactionInstance.java b/src/minecraft/dark/library/team/FactionInstance.java new file mode 100644 index 00000000..3a97c774 --- /dev/null +++ b/src/minecraft/dark/library/team/FactionInstance.java @@ -0,0 +1,107 @@ +package dark.library.team; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import net.minecraft.nbt.NBTTagCompound; +import dark.library.access.AccessLevel; +import dark.library.access.GlobalAccessManager; +import dark.library.access.UserAccess; +import dark.library.helpers.Pair; +import dark.library.helpers.Time; + +/** + * Class used to track and manage a player/NPC faction + * + * @author DarkGuardsman + */ +public class FactionInstance +{ + List userList; + String name; + String creator; + String date = "unkown"; + String prefix; + + public FactionInstance(String prefix, String name, String maker, Pair date) + { + if (this.name == null || this.name.isEmpty()) + { + this.name = "Faction" + date.getValue().getMonth() + date.getValue().getDay(); + } + else + { + this.name = name; + } + + if (maker == null || maker.isEmpty()) + { + this.creator = "World"; + } + else + { + this.creator = maker; + } + + if (prefix == null) + { + this.prefix = name.substring(0, 4); + } + else if (prefix.length() > 6) + { + this.prefix = prefix.substring(0, 6); + } + else + { + this.prefix = prefix; + } + + if (date == null) + { + date = Time.getCurrentTimeStamp(); + } + this.date = date.getKey(); + + userList = GlobalAccessManager.getOrCreateList(name, maker); + if (userList == null) + { + userList = new ArrayList(); + userList.add(new UserAccess(this.creator, AccessLevel.OWNER, true)); + } + } + + public String getCreationDate() + { + return this.date; + } + + /** + * The person who original created the faction + */ + public String getCreator() + { + return (creator != null && !creator.isEmpty()) ? this.creator : "World"; + } + + /** + * The name of the faction + */ + public String getName() + { + return (name != null && !name.isEmpty()) ? this.name : "FactionName"; + } + + public NBTTagCompound write() + { + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("name", this.getName()); + tag.setString("creator", this.creator); + return tag; + } + + public void read(NBTTagCompound tag) + { + + } +} diff --git a/src/minecraft/hydraulic/Credits b/src/minecraft/hydraulic/Credits new file mode 100644 index 00000000..75d1264e --- /dev/null +++ b/src/minecraft/hydraulic/Credits @@ -0,0 +1 @@ +Most of the workings of hydraulics is credited to universal electric and its creator Calclavia. hydraulics though is not a fully copy but a revised version of UE to function for Liquid Systems. \ No newline at end of file diff --git a/src/minecraft/hydraulic/INFO.java b/src/minecraft/hydraulic/INFO.java new file mode 100644 index 00000000..174b0e01 --- /dev/null +++ b/src/minecraft/hydraulic/INFO.java @@ -0,0 +1,15 @@ +package hydraulic; + +public class INFO +{ + /** + * I would place a txt file here but the reob would just ignore it + * + * Anyways if you use the hydraulics system to make your mod more compatible with fluid + * mechanics you only need the api file. However, if you wish to make your own pipes you need + * the core folder as well. As well you will need to register your mod threw the Hydraulics + * class to activate it. + * + * + */ +} diff --git a/src/minecraft/hydraulic/api/ColorCode.java b/src/minecraft/hydraulic/api/ColorCode.java new file mode 100644 index 00000000..54992315 --- /dev/null +++ b/src/minecraft/hydraulic/api/ColorCode.java @@ -0,0 +1,65 @@ +package hydraulic.api; + +import net.minecraftforge.liquids.LiquidStack; + +public enum ColorCode +{ + BLACK("Black"), RED("Red"), GREEN("Green"), BROWN("Brown"), BLUE("Blue"), PURPLE("Purple"), CYAN("Cyan"), SILVER("Silver"), GREY("Grey"), PINK("Pink"), LIME("Lime"), YELLOW("Yellow"), LIGHTBLUE("LightBlue"), WHITE("White"), ORANGE("Orange"), NONE(""); + + String name; + + private ColorCode(String name) + { + this.name = name; + } + + public String getName() + { + return this.name; + } + + /** + * gets a ColorCode from any of the following + * + * @param obj - Integer,String,LiquidData,ColorCode + * @return Color NONE if it can't find it + */ + public static ColorCode get(Object obj) + { + if (obj instanceof Integer && ((Integer) obj) < ColorCode.values().length) + { + return ColorCode.values()[((Integer) obj)]; + } + else if (obj instanceof ColorCode) + { + return (ColorCode) obj; + } + else if (obj instanceof String) + { + for (int i = 0; i < ColorCode.values().length; i++) + { + if (((String) obj).equalsIgnoreCase(ColorCode.get(i).getName())) + { + return ColorCode.get(i); + } + } + } + return NONE; + } + + /** + * checks to see if the liquidStack is valid for the given color + */ + public boolean isValidLiquid(LiquidStack stack) + { + if (stack == null) + { + return false; + } + if(!FluidRestrictionHandler.hasRestrictedStack(this.ordinal())) + { + return true; + } + return FluidRestrictionHandler.hasRestrictedStack(this.ordinal()) && FluidRestrictionHandler.getStackForColor(this).isLiquidEqual(stack); + } +} diff --git a/src/minecraft/hydraulic/api/FluidRestrictionHandler.java b/src/minecraft/hydraulic/api/FluidRestrictionHandler.java new file mode 100644 index 00000000..7b1b73ec --- /dev/null +++ b/src/minecraft/hydraulic/api/FluidRestrictionHandler.java @@ -0,0 +1,65 @@ +package hydraulic.api; + +import net.minecraftforge.event.ForgeSubscribe; +import net.minecraftforge.liquids.LiquidDictionary; +import net.minecraftforge.liquids.LiquidDictionary.LiquidRegisterEvent; +import net.minecraftforge.liquids.LiquidStack; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +public class FluidRestrictionHandler +{ + private static BiMap restrictedStacks = HashBiMap.create(); + + static + { + /* ADD DEFAULT LIQUIDS */ + restrictedStacks.put(ColorCode.BLUE, LiquidDictionary.getCanonicalLiquid("Water")); + restrictedStacks.put(ColorCode.RED, LiquidDictionary.getCanonicalLiquid("Lava")); + } + + @ForgeSubscribe + public void onLiquidRegistered(LiquidRegisterEvent event) + { + if (event.Name != null) + { + if (event.Name.equalsIgnoreCase("Fuel") && !restrictedStacks.containsKey(ColorCode.YELLOW)) + { + restrictedStacks.put(ColorCode.YELLOW, event.Liquid); + } + else if (event.Name.equalsIgnoreCase("Oil") && !restrictedStacks.containsKey(ColorCode.BLACK)) + { + restrictedStacks.put(ColorCode.BLACK, event.Liquid); + } + else if (event.Name.equalsIgnoreCase("Milk") && !restrictedStacks.containsKey(ColorCode.WHITE)) + { + restrictedStacks.put(ColorCode.WHITE, event.Liquid); + } + } + } + + /** + * Checks too see if a color has a restricted stack + */ + public static boolean hasRestrictedStack(int meta) + { + return restrictedStacks.containsKey(ColorCode.get(meta)); + } + public static boolean hasRestrictedStack(LiquidStack stack) + { + if(stack == null) + { + return false; + } + return restrictedStacks.inverse().containsKey(stack); + } + /** + * gets the liquid stack that is restricted to this color + * + */ + public static LiquidStack getStackForColor(ColorCode color) + { + return restrictedStacks.get(color); + } +} diff --git a/src/minecraft/hydraulic/api/IColorCoded.java b/src/minecraft/hydraulic/api/IColorCoded.java new file mode 100644 index 00000000..92ced5bc --- /dev/null +++ b/src/minecraft/hydraulic/api/IColorCoded.java @@ -0,0 +1,14 @@ +package hydraulic.api; + + +public interface IColorCoded +{ + /** + * Returns the ColorCode of the object + */ + public ColorCode getColor(); + /** + * Sets the ColorCode of the Object + */ + public void setColor(Object obj); +} diff --git a/src/minecraft/hydraulic/api/IDrain.java b/src/minecraft/hydraulic/api/IDrain.java new file mode 100644 index 00000000..4fb3852f --- /dev/null +++ b/src/minecraft/hydraulic/api/IDrain.java @@ -0,0 +1,44 @@ +package hydraulic.api; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.liquids.ITankContainer; +import net.minecraftforge.liquids.LiquidStack; + +/** + * Interface to make or use the TileEntityDrain. In real life a drain would do nothing but act as an + * input or output for a pipe system. In code in order to interact with the pump the drain actual + * has to do the filling/draining for the pump. The pump only need to find the drain and tell it to + * fill or drain an area. + * + * The use of ITankContainer is optional but is need for the drain to be added to a Fluid Network + */ +public interface IDrain extends ITankContainer +{ + /** + * In the drain you can use the ITankContainer.fill methods or use this to get the drain to + * place a liquid into the world + * + * @param stack - valid LiquidStack that has a Liquid Block for it + * @param doFill - actual do the action of filling or check if it can + * @return amount of liquid used + */ + public int fillArea(LiquidStack stack, boolean doFill); + + /** + * Requests that this drain give the pump this liquid. The pump will have to decide if it can + * accept, request, and maintain this demand + * + * @param pump - requesting pump + * @param stack - liquid this pump wants for this request + */ + public void requestLiquid(TileEntity pump, LiquidStack stack); + + /** + * Request that this drain no longer supply the pump with a volume. By default a request will be + * removed from the request map after being filled. However, this can be used too stop a request + * short if the pump becomes full before the request is filled + * + * @param tileEntity - requesting pump + */ + public void stopRequesting(TileEntity tileEntity); +} diff --git a/src/minecraft/hydraulic/api/IHeatProducer.java b/src/minecraft/hydraulic/api/IHeatProducer.java new file mode 100644 index 00000000..19eb6e30 --- /dev/null +++ b/src/minecraft/hydraulic/api/IHeatProducer.java @@ -0,0 +1,16 @@ +package hydraulic.api; + +import net.minecraftforge.common.ForgeDirection; + +public interface IHeatProducer +{ + /** + *Checks too see if this can produce heat + */ + public boolean getCanProduceHeat(ForgeDirection dir); + + /** + * Gets the amount of heat in joules this can output + */ + public double getHeatAmmount(ForgeDirection dir); +} diff --git a/src/minecraft/hydraulic/api/IPipeConnection.java b/src/minecraft/hydraulic/api/IPipeConnection.java new file mode 100644 index 00000000..9f98c072 --- /dev/null +++ b/src/minecraft/hydraulic/api/IPipeConnection.java @@ -0,0 +1,18 @@ +package hydraulic.api; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; + +public interface IPipeConnection +{ + /** + * This method should only be used by pipe like objects to find if they can connect to this + * object + * + * @param entity - the pipe connecting to this object as a TileEntity instance + * @param dir - side connecting too + * + * @return true if it can connect + */ + public boolean canPipeConnect(TileEntity entity, ForgeDirection dir); +} diff --git a/src/minecraft/hydraulic/api/IPsiReciever.java b/src/minecraft/hydraulic/api/IPsiReciever.java new file mode 100644 index 00000000..4ffd99b6 --- /dev/null +++ b/src/minecraft/hydraulic/api/IPsiReciever.java @@ -0,0 +1,16 @@ +package hydraulic.api; + + +/** + * A tileEntity that receives a pressure driven fluid. Suggested to use some of the class from + * net.minecraftforge.liquids too make your machine work with other fluid mods that don't use + * pressure + */ +public interface IPsiReciever extends IPipeConnection +{ + /** + * the load that this machine is handling, working, or moving + */ + public double getPressureLoad(); + +} diff --git a/src/minecraft/hydraulic/api/IReadOut.java b/src/minecraft/hydraulic/api/IReadOut.java new file mode 100644 index 00000000..441886be --- /dev/null +++ b/src/minecraft/hydraulic/api/IReadOut.java @@ -0,0 +1,17 @@ +package hydraulic.api; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.common.ForgeDirection; + +public interface IReadOut +{ + /** + * Grabs the message displayed to the user on right click of the machine with the pipe gauge + * + * @param user + * @param side - may not work correctly yet but should give you a side + * @return - a string to be displayed to the player for a reading. automatically adds ReadOut: + * to the beginning + */ + public String getMeterReading(EntityPlayer user, ForgeDirection side); +} diff --git a/src/minecraft/hydraulic/fluidnetwork/FluidPressurePack.java b/src/minecraft/hydraulic/fluidnetwork/FluidPressurePack.java new file mode 100644 index 00000000..786ca010 --- /dev/null +++ b/src/minecraft/hydraulic/fluidnetwork/FluidPressurePack.java @@ -0,0 +1,31 @@ +package hydraulic.fluidnetwork; + +import net.minecraftforge.liquids.LiquidStack; + +public class FluidPressurePack implements Cloneable +{ + public LiquidStack liquidStack; + public double pressure; + + public FluidPressurePack(LiquidStack liquidStack, double voltage) + { + this.liquidStack = liquidStack; + this.pressure = voltage; + } + + public FluidPressurePack() + { + this(new LiquidStack(0, 0, 0), 0); + } + + @Override + public FluidPressurePack clone() + { + return new FluidPressurePack(this.liquidStack, this.pressure); + } + + public boolean isEqual(FluidPressurePack electricityPack) + { + return this.liquidStack.isLiquidEqual(electricityPack.liquidStack) && this.pressure == electricityPack.pressure; + } +} diff --git a/src/minecraft/hydraulic/fluidnetwork/HydraulicNetwork.java b/src/minecraft/hydraulic/fluidnetwork/HydraulicNetwork.java new file mode 100644 index 00000000..73e78a07 --- /dev/null +++ b/src/minecraft/hydraulic/fluidnetwork/HydraulicNetwork.java @@ -0,0 +1,700 @@ +package hydraulic.fluidnetwork; + +import hydraulic.api.ColorCode; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.liquids.ILiquidTank; +import net.minecraftforge.liquids.ITankContainer; +import net.minecraftforge.liquids.LiquidContainerRegistry; +import net.minecraftforge.liquids.LiquidDictionary; +import net.minecraftforge.liquids.LiquidStack; +import net.minecraftforge.liquids.LiquidTank; +import universalelectricity.core.path.Pathfinder; +import universalelectricity.core.vector.Vector3; +import cpw.mods.fml.common.FMLLog; +import dark.library.helpers.ConnectionHelper; + +/** + * Side note: the network should act like this when done {@link http + * ://www.e4training.com/hydraulic_calculators/B1.htm} as well as stay compatible with the forge + * Liquids + * + * @author Rseifert + * + */ +public class HydraulicNetwork +{ + /* BLOCK THAT ACT AS FLUID CONVEYORS ** */ + public final List fluidParts = new ArrayList(); + /* MACHINES THAT USE THE FORGE LIQUID API TO RECEIVE LIQUID ** */ + public final List fluidTanks = new ArrayList(); + /* MACHINES THAT USE THE PRESSURE SYSTEM TO DO WORK ** */ + private final HashMap pressureProducers = new HashMap(); + private final HashMap pressureLoads = new HashMap(); + + public ColorCode color = ColorCode.NONE; + /* PRESSURE OF THE NETWORK AS A TOTAL. ZERO AS IN NO PRODUCTION */ + public double pressureProduced = 0; + /* PRESSURE OF THE NETWORK'S LOAD AS A TOTAL. ZERO AS IN NO LOAD */ + public double pressureLoad = 0; + /* IS IT PROCESSING AN ADD LIQUID EVENT */ + private boolean processingRequest = false; + /* COMBINED TEMP STORAGE FOR ALL PIPES IN THE NETWORK */ + private LiquidTank combinedStorage = new LiquidTank(LiquidContainerRegistry.BUCKET_VOLUME); + + public HydraulicNetwork(ColorCode color, IFluidNetworkPart... parts) + { + this.fluidParts.addAll(Arrays.asList(parts)); + this.color = color; + } + + /** + * sets this tileEntity to produce a pressure and flow rate in the network + */ + public void startProducingPressure(TileEntity tileEntity, FluidPressurePack fluidPack) + { + if (tileEntity != null && fluidPack.liquidStack != null) + { + if ((this.combinedStorage.getLiquid() == null || fluidPack.liquidStack.isLiquidEqual(this.combinedStorage.getLiquid())) && fluidPack.liquidStack.amount > 0) + { + this.pressureProducers.put(tileEntity, fluidPack); + } + } + } + + /** + * sets this tileEntity to produce a pressure and flow rate in the network + */ + public void startProducingPressure(TileEntity tileEntity, LiquidStack stack, double pressure) + { + this.startProducingPressure(tileEntity, new FluidPressurePack(stack, pressure)); + } + + /** + * is this tile entity producing a pressure + */ + public boolean isProducingPressure(TileEntity tileEntity) + { + return this.pressureProducers.containsKey(tileEntity); + } + + /** + * Sets this tile entity to stop producing pressure and flow in this network + */ + public void removeSource(TileEntity tileEntity) + { + this.pressureProducers.remove(tileEntity); + } + + /** + * Sets this tile entity to act as a load on the system + */ + public void addLoad(TileEntity tileEntity, FluidPressurePack fluidPack) + { + if (tileEntity != null && fluidPack.liquidStack != null && fluidPack.liquidStack.amount > 0) + { + this.pressureLoads.put(tileEntity, fluidPack); + } + } + + /** + * Sets this tile entity to act as a load on the system + */ + public void addLoad(TileEntity tileEntity, LiquidStack stack, double pressure) + { + this.addLoad(tileEntity, new FluidPressurePack(stack, pressure)); + } + + /** + * is this tileEntity a load in the network + */ + public boolean isLoad(TileEntity tileEntity) + { + return this.pressureLoads.containsKey(tileEntity); + } + + /** + * removes this tileEntity from being a load on the network + */ + public void removeLoad(TileEntity tileEntity) + { + this.pressureLoads.remove(tileEntity); + } + + /** + * Removes a tileEntity from any of the valid lists + */ + public void removeEntity(TileEntity ent) + { + if (fluidTanks.contains(ent)) + { + fluidTanks.remove(ent); + } + this.removeLoad(ent); + this.removeSource(ent); + } + + /** + * Adds a tileEntity to the list if its valid + */ + public void addEntity(ITankContainer ent) + { + if (ent == null) + { + return; + } + else if (ent instanceof IFluidNetworkPart) + { + this.addNetworkPart((IFluidNetworkPart) ent); + } + else if (!fluidTanks.contains(ent)) + { + fluidTanks.add(ent); + } + } + + public void addNetworkPart(IFluidNetworkPart newConductor) + { + this.cleanConductors(); + + if (newConductor.getColor() == this.color && !fluidParts.contains(newConductor)) + { + fluidParts.add(newConductor); + newConductor.setNetwork(this); + } + } + + /** + * Checks too see if the tileEntity is part of or connected too the network + */ + public boolean isConnected(TileEntity tileEntity) + { + if (this.fluidParts.contains(tileEntity)) + { + return true; + } + else if (this.fluidTanks.contains(tileEntity)) + { + return true; + } + else + { + return false; + } + } + + /** + * @param ignoreTiles The TileEntities to ignore during this calculation. Null will make it not + * ignore any. + * @return The electricity produced in this electricity network + */ + public double getPressureProduced(TileEntity... ignoreTiles) + { + // TODO pressure is not added as a sum but rather as a collective sum of the largest + // pressures. IF the pressure is to small it will be ignored and stop producing pressure. + int totalPressure = 0; + + Iterator it = this.pressureProducers.entrySet().iterator(); + + loop: + while (it.hasNext()) + { + Map.Entry pairs = (Map.Entry) it.next(); + + if (pairs != null) + { + TileEntity tileEntity = (TileEntity) pairs.getKey(); + + if (tileEntity == null) + { + it.remove(); + continue; + } + + if (tileEntity.isInvalid()) + { + it.remove(); + continue; + } + + if (tileEntity.worldObj.getBlockTileEntity(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord) != tileEntity) + { + it.remove(); + continue; + } + + if (ignoreTiles != null) + { + for (TileEntity ignoreTile : ignoreTiles) + { + if (tileEntity == ignoreTile) + { + continue loop; + } + } + } + + FluidPressurePack pack = (FluidPressurePack) pairs.getValue(); + + if (pairs.getKey() != null && pairs.getValue() != null && pack != null) + { + totalPressure += pack.pressure; + } + } + } + + return totalPressure; + } + + /** + * Adds FLuid to this network from one of the connected Pipes + * + * @param source - Were this liquid came from + * @param stack - LiquidStack to be sent + * @param doFill - actually fill the tank or just check numbers + * @return the amount of liquid consumed from the init stack + */ + public int addFluidToNetwork(TileEntity source, LiquidStack stack, boolean doFill) + { + return this.addFluidToNetwork(source, stack, doFill, false); + } + + /** + * Adds FLuid to this network from one of the connected Pipes + * + * @param source - Were this liquid came from + * @param stack - LiquidStack to be sent + * @param doFill - actually fill the tank or just check numbers + * @param allowStore - allows the network to store this liquid in the pipes + * @return the amount of liquid consumed from the init stack + */ + public int addFluidToNetwork(TileEntity source, LiquidStack stack, boolean doFill, boolean allowStore) + { + int used = 0; + LiquidStack prevCombined = this.combinedStorage.getLiquid(); + if (!this.processingRequest && stack != null && color.isValidLiquid(stack)) + { + if (this.combinedStorage.getLiquid() != null && !stack.isLiquidEqual(this.combinedStorage.getLiquid())) + { + // TODO cause mixing + } + if (stack.amount > this.getMaxFlow(stack)) + { + stack = new LiquidStack(stack.itemID, this.getMaxFlow(stack), stack.itemMeta); + } + + /* Main fill target to try to fill with the stack */ + ITankContainer primaryFill = null; + int volume = Integer.MAX_VALUE; + ForgeDirection fillDir = ForgeDirection.UNKNOWN; + + /* Secondary fill target if the main target is not found */ + ITankContainer secondayFill = null; + int mostFill = 0; + ForgeDirection otherFillDir = ForgeDirection.UNKNOWN; + + boolean found = false; + + /* FIND THE FILL TARGET FROM THE LIST OF FLUID RECIEVERS */ + for (ITankContainer tankContainer : fluidTanks) + { + if (tankContainer instanceof TileEntity && tankContainer != source && !(tankContainer instanceof IFluidNetworkPart)) + { + TileEntity[] connectedTiles = ConnectionHelper.getSurroundingTileEntities((TileEntity) tankContainer); + + for (int i = 0; i < 6; i++) + { + if (connectedTiles[i] instanceof IFluidNetworkPart && ((IFluidNetworkPart) connectedTiles[i]).getNetwork() == this) + { + ForgeDirection dir = ForgeDirection.getOrientation(i).getOpposite(); + ILiquidTank targetTank = tankContainer.getTank(dir, stack); + int fill = tankContainer.fill(dir, stack, false); + + /* USE GET TANK FROM SIDE METHOD FIRST */ + if (targetTank != null) + { + LiquidStack stackStored = targetTank.getLiquid(); + if (stackStored == null) + { + primaryFill = tankContainer; + found = true; + fillDir = dir; + break; + } + else if (stackStored.amount < targetTank.getCapacity() && stackStored.amount < volume) + { + primaryFill = tankContainer; + volume = stackStored.amount; + } + }/* USE FILL METHOD IF GET TANK == NULL */ + else if (fill > 0 && fill > mostFill) + { + secondayFill = tankContainer; + mostFill = fill; + otherFillDir = dir; + } + } + } + } + if (found) + { + break; + } + }// End of tank finder + boolean filledMain = false; + if (primaryFill != null) + { + used = primaryFill.fill(fillDir, stack, doFill); + //System.out.println("Primary Target " + used + doFill); + } + else if (secondayFill != null) + { + used = secondayFill.fill(fillDir, stack, doFill); + //System.out.println("Seconday Target " + used + doFill); + } + else if (allowStore && (this.combinedStorage.getLiquid() == null || this.combinedStorage.getLiquid().amount < this.combinedStorage.getCapacity())) + { + used = this.combinedStorage.fill(stack, doFill); + //System.out.println("Network Target filled for " + used + doFill); + filledMain = true; + } + /* IF THE COMBINED STORAGE OF THE PIPES HAS LIQUID MOVE IT FIRST */ + if (!filledMain && used > 0 && this.combinedStorage.getLiquid() != null && this.combinedStorage.getLiquid().amount > 0) + { + + LiquidStack drainStack = new LiquidStack(0, 0, 0); + if (this.combinedStorage.getLiquid().amount >= used) + { + drainStack = this.combinedStorage.drain(used, doFill); + used = 0; + } + else + { + int pUsed = used; + used = Math.min(used, Math.max(used - this.combinedStorage.getLiquid().amount, 0)); + drainStack = this.combinedStorage.drain(pUsed - used, doFill); + } + //System.out.println("Pulling " + (drainStack != null ? drainStack.amount : 0) + " from combined leaving " + (this.combinedStorage.getLiquid() != null ? this.combinedStorage.getLiquid().amount : 0)); + + } + if (prevCombined != null && this.combinedStorage.getLiquid() != null && prevCombined.amount != this.combinedStorage.getLiquid().amount) + { + this.moveAndSumVolume(false); + } + } + this.processingRequest = false; + return used; + } + + /** + * gets the flow rate of the network by getting the pipe with the lowest flow rate. + * + * @return units of liquid per tick, default 20B/s + */ + public int getMaxFlow(LiquidStack stack) + { + int flow = 1000; + for (IFluidNetworkPart conductor : this.fluidParts) + { + // TODO change the direction to actual look for connected only directions and pipes + // along + // the path to the target + int cFlow = conductor.getMaxFlowRate(stack, ForgeDirection.UNKNOWN); + if (cFlow < flow) + { + flow = cFlow; + } + } + return flow; + } + + public void cleanConductors() + { + for (int i = 0; i < fluidParts.size(); i++) + { + if (fluidParts.get(i) == null) + { + fluidParts.remove(i); + } + else if (((TileEntity) fluidParts.get(i)).isInvalid()) + { + fluidParts.remove(i); + } + } + } + + public void setNetwork() + { + this.cleanConductors(); + + for (IFluidNetworkPart conductor : this.fluidParts) + { + conductor.setNetwork(this); + } + } + + public void onPresureChange() + { + this.cleanConductors(); + + for (int i = 0; i < fluidParts.size(); i++) + { + // TODO change to actual check connected sides only && get true value from settings file + IFluidNetworkPart part = fluidParts.get(i); + if (part.getMaxPressure(ForgeDirection.UNKNOWN) < this.pressureProduced && part.onOverPressure(true)) + { + this.fluidParts.remove(part); + this.cleanConductors(); + } + + } + } + + public void cleanUpConductors() + { + Iterator it = this.fluidParts.iterator(); + int capacity = 0; + + while (it.hasNext()) + { + IFluidNetworkPart conductor = (IFluidNetworkPart) it.next(); + + if (conductor == null) + { + it.remove(); + } + else if (((TileEntity) conductor).isInvalid()) + { + it.remove(); + } + else if (conductor.getColor() != this.color) + { + it.remove(); + } + else + { + conductor.setNetwork(this); + capacity += LiquidContainerRegistry.BUCKET_VOLUME; + } + } + this.combinedStorage.setCapacity(capacity); + } + + /** + * This function is called to refresh all conductors in this network + */ + public void refreshConductors() + { + this.cleanUpConductors(); + + try + { + Iterator it = this.fluidParts.iterator(); + + while (it.hasNext()) + { + IFluidNetworkPart conductor = it.next(); + conductor.updateAdjacentConnections(); + } + } + catch (Exception e) + { + FMLLog.severe("Universal Electricity: Failed to refresh conductor."); + e.printStackTrace(); + } + } + + public List getFluidNetworkParts() + { + return this.fluidParts; + } + + public void mergeNetworks(HydraulicNetwork network) + { + if (network != null && network != this && network.color == this.color) + { + if (this.combinedStorage.getLiquid() != null && network.combinedStorage.getLiquid() != null && !this.combinedStorage.getLiquid().isLiquidEqual(network.combinedStorage.getLiquid())) + { + this.causingMixing(this.combinedStorage.getLiquid(), network.combinedStorage.getLiquid()); + } + else + { + this.moveAndSumVolume(false); + network.moveAndSumVolume(false); + LiquidStack stack = new LiquidStack(0, 0, 0); + if (this.combinedStorage.getLiquid() != null && network.combinedStorage.getLiquid() != null && this.combinedStorage.getLiquid().isLiquidEqual(network.combinedStorage.getLiquid())) + { + stack = this.combinedStorage.getLiquid(); + stack.amount += network.combinedStorage.getLiquid().amount; + } + else if (this.combinedStorage.getLiquid() == null && network.combinedStorage.getLiquid() != null) + { + stack = network.combinedStorage.getLiquid(); + } + else if (this.combinedStorage.getLiquid() != null && network.combinedStorage.getLiquid() == null) + { + stack = this.combinedStorage.getLiquid(); + } + HydraulicNetwork newNetwork = new HydraulicNetwork(this.color); + + newNetwork.getFluidNetworkParts().addAll(this.getFluidNetworkParts()); + newNetwork.getFluidNetworkParts().addAll(network.getFluidNetworkParts()); + + newNetwork.cleanUpConductors(); + newNetwork.moveAndSumVolume(true); + } + } + } + + public void causingMixing(LiquidStack stack, LiquidStack stack2) + { + // TODO cause mixing of liquids based on types and volume. Also apply damage to pipes/parts + // as needed + } + + public void splitNetwork(World world, IFluidNetworkPart splitPoint) + { + if (splitPoint instanceof TileEntity) + { + this.getFluidNetworkParts().remove(splitPoint); + this.moveAndSumVolume(false); + /** + * Loop through the connected blocks and attempt to see if there are connections between + * the two points elsewhere. + */ + TileEntity[] connectedBlocks = splitPoint.getAdjacentConnections(); + + for (int i = 0; i < connectedBlocks.length; i++) + { + TileEntity connectedBlockA = connectedBlocks[i]; + + if (connectedBlockA instanceof IFluidNetworkPart) + { + for (int pipeCount = 0; pipeCount < connectedBlocks.length; pipeCount++) + { + final TileEntity connectedBlockB = connectedBlocks[pipeCount]; + + if (connectedBlockA != connectedBlockB && connectedBlockB instanceof IFluidNetworkPart) + { + Pathfinder finder = new PathfinderCheckerPipes(world, (IFluidNetworkPart) connectedBlockB, splitPoint); + finder.init(new Vector3(connectedBlockA)); + + if (finder.results.size() > 0) + { + /* STILL CONNECTED SOMEWHERE ELSE */ + for (Vector3 node : finder.closedSet) + { + TileEntity entity = node.getTileEntity(world); + if (entity instanceof IFluidNetworkPart) + { + if (node != splitPoint) + { + ((IFluidNetworkPart) entity).setNetwork(this); + } + } + } + } + else + { + /* NO LONGER CONNECTED ELSE WHERE SO SPLIT AND REFRESH */ + HydraulicNetwork newNetwork = new HydraulicNetwork(this.color); + int parts = 0; + for (Vector3 node : finder.closedSet) + { + TileEntity entity = node.getTileEntity(world); + if (entity instanceof IFluidNetworkPart) + { + if (node != splitPoint) + { + newNetwork.getFluidNetworkParts().add((IFluidNetworkPart) entity); + parts++; + } + } + } + + newNetwork.cleanUpConductors(); + newNetwork.moveAndSumVolume(true); + } + } + } + } + } + } + } + + /** + * Moves the volume stored in the network to the parts or sums up the volume from the parts and + * loads it to the network. Assumes that all liquidStacks stored are equal + * + * @param load - loads the volume from the parts before leveling out the volumes + */ + public void moveAndSumVolume(boolean load) + { + int volume = 0; + int itemID = 0; + int itemMeta = 0; + if (load) + { + for (IFluidNetworkPart part : this.fluidParts) + { + + if (part.getTank() != null && part.getTank().getLiquid() != null) + { + if (itemID == 0) + { + itemID = part.getTank().getLiquid().itemID; + itemMeta = part.getTank().getLiquid().itemMeta; + } + volume += part.getTank().getLiquid().amount; + } + } + this.combinedStorage.setLiquid(new LiquidStack(itemID, volume, itemMeta)); + } + + if (this.combinedStorage.getLiquid() != null && this.fluidParts.size() > 0) + { + volume = this.combinedStorage.getLiquid().amount / this.fluidParts.size(); + itemID = this.combinedStorage.getLiquid().itemID; + itemMeta = this.combinedStorage.getLiquid().itemMeta; + + for (IFluidNetworkPart part : this.fluidParts) + { + part.setTankContent(null); + part.setTankContent(new LiquidStack(itemID, volume, itemMeta)); + } + } + } + + @Override + public String toString() + { + return "HydraulicNetwork[" + this.hashCode() + "|parts:" + this.fluidParts.size() + "]"; + } + + public String getStorageFluid() + { + if (!combinedStorage.containsValidLiquid()) + { + return "Zero"; + } + return String.format("%d/%d %S Stored", combinedStorage.getLiquid().amount / LiquidContainerRegistry.BUCKET_VOLUME, combinedStorage.getCapacity() / LiquidContainerRegistry.BUCKET_VOLUME, LiquidDictionary.findLiquidName(this.combinedStorage.getLiquid())); + } + + public ILiquidTank getTank() + { + if (this.combinedStorage == null) + { + this.combinedStorage = new LiquidTank(0); + } + return this.combinedStorage; + } +} diff --git a/src/minecraft/hydraulic/fluidnetwork/HydraulicNetworkHelper.java b/src/minecraft/hydraulic/fluidnetwork/HydraulicNetworkHelper.java new file mode 100644 index 00000000..2cc8e590 --- /dev/null +++ b/src/minecraft/hydraulic/fluidnetwork/HydraulicNetworkHelper.java @@ -0,0 +1,42 @@ +package hydraulic.fluidnetwork; + + +import hydraulic.api.IDrain; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.liquids.ITankContainer; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; + +public class HydraulicNetworkHelper +{ + + /** + * Invalidates a TileEntity + */ + public static void invalidate(TileEntity tileEntity) + { + for (int i = 0; i < 6; i++) + { + ForgeDirection direction = ForgeDirection.getOrientation(i); + TileEntity checkTile = VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction); + + if (checkTile instanceof IFluidNetworkPart) + { + HydraulicNetwork network = ((IFluidNetworkPart) checkTile).getNetwork(); + + if (network != null) + { + network.removeEntity(tileEntity); + for(ITankContainer tank : network.fluidTanks) + { + if(tank instanceof IDrain) + { + ((IDrain)tank).stopRequesting(tileEntity); + } + } + } + } + } + } +} diff --git a/src/minecraft/hydraulic/fluidnetwork/IFluidNetworkPart.java b/src/minecraft/hydraulic/fluidnetwork/IFluidNetworkPart.java new file mode 100644 index 00000000..d6622440 --- /dev/null +++ b/src/minecraft/hydraulic/fluidnetwork/IFluidNetworkPart.java @@ -0,0 +1,45 @@ +package hydraulic.fluidnetwork; + +import hydraulic.api.IColorCoded; +import hydraulic.api.IPipeConnection; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.liquids.ILiquidTank; +import net.minecraftforge.liquids.ITankContainer; +import net.minecraftforge.liquids.LiquidStack; + +/** + * A machine that acts as one with the liquid network using the networks pressure for some function + * that doesn't change the over all network pressure. So pipes, gauges, tubes, buffers, decor + * blocks. + */ +public interface IFluidNetworkPart extends IPipeConnection, IColorCoded, ITankContainer, INetworkPath +{ + /** + * gets the devices pressure from a given side for input + */ + public double getMaxPressure(ForgeDirection side); + + /** + * The max amount of liquid that can flow per request + */ + public int getMaxFlowRate(LiquidStack stack, ForgeDirection side); + + /** + * Called when the pressure on the machine reachs max + * + * @param damageAllowed - can this tileEntity cause grief damage + * @return true if the device over pressured and destroyed itself + */ + public boolean onOverPressure(Boolean damageAllowed); + + /** + * size of the pipes liquid storage ability + */ + public int getTankSize(); + + public ILiquidTank getTank(); + + public void setTankContent(LiquidStack stack); + + +} diff --git a/src/minecraft/hydraulic/fluidnetwork/INetworkPath.java b/src/minecraft/hydraulic/fluidnetwork/INetworkPath.java new file mode 100644 index 00000000..d63730c9 --- /dev/null +++ b/src/minecraft/hydraulic/fluidnetwork/INetworkPath.java @@ -0,0 +1,31 @@ +package hydraulic.fluidnetwork; + +import net.minecraft.tileentity.TileEntity; + +public interface INetworkPath +{ + + /** + * Gets a list of all the connected TileEntities that this conductor is connected to. The + * array's length should be always the 6 adjacent wires. + * + * @return + */ + public TileEntity[] getAdjacentConnections(); + + /** + * Instantly refreshes all connected blocks around the conductor, recalculating the connected + * blocks. + */ + public void updateAdjacentConnections(); + + /** + * The Fluid network that this machine is part of + */ + public HydraulicNetwork getNetwork(); + + /** + * sets the machines network + */ + public void setNetwork(HydraulicNetwork network); +} diff --git a/src/minecraft/hydraulic/fluidnetwork/PathfinderCheckerPipes.java b/src/minecraft/hydraulic/fluidnetwork/PathfinderCheckerPipes.java new file mode 100644 index 00000000..b03b0dce --- /dev/null +++ b/src/minecraft/hydraulic/fluidnetwork/PathfinderCheckerPipes.java @@ -0,0 +1,59 @@ +package hydraulic.fluidnetwork; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.path.IPathCallBack; +import universalelectricity.core.path.Pathfinder; +import universalelectricity.core.vector.Vector3; + +/** + * Check if a conductor connects with another. + */ +public class PathfinderCheckerPipes extends Pathfinder +{ + public PathfinderCheckerPipes(final World world, final IFluidNetworkPart targetConnector, final IFluidNetworkPart... ignoreConnector) + { + super(new IPathCallBack() + { + @Override + public Set getConnectedNodes(Pathfinder finder, Vector3 currentNode) + { + Set neighbors = new HashSet(); + + for (int i = 0; i < 6; i++) + { + ForgeDirection direction = ForgeDirection.getOrientation(i); + Vector3 position = currentNode.clone().modifyPositionFromSide(direction); + TileEntity connectedBlock = position.getTileEntity(world); + + if (connectedBlock instanceof IFluidNetworkPart && !Arrays.asList(ignoreConnector).contains(connectedBlock)) + { + if (((IFluidNetworkPart) connectedBlock).canPipeConnect(connectedBlock, direction.getOpposite())) + { + neighbors.add(position); + } + } + } + + return neighbors; + } + + @Override + public boolean onSearch(Pathfinder finder, Vector3 node) + { + if (node.getTileEntity(world) == targetConnector) + { + finder.results.add(node); + return true; + } + + return false; + } + }); + } +} diff --git a/src/minecraft/hydraulic/helpers/FillDrainHelper.java b/src/minecraft/hydraulic/helpers/FillDrainHelper.java new file mode 100644 index 00000000..2c8c1936 --- /dev/null +++ b/src/minecraft/hydraulic/helpers/FillDrainHelper.java @@ -0,0 +1,55 @@ +package hydraulic.helpers; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.liquids.ITankContainer; +import net.minecraftforge.liquids.LiquidStack; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; + +/** + * Used to help with draining and filling of a tank + * + * @author DarkGuardsman + */ +public class FillDrainHelper +{ + /** + * Fills all ITankContainers around the point + * + * @return amount filled into the tank, use this to drain the source of the stack + */ + public static int fillArround(World world, Vector3 center, LiquidStack stack) + { + if (stack == null || stack.amount <= 0 || center.y < 6 || center.y > 255) + { + return 0; + } + int fill = 0; + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + fill += FillDrainHelper.fillDirection(world, center, stack, direction); + } + return fill; + } + + /** + * Fills a ITankContainer in one direction from a point in the world + * + * @return amount filled into the tank, use this to drain the source of the stack + */ + public static int fillDirection(World world, Vector3 center, LiquidStack stack, ForgeDirection direction) + { + if (stack == null || stack.amount <= 0 || center.y < 6 || center.y > 255) + { + return 0; + } + TileEntity entity = VectorHelper.getTileEntityFromSide(world, center, direction); + if (entity instanceof ITankContainer && ((ITankContainer) entity).fill(direction.getOpposite(), stack, false) > 0) + { + return ((ITankContainer) entity).fill(direction.getOpposite(), stack, true); + } + return 0; + } +} diff --git a/src/minecraft/hydraulic/helpers/FluidHelper.java b/src/minecraft/hydraulic/helpers/FluidHelper.java new file mode 100644 index 00000000..5fa1a8bf --- /dev/null +++ b/src/minecraft/hydraulic/helpers/FluidHelper.java @@ -0,0 +1,186 @@ +package hydraulic.helpers; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.liquids.ILiquid; +import net.minecraftforge.liquids.LiquidContainerRegistry; +import net.minecraftforge.liquids.LiquidDictionary; +import net.minecraftforge.liquids.LiquidStack; +import universalelectricity.core.vector.Vector3; + +public class FluidHelper +{ + /** + * The default built in flow rate of the liquid threw the pipes. Will correct this later to use + * a visc value instead of flow value so that the size of the pipe can play a factor in flow + */ + public static int getDefaultFlowRate(LiquidStack stack) + { + if (stack != null) + { + String stackName = LiquidDictionary.findLiquidName(stack); + if (stackName.equalsIgnoreCase("UraniumHexafluoride")) + { + return 1000; + } + else if (stackName.equalsIgnoreCase("steam")) + { + return 1000; + } + else if (stackName.equalsIgnoreCase("methane")) + { + return 1000; + } + else if (stackName.equalsIgnoreCase("lava")) + { + return 250; + } + } + return 500; + } + + /** + * Creates a new LiquidStack using the sample stack + * + * @param stack - liquidLiquid being used to create the stack + * @param vol - amount or volume of the stack + * @return a new @LiquidStack + */ + public static LiquidStack getStack(LiquidStack stack, int vol) + { + if (stack == null) + { + return null; + } + return new LiquidStack(stack.itemID, vol, stack.itemMeta); + } + + /** + * Consumes one item of a the ItemStack + */ + public static ItemStack consumeItem(ItemStack stack) + { + if (stack.stackSize == 1) + { + if (stack.getItem().hasContainerItem()) + { + return stack.getItem().getContainerItemStack(stack); + } + else + { + return null; + } + } + else + { + stack.splitStack(1); + return stack; + } + } + + /** + * gets the blockID/ItemID of the Still liquid + * + * @param id - blockID + * @return will return -1 if its not a valid liquid Block + */ + public static int getLiquidId(int id) + { + if (id == Block.waterStill.blockID || id == Block.waterMoving.blockID) + { + return Block.waterStill.blockID; + } + else if (id == Block.lavaStill.blockID || id == Block.lavaMoving.blockID) + { + return Block.lavaStill.blockID; + } + else if (Block.blocksList[id] instanceof ILiquid) + { + return ((ILiquid) Block.blocksList[id]).stillLiquidId(); + } + else + { + return -1; + } + } + + /** + * gets the liquidStack of the block + * + * @param id - block's ID + */ + public static LiquidStack getLiquidFromBlockId(int id) + { + if (id == Block.waterStill.blockID || id == Block.waterMoving.blockID) + { + return new LiquidStack(Block.waterStill.blockID, LiquidContainerRegistry.BUCKET_VOLUME, 0); + } + else if (id == Block.lavaStill.blockID || id == Block.lavaMoving.blockID) + { + return new LiquidStack(Block.lavaStill.blockID, LiquidContainerRegistry.BUCKET_VOLUME, 0); + } + else if (Block.blocksList[id] instanceof ILiquid) + { + ILiquid liquid = (ILiquid) Block.blocksList[id]; + if (liquid.isMetaSensitive()) + { + return new LiquidStack(liquid.stillLiquidId(), LiquidContainerRegistry.BUCKET_VOLUME, liquid.stillLiquidMeta()); + } + else + { + return new LiquidStack(liquid.stillLiquidId(), LiquidContainerRegistry.BUCKET_VOLUME, 0); + } + } + return null; + } + + /** + * Is the location a liquid source block + */ + public static boolean isSourceBlock(World world, Vector3 vec) + { + LiquidStack liquid = FluidHelper.getLiquidFromBlockId(vec.getBlockID(world)); + if ((liquid != null && vec.getBlockMetadata(world) == 0)) + { + return true; + } + return false; + } + + /** + * Gets the number of source liquids blocks around the locaiton + */ + public static int getConnectedSources(World world, Vector3 vec) + { + int sources = 0; + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + Vector3 pos = vec.clone().modifyPositionFromSide(direction); + if (isSourceBlock(world, pos)) + { + sources++; + } + } + return sources; + } + + /** + * Gets the number of liquid fillable blocks around the location + */ + public static int getConnectedFillables(World world, Vector3 vec) + { + int sources = 0; + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + Vector3 pos = vec.clone().modifyPositionFromSide(direction); + LiquidStack liquid = FluidHelper.getLiquidFromBlockId(pos.getBlockID(world)); + if ((liquid != null || pos.getBlockID(world) == 0) && getConnectedSources(world, pos) > 0) + { + sources++; + } + } + return sources; + } +} diff --git a/src/minecraft/hydraulic/prefab/tile/TileEntityFluidDevice.java b/src/minecraft/hydraulic/prefab/tile/TileEntityFluidDevice.java new file mode 100644 index 00000000..a71cec02 --- /dev/null +++ b/src/minecraft/hydraulic/prefab/tile/TileEntityFluidDevice.java @@ -0,0 +1,43 @@ +package hydraulic.prefab.tile; + +import hydraulic.api.IPipeConnection; +import hydraulic.api.IReadOut; +import hydraulic.fluidnetwork.HydraulicNetworkHelper; + +import java.util.Random; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.liquids.ITankContainer; +import net.minecraftforge.liquids.LiquidStack; +import universalelectricity.prefab.tile.TileEntityAdvanced; + +public abstract class TileEntityFluidDevice extends TileEntityAdvanced implements IReadOut, IPipeConnection +{ + public Random random = new Random(); + + @Override + public void invalidate() + { + super.invalidate(); + HydraulicNetworkHelper.invalidate(this); + } + + /** + * Fills an ITankContainer in the direction + * + * @param stack - LiquidStack that will be inputed in the tile + * @param side - direction to fill in + * @return the ammount filled + */ + public int fillSide(LiquidStack stack, ForgeDirection side, boolean doFill) + { + TileEntity tileEntity = worldObj.getBlockTileEntity(xCoord + side.offsetX, yCoord + side.offsetY, zCoord + side.offsetZ); + + if (stack != null && stack.amount > 0 && tileEntity instanceof ITankContainer) + { + return ((ITankContainer) tileEntity).fill(side.getOpposite(), stack, doFill); + } + return 0; + } +} diff --git a/src/minecraft/hydraulic/prefab/tile/TileEntityFluidStorage.java b/src/minecraft/hydraulic/prefab/tile/TileEntityFluidStorage.java new file mode 100644 index 00000000..da2d1df6 --- /dev/null +++ b/src/minecraft/hydraulic/prefab/tile/TileEntityFluidStorage.java @@ -0,0 +1,149 @@ +package hydraulic.prefab.tile; + +import hydraulic.api.IColorCoded; +import hydraulic.helpers.FluidHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.liquids.ILiquidTank; +import net.minecraftforge.liquids.ITankContainer; +import net.minecraftforge.liquids.LiquidContainerRegistry; +import net.minecraftforge.liquids.LiquidDictionary; +import net.minecraftforge.liquids.LiquidStack; +import net.minecraftforge.liquids.LiquidTank; + +public abstract class TileEntityFluidStorage extends TileEntityFluidDevice implements ITankContainer, IColorCoded +{ + /* INTERNAL TANK */ + public LiquidTank tank = new LiquidTank(this.getTankSize()); + + /** + * gets the max storage limit of the tank + */ + public abstract int getTankSize(); + + @Override + public String getMeterReading(EntityPlayer user, ForgeDirection side) + { + if (this.tank.getLiquid() == null) + { + return "Empty"; + } + return String.format("%d/%d %S Stored", tank.getLiquid().amount / LiquidContainerRegistry.BUCKET_VOLUME, tank.getCapacity() / LiquidContainerRegistry.BUCKET_VOLUME, LiquidDictionary.findLiquidName(tank.getLiquid())); + } + + @Override + public boolean canPipeConnect(TileEntity entity, ForgeDirection dir) + { + return true; + } + + @Override + public int fill(ForgeDirection from, LiquidStack resource, boolean doFill) + { + return this.fill(0, resource, doFill); + } + + @Override + public int fill(int tankIndex, LiquidStack resource, boolean doFill) + { + if (resource == null || tankIndex != 0) + { + return 0; + } + else if (!getColor().isValidLiquid(resource)) + { + return 0; + } + else if (this.tank.getLiquid() != null && !resource.isLiquidEqual(this.tank.getLiquid())) + { + return 0; + } + return this.tank.fill(resource, doFill); + } + + @Override + public LiquidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) + { + return this.drain(0, maxDrain, doDrain); + } + + @Override + public LiquidStack drain(int tankIndex, int maxDrain, boolean doDrain) + { + if (tankIndex != 0 || this.tank.getLiquid() == null) + { + return null; + } + LiquidStack stack = this.tank.getLiquid(); + if (maxDrain < stack.amount) + { + stack = FluidHelper.getStack(stack, maxDrain); + } + return this.tank.drain(maxDrain, doDrain); + } + + @Override + public ILiquidTank[] getTanks(ForgeDirection dir) + { + return new ILiquidTank[] { this.tank }; + } + + @Override + public ILiquidTank getTank(ForgeDirection dir, LiquidStack type) + { + if (type == null) + { + return null; + } + if (type.isLiquidEqual(this.tank.getLiquid())) + { + return this.tank; + } + return null; + } + + @Override + public void readFromNBT(NBTTagCompound nbt) + { + super.readFromNBT(nbt); + + LiquidStack liquid = LiquidStack.loadLiquidStackFromNBT(nbt.getCompoundTag("stored")); + if (liquid != null) + { + tank.setLiquid(liquid); + } + } + + @Override + public void writeToNBT(NBTTagCompound nbt) + { + super.writeToNBT(nbt); + if (this.tank.containsValidLiquid()) + { + nbt.setTag("stored", this.tank.getLiquid().writeToNBT(new NBTTagCompound())); + } + } + + /** + * Is the internal tank full + */ + public boolean isFull() + { + if (this.tank.getLiquid() == null || this.tank.getLiquid().amount < this.tank.getCapacity()) + { + return false; + } + return true; + } + + /** + * gets the liquidStack stored in the internal tank + */ + public LiquidStack getStoredLiquid() + { + return this.tank.getLiquid(); + } + +}