diff --git a/src/com/dark/ModObjectRegistry.java b/src/com/dark/CoreRegistry.java similarity index 96% rename from src/com/dark/ModObjectRegistry.java rename to src/com/dark/CoreRegistry.java index da8e42dc4..ed97d736b 100644 --- a/src/com/dark/ModObjectRegistry.java +++ b/src/com/dark/CoreRegistry.java @@ -25,7 +25,7 @@ import cpw.mods.fml.common.registry.GameRegistry; /** Handler to make registering all parts of a mod's objects that are loaded into the game by forge * * @author DarkGuardsman */ -public class ModObjectRegistry +public class CoreRegistry { public static HashMap registredBlocks = new HashMap(); public static HashMap registredItems = new HashMap(); @@ -37,12 +37,12 @@ public class ModObjectRegistry public static Block createNewBlock(String name, String modID, Class blockClass) { - return ModObjectRegistry.createNewBlock(name, modID, blockClass, true); + return CoreRegistry.createNewBlock(name, modID, blockClass, true); } public static Block createNewBlock(String name, String modID, Class blockClass, boolean canDisable) { - return ModObjectRegistry.createNewBlock(name, modID, blockClass, null, canDisable); + return CoreRegistry.createNewBlock(name, modID, blockClass, null, canDisable); } public static Block createNewBlock(String name, String modID, Class blockClass, Class itemClass) @@ -72,7 +72,7 @@ public class ModObjectRegistry { registredBlocks.put(block, name); proxy.registerBlock(block, itemClass, name, modID); - ModObjectRegistry.finishCreation(block); + CoreRegistry.finishCreation(block); } } return block; diff --git a/src/com/dark/DarkCore.java b/src/com/dark/DarkCore.java index be7e9df38..bb6477d06 100644 --- a/src/com/dark/DarkCore.java +++ b/src/com/dark/DarkCore.java @@ -2,16 +2,30 @@ package com.dark; import net.minecraft.block.Block; import net.minecraft.item.Item; +import net.minecraftforge.common.MinecraftForge; +import universalelectricity.compatibility.Compatibility; +import universalelectricity.core.UniversalElectricity; + +import com.dark.fluid.FluidHelper; +import com.dark.helpers.PlayerKeyHandler; +import com.dark.prefab.tile.network.NetworkUpdateHandler; +import com.dark.save.SaveManager; + +import cpw.mods.fml.common.registry.TickRegistry; +import cpw.mods.fml.relauncher.Side; public class DarkCore { private static DarkCore instance; + private boolean pre, load, post; + public static final String TEXTURE_DIRECTORY = "textures/"; public static final String BLOCK_DIRECTORY = TEXTURE_DIRECTORY + "blocks/"; public static final String ITEM_DIRECTORY = TEXTURE_DIRECTORY + "items/"; public static final String MODEL_DIRECTORY = TEXTURE_DIRECTORY + "models/"; public static final String GUI_DIRECTORY = TEXTURE_DIRECTORY + "gui/"; + public static final String CHANNEL = "DARKCORE"; /* START IDS */ public static int BLOCK_ID_PRE = 3100; @@ -26,6 +40,39 @@ public class DarkCore return instance; } + public void preLoad() + { + if (!pre) + { + MinecraftForge.EVENT_BUS.register(new FluidHelper()); + MinecraftForge.EVENT_BUS.register(SaveManager.instance()); + TickRegistry.registerTickHandler(NetworkUpdateHandler.instance(), Side.SERVER); + TickRegistry.registerScheduledTickHandler(new PlayerKeyHandler(), Side.CLIENT); + UniversalElectricity.initiate(); + Compatibility.initiate(); + pre = true; + } + } + + public void Load() + { + if (!load) + { + ExternalModHandler.init(); + CoreRegistry.masterBlockConfig.load(); + load = true; + } + } + + public void postLoad() + { + if (!post) + { + CoreRegistry.masterBlockConfig.save(); + post = true; + } + } + /** Gets the next unused ID in the block list. Does not prevent config file issues after the file * has been made */ public static int getNextID() @@ -63,4 +110,5 @@ public class DarkCore ITEM_ID_PREFIX = id + 1; return id; } + } diff --git a/src/com/dark/IndustryCreativeTab.java b/src/com/dark/IndustryCreativeTab.java new file mode 100644 index 000000000..271ee1ce3 --- /dev/null +++ b/src/com/dark/IndustryCreativeTab.java @@ -0,0 +1,68 @@ +package com.dark; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public class IndustryCreativeTab extends CreativeTabs +{ + public ItemStack itemStack = new ItemStack(Item.ingotIron, 1, 0); + + private static IndustryCreativeTab tabAutomation = new IndustryCreativeTab("Automation"); + private static IndustryCreativeTab tabIndustrial = new IndustryCreativeTab("Industrial"); + private static IndustryCreativeTab tabHydrualic = new IndustryCreativeTab("Hydraulic"); + private static IndustryCreativeTab tabMining = new IndustryCreativeTab("Mining"); + + public IndustryCreativeTab(String label) + { + super(label); + } + + @Override + public ItemStack getIconItemStack() + { + return this.itemStack; + } + + public void setIconItemStack(ItemStack stack) + { + this.itemStack = stack; + } + + public static IndustryCreativeTab tabAutomation() + { + if (tabAutomation == null) + { + tabAutomation = new IndustryCreativeTab("Automation"); + } + return tabAutomation; + } + + public static IndustryCreativeTab tabIndustrial() + { + if (tabIndustrial == null) + { + tabIndustrial = new IndustryCreativeTab("Industrial"); + } + return tabIndustrial; + } + + public static IndustryCreativeTab tabHydraulic() + { + if (tabHydrualic == null) + { + tabHydrualic = new IndustryCreativeTab("Hydraulic"); + } + return tabHydrualic; + } + + public static IndustryCreativeTab tabMining() + { + if (tabMining == null) + { + tabMining = new IndustryCreativeTab("Mining"); + } + return tabMining; + } + +} diff --git a/src/com/dark/fluid/EnumFluid.java b/src/com/dark/fluid/EnumFluid.java new file mode 100644 index 000000000..b66078e8d --- /dev/null +++ b/src/com/dark/fluid/EnumFluid.java @@ -0,0 +1,21 @@ +package com.dark.fluid; + +import net.minecraftforge.fluids.Fluid; + +/** Some common Fluid that other mods use + * + * @author DarkGuardsman */ +public enum EnumFluid +{ + FUEL(new Fluid("fuel").setUnlocalizedName("fluid.fuel.name")), + OIL(new Fluid("oil").setUnlocalizedName("fluid.oil.name").setDensity(1500).setViscosity(4700)), + BIOFUEL(new Fluid("biofuel").setUnlocalizedName("fluid.biofuel.name")), + WASTE(new Fluid("waste").setUnlocalizedName("fluid.waste.name").setDensity(1300).setViscosity(1800)); + + public final Fluid fluid; + + private EnumFluid(Fluid fluid) + { + this.fluid = fluid; + } +} diff --git a/src/com/dark/fluid/EnumGas.java b/src/com/dark/fluid/EnumGas.java new file mode 100644 index 000000000..13811537e --- /dev/null +++ b/src/com/dark/fluid/EnumGas.java @@ -0,0 +1,76 @@ +package com.dark.fluid; + +import com.builtbroken.common.science.ChemElement; +import com.builtbroken.common.science.ChemicalCompound; + +/** Enum of gases used to create all the gas fluids + * + * @author DarkGuardsman */ +public enum EnumGas +{ + CARBONDIOXIDE("Carbon DiOxide", false), + OXYGEN(ChemElement.Oxygen, 2f, true), + BUTANE(ChemicalCompound.BUTANE, true), + METHANE(ChemicalCompound.METHANE, true), + NATURAL_GAS("Natural Gas", false), + PROPANE("Propane", false); + + /** Name used when creating this as a fluid */ + public final String fluidName; + /** Name used to display to the players */ + public final String name; + /** Object data reference that was used to create this gas, can be a ChemicalCompound, Element, + * or Fluid */ + public final Object data; + public boolean enabled = false; + /** Only used for elements since when used as a gas they sometimes bind together */ + private float molePerGasMolecule = 1.0f; + /** Local instance of the gas used when the getGas method is called */ + private Gas gas; + + private EnumGas(String name, boolean enabled) + { + this.fluidName = name.replace(" ", "").toLowerCase(); + this.name = name; + data = null; + this.enabled = enabled; + } + + private EnumGas(ChemicalCompound compound, boolean enabled) + { + this.fluidName = "gas:" + compound.compoundName.replace(" ", "").toLowerCase(); + this.name = compound.compoundName; + data = compound; + this.enabled = enabled; + } + + private EnumGas(ChemElement element, float molesPerGasMolecule, boolean enabled) + { + this.fluidName = "gas:" + element.elementName.replace(" ", "").toLowerCase(); + this.name = element.elementName; + data = element; + this.enabled = enabled; + this.molePerGasMolecule = molesPerGasMolecule; + } + + public Gas getGas() + { + if (gas == null) + { + gas = new Gas(fluidName); + if (data instanceof ChemElement) + { + gas.setDensity((int) ((ChemElement) data).density * 1000); + } + else if (data instanceof ChemicalCompound) + { + gas.setDensity((int) ((ChemicalCompound) data).density * 1000); + } + else + { + gas.setDensity(-1000); + } + } + return gas; + } +} diff --git a/src/com/dark/fluid/FilteredTank.java b/src/com/dark/fluid/FilteredTank.java new file mode 100644 index 000000000..3a93fa093 --- /dev/null +++ b/src/com/dark/fluid/FilteredTank.java @@ -0,0 +1,58 @@ +package com.dark.fluid; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; + +/** Tank that has a filter on the fluid ids it will accept + * + * @author DarkGuardsman */ +public class FilteredTank extends FluidTank +{ + private List fluidIds = new ArrayList(); + boolean gas = true; + boolean liquid = true; + + public FilteredTank(int capacity, int... fluidIds) + { + this(capacity, true, true, fluidIds); + } + + public FilteredTank(int capacity, boolean gas, boolean liquid, int... fluidIds) + { + super(capacity); + this.gas = gas; + this.liquid = liquid; + for (int id : fluidIds) + { + this.fluidIds.add(id); + } + } + + public FilteredTank(FluidStack stack, int capacity) + { + super(stack, capacity); + } + + public FilteredTank(Fluid fluid, int amount, int capacity) + { + super(fluid, amount, capacity); + } + + @Override + public int fill(FluidStack resource, boolean doFill) + { + if (resource != null && resource.getFluid() != null && (!gas || gas && resource.getFluid().isGaseous()) && (!liquid || liquid && !resource.getFluid().isGaseous())) + { + if (fluidIds.contains(resource.fluidID)) + { + return super.fill(resource, doFill); + } + } + return 0; + } + +} diff --git a/src/com/dark/fluid/FluidHelper.java b/src/com/dark/fluid/FluidHelper.java new file mode 100644 index 000000000..8286a7a67 --- /dev/null +++ b/src/com/dark/fluid/FluidHelper.java @@ -0,0 +1,432 @@ +package com.dark.fluid; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockFluid; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidBlock; +import net.minecraftforge.fluids.IFluidHandler; +import universalelectricity.core.vector.Vector3; + +import com.builtbroken.common.Pair; +import com.dark.helpers.AutoCraftingManager; + +public class FluidHelper +{ + public static List> replacableBlockMeta = new ArrayList>(); + public static List replacableBlocks = new ArrayList(); + public static List nonBlockDropList = new ArrayList(); + + static + { + + /* Adds default fluid replaceable blocks */ + replacableBlocks.add(Block.crops); + replacableBlocks.add(Block.deadBush); + nonBlockDropList.add(Block.deadBush); + //TODO have waterlily raise and lower when automaticly filling or draining a block rather than remove it + replacableBlocks.add(Block.waterlily); + replacableBlocks.add(Block.mushroomRed); + replacableBlocks.add(Block.mushroomBrown); + replacableBlocks.add(Block.netherStalk); + replacableBlocks.add(Block.sapling); + replacableBlocks.add(Block.melonStem); + nonBlockDropList.add(Block.melonStem); + replacableBlocks.add(Block.pumpkinStem); + nonBlockDropList.add(Block.pumpkinStem); + replacableBlocks.add(Block.tallGrass); + replacableBlocks.add(Block.torchWood); + } + + /** Gets the block's fluid if it has one + * + * @param world - world we are working in + * @param vector - 3D location in world + * @return @Fluid that the block is */ + public static Fluid getLiquidFromBlock(World world, Vector3 vector) + { + return FluidHelper.getFluidFromBlockID(vector.getBlockID(world)); + } + + /** Gets a fluid from blockID */ + public static Fluid getFluidFromBlockID(int id) + { + if (Block.blocksList[id] instanceof IFluidBlock) + { + return ((IFluidBlock) Block.blocksList[id]).getFluid(); + } + else if (id == Block.waterStill.blockID || id == Block.waterMoving.blockID) + { + return FluidRegistry.getFluid("water"); + } + else if (id == Block.lavaStill.blockID || id == Block.lavaMoving.blockID) + { + return FluidRegistry.getFluid("lava"); + } + return null; + } + + public static FluidStack getStack(FluidStack stack, int amount) + { + if (stack != null) + { + FluidStack newStack = stack.copy(); + newStack.amount = amount; + return newStack; + } + return stack; + } + + /** Drains a block of fluid + * + * @Note sets the block with a client update only. Doesn't tick the block allowing for better + * placement of fluid that can flow infinitely + * + * @param doDrain - do the action + * @return FluidStack drained from the block */ + public static FluidStack drainBlock(World world, Vector3 node, boolean doDrain) + { + return drainBlock(world, node, doDrain, 2); + } + + /** Drains a block of fluid + * + * @param doDrain - do the action + * @param update - block update flag to use + * @return FluidStack drained from the block */ + public static FluidStack drainBlock(World world, Vector3 node, boolean doDrain, int update) + { + if (world == null || node == null) + { + return null; + } + + int blockID = node.getBlockID(world); + int meta = node.getBlockMetadata(world); + Block block = Block.blocksList[blockID]; + if (block != null) + { + if (block instanceof IFluidBlock && ((IFluidBlock) block).canDrain(world, node.intX(), node.intY(), node.intZ())) + { + return ((IFluidBlock) block).drain(world, node.intX(), node.intY(), node.intZ(), doDrain); + } + else if ((block.blockID == Block.waterStill.blockID || block.blockID == Block.waterMoving.blockID) && node.getBlockMetadata(world) == 0) + { + if (doDrain) + { + Vector3 vec = node.clone().modifyPositionFromSide(ForgeDirection.UP); + if (vec.getBlockID(world) == Block.waterlily.blockID) + { + vec.setBlock(world, 0, 0, update); + node.setBlock(world, blockID, meta); + } + else + { + node.setBlock(world, 0, 0, update); + } + } + return new FluidStack(FluidRegistry.getFluid("water"), FluidContainerRegistry.BUCKET_VOLUME); + } + else if ((block.blockID == Block.lavaStill.blockID || block.blockID == Block.lavaMoving.blockID) && node.getBlockMetadata(world) == 0) + { + if (doDrain) + { + node.setBlock(world, 0, 0, update); + } + return new FluidStack(FluidRegistry.getFluid("lava"), FluidContainerRegistry.BUCKET_VOLUME); + } + } + return null; + } + + /** Checks to see if a non-fluid block is able to be filled with fluid */ + public static boolean isFillableBlock(World world, Vector3 node) + { + if (world == null || node == null) + { + return false; + } + + int blockID = node.getBlockID(world); + int meta = node.getBlockMetadata(world); + Block block = Block.blocksList[blockID]; + if (drainBlock(world, node, false) != null) + { + return false; + } + else if (block == null || block.blockID == 0 || block.isAirBlock(world, node.intX(), node.intY(), node.intZ())) + { + return true; + } + else if (!(block instanceof IFluidBlock || block instanceof BlockFluid) && block.isBlockReplaceable(world, node.intX(), node.intY(), node.intZ()) || replacableBlockMeta.contains(new Pair(blockID, meta)) || replacableBlocks.contains(block)) + { + return true; + } + return false; + } + + /** Checks to see if a fluid related block is able to be filled */ + public static boolean isFillableFluid(World world, Vector3 node) + { + if (world == null || node == null) + { + return false; + } + + int blockID = node.getBlockID(world); + int meta = node.getBlockMetadata(world); + Block block = Block.blocksList[blockID]; + //TODO when added change this to call canFill and fill + if (drainBlock(world, node, false) != null) + { + return false; + } + else if (block instanceof IFluidBlock || block instanceof BlockFluid) + { + return meta != 0; + } + return false; + } + + /** Helper method to fill a location with a fluid + * + * Note: This does not update the block to prevent the liquid from flowing + * + * @return */ + public static int fillBlock(World world, Vector3 node, FluidStack stack, boolean doFill) + { + if ((isFillableBlock(world, node) || isFillableFluid(world, node)) && stack != null && stack.amount >= FluidContainerRegistry.BUCKET_VOLUME) + { + if (doFill) + { + int blockID = node.getBlockID(world); + int meta = node.getBlockMetadata(world); + Block block = Block.blocksList[blockID]; + Vector3 vec = node.clone().modifyPositionFromSide(ForgeDirection.UP); + + if (block != null) + { + if (block.blockID == Block.waterlily.blockID && vec.getBlockID(world) == 0) + { + vec.setBlock(world, blockID, meta); + } + else if (block != null && replacableBlocks.contains(block) && !nonBlockDropList.contains(block)) + { + block.dropBlockAsItem(world, node.intX(), node.intY(), node.intZ(), meta, 1); + block.breakBlock(world, node.intX(), node.intY(), node.intZ(), blockID, meta); + } + } + + node.setBlock(world, stack.getFluid().getBlockID()); + } + return FluidContainerRegistry.BUCKET_VOLUME; + } + return 0; + } + + /** Fills all instances of IFluidHandler surrounding the origin + * + * @param stack - FluidStack that will be filled into the tanks + * @param doFill - Actually perform the action or simulate action + * @param ignore - ForgeDirections to ignore + * @return amount of fluid that was used from the stack */ + public static int fillTanksAllSides(World world, Vector3 origin, FluidStack stack, boolean doFill, ForgeDirection... ignore) + { + int filled = 0; + FluidStack fillStack = stack != null ? stack.copy() : null; + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + if (fillStack == null || fillStack.amount <= 0) + { + return filled; + } + if (ignore != null) + { + for (int i = 0; i < ignore.length; i++) + { + if (direction == ignore[i]) + { + continue; + } + } + } + filled += fillTankSide(world, origin, stack, doFill, direction); + fillStack = getStack(stack, stack.amount - filled); + + } + return filled; + } + + /** Fills an instance of IFluidHandler in the given direction + * + * @param stack - FluidStack to fill the tank will + * @param doFill - Actually perform the action or simulate action + * @param direction - direction to fill in from the origin + * @return amount of fluid that was used from the stack */ + public static int fillTankSide(World world, Vector3 origin, FluidStack stack, boolean doFill, ForgeDirection direction) + { + TileEntity entity = origin.clone().modifyPositionFromSide(direction).getTileEntity(world); + if (entity instanceof IFluidHandler && ((IFluidHandler) entity).canFill(direction.getOpposite(), stack.getFluid())) + { + return ((IFluidHandler) entity).fill(direction.getOpposite(), stack, doFill); + } + return 0; + } + + /** Does all the work needed to fill or drain an item of fluid when a player clicks on the block. */ + public static boolean playerActivatedFluidItem(World world, int x, int y, int z, EntityPlayer entityplayer, int side) + { + //TODO add double click support similar to the crates in assembly line + ItemStack current = entityplayer.inventory.getCurrentItem(); + if (current != null && world.getBlockTileEntity(x, y, z) instanceof IFluidHandler) + { + + FluidStack liquid = FluidContainerRegistry.getFluidForFilledItem(current); + + IFluidHandler tank = (IFluidHandler) world.getBlockTileEntity(x, y, z); + + if (liquid != null) + { + if (tank.fill(ForgeDirection.UNKNOWN, liquid, true) != 0 && !entityplayer.capabilities.isCreativeMode) + { + entityplayer.inventory.setInventorySlotContents(entityplayer.inventory.currentItem, AutoCraftingManager.consumeItem(current, 1)); + } + + return true; + } + else + { + + FluidStack available = tank.drain(ForgeDirection.getOrientation(side), Integer.MAX_VALUE, false); + if (available != null) + { + ItemStack filled = FluidContainerRegistry.fillFluidContainer(available, current); + + liquid = FluidContainerRegistry.getFluidForFilledItem(filled); + + if (liquid != null) + { + if (!entityplayer.capabilities.isCreativeMode) + { + if (current.stackSize > 1) + { + if (!entityplayer.inventory.addItemStackToInventory(filled)) + { + return false; + } + else + { + entityplayer.inventory.setInventorySlotContents(entityplayer.inventory.currentItem, AutoCraftingManager.consumeItem(current, 1)); + } + } + else + { + entityplayer.inventory.setInventorySlotContents(entityplayer.inventory.currentItem, AutoCraftingManager.consumeItem(current, 1)); + entityplayer.inventory.setInventorySlotContents(entityplayer.inventory.currentItem, filled); + } + } + tank.drain(ForgeDirection.UNKNOWN, liquid.amount, true); + return true; + } + } + } + } + + return false; + } + + /** Drains an item of fluid and fills the tank with what was drained + * + * @param consumeItem - should it consume the item. Used mainly for creative mode players. This + * does effect the return of the method + * @return Item stack that would be returned if the item was drain of its fluid. Water bucket -> + * empty bucket */ + public static ItemStack drainItem(ItemStack stack, IFluidHandler tank, ForgeDirection side) + { + if (stack != null && tank != null) + { + FluidStack liquid = FluidContainerRegistry.getFluidForFilledItem(stack); + if (liquid != null) + { + if (tank.fill(side, liquid, true) > 0) + { + return stack.getItem().getContainerItemStack(stack); + } + } + } + return stack; + } + + /** Fills an item with fluid from the tank + * + * @param consumeItem - should it consume the item. Used mainly for creative mode players. This + * does effect the return of the method + * @return Item stack that would be returned if the item was filled with fluid. empty bucket -> + * water bucket */ + public static ItemStack fillItem(ItemStack stack, IFluidHandler tank, ForgeDirection side) + { + if (stack != null && tank != null) + { + FluidStack liquid = FluidContainerRegistry.getFluidForFilledItem(stack); + FluidStack drainStack = tank.drain(side, Integer.MAX_VALUE, false); + if (liquid == null && drainStack != null) + { + ItemStack liquidItem = FluidContainerRegistry.fillFluidContainer(drainStack, stack); + if (tank.drain(side, FluidContainerRegistry.getFluidForFilledItem(liquidItem), true) != null) + { + return liquidItem; + } + } + } + return stack; + } + + /** Builds a list of fluidStacks from FluidTankInfo general taken from an instanceof + * IFluidHandler */ + public static List getFluidList(FluidTankInfo... fluidTankInfos) + { + List stackList = new ArrayList(); + HashMap map = new HashMap(); + if (fluidTankInfos != null) + { + for (int i = 0; i < fluidTankInfos.length; i++) + { + FluidTankInfo info = fluidTankInfos[i]; + if (info != null && info.fluid != null) + { + FluidStack stack = info.fluid; + if (map.containsKey(FluidHelper.getStack(stack, 0))) + { + map.put(FluidHelper.getStack(stack, 0), map.get(FluidHelper.getStack(stack, 0)) + stack.amount); + } + else + { + map.put(FluidHelper.getStack(stack, 0), stack.amount); + } + } + } + Iterator> it = map.entrySet().iterator(); + while (it.hasNext()) + { + Entry entry = it.next(); + stackList.add(FluidHelper.getStack(entry.getKey(), entry.getValue())); + } + } + return stackList; + + } +} diff --git a/src/com/dark/fluid/Gas.java b/src/com/dark/fluid/Gas.java new file mode 100644 index 000000000..7a9e062be --- /dev/null +++ b/src/com/dark/fluid/Gas.java @@ -0,0 +1,17 @@ +package com.dark.fluid; + +import net.minecraftforge.fluids.Fluid; + +/** These is an extension of the Fluid system forcing it to be a gas on creation + * + * @author Archadia, DarkGuardsman */ +public class Gas extends Fluid +{ + + public Gas(String name) + { + super(name); + this.isGaseous = true; + this.density = -1000; + } +} diff --git a/src/com/dark/fluid/GasTank.java b/src/com/dark/fluid/GasTank.java new file mode 100644 index 000000000..0ef4b440b --- /dev/null +++ b/src/com/dark/fluid/GasTank.java @@ -0,0 +1,38 @@ +package com.dark.fluid; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; + +/** Version of the fluid tank that is restricted to gases only + * + * @author DarkGuardsman */ +public class GasTank extends FluidTank +{ + + public GasTank(int capacity) + { + super(capacity); + } + + public GasTank(FluidStack stack, int capacity) + { + super(stack, capacity); + } + + public GasTank(Fluid fluid, int amount, int capacity) + { + super(fluid, amount, capacity); + } + + @Override + public int fill(FluidStack resource, boolean doFill) + { + if (resource != null && resource.getFluid() != null && resource.getFluid().isGaseous()) + { + return super.fill(resource, doFill); + } + return 0; + } + +} diff --git a/src/com/dark/fluid/LiquidTank.java b/src/com/dark/fluid/LiquidTank.java new file mode 100644 index 000000000..0c22be3be --- /dev/null +++ b/src/com/dark/fluid/LiquidTank.java @@ -0,0 +1,38 @@ +package com.dark.fluid; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; + +/** Version of the fluid tank that only supports liquids + * + * @author DarkGuardsman */ +public class LiquidTank extends FluidTank +{ + + public LiquidTank(int capacity) + { + super(capacity); + } + + public LiquidTank(FluidStack stack, int capacity) + { + super(stack, capacity); + } + + public LiquidTank(Fluid fluid, int amount, int capacity) + { + super(fluid, amount, capacity); + } + + @Override + public int fill(FluidStack resource, boolean doFill) + { + if (resource != null && resource.getFluid() != null && !resource.getFluid().isGaseous()) + { + return super.fill(resource, doFill); + } + return 0; + } + +} diff --git a/src/com/dark/helpers/AutoCraftingManager.java b/src/com/dark/helpers/AutoCraftingManager.java new file mode 100644 index 000000000..901c98a4a --- /dev/null +++ b/src/com/dark/helpers/AutoCraftingManager.java @@ -0,0 +1,543 @@ +package com.dark.helpers; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemBucket; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.ShapedRecipes; +import net.minecraft.item.crafting.ShapelessRecipes; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent; +import net.minecraftforge.oredict.ShapedOreRecipe; +import net.minecraftforge.oredict.ShapelessOreRecipe; + +import com.builtbroken.common.Pair; + +import cpw.mods.fml.relauncher.ReflectionHelper; + +/** Rewrite of the imprinter crafting system into its own manageable class + * + * @author DarkGuardsman */ +public class AutoCraftingManager +{ + static boolean doDebug = false; + TileEntity craftingEntity; + IInventory craftingInv; + + /** The entity must be an instance of IInventory to pass only the tileEntity */ + public AutoCraftingManager(final IAutoCrafter entity) + { + this.craftingEntity = (TileEntity) entity; + if (entity instanceof IInventory) + { + this.craftingInv = (IInventory) entity; + } + } + + /** Use only the entity if it is also an instance of IInventory */ + public AutoCraftingManager(final IAutoCrafter entity, final IInventory inv) + { + this(entity); + if (inv != null) + { + this.craftingInv = inv; + } + } + + public void printDebug(String pre, String msg) + { + if (doDebug) + { + System.out.println("[AutoCrafter]: " + pre + " > " + msg); + } + } + + public static void printRecipe(Object[] objects) + { + //TODO format and make it look nice + for (Object obj : objects) + { + System.out.println(obj); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static void printRecipes(ItemStack stack) + { + List recipes = getRecipes(stack); + for (IRecipe recipe : recipes) + { + if (recipe.getRecipeOutput() != null) + { + if (AutoCraftingManager.areStacksEqual(recipe.getRecipeOutput(), stack)) + { + if (recipe instanceof ShapedRecipes) + { + printRecipe(((ShapedRecipes) recipe).recipeItems); + } + else if (recipe instanceof ShapelessRecipes) + { + printRecipe(((ShapelessRecipes) recipe).recipeItems.toArray(new Object[1])); + } + else if (recipe instanceof ShapedOreRecipe) + { + ShapedOreRecipe oreRecipe = (ShapedOreRecipe) recipe; + printRecipe((Object[]) ReflectionHelper.getPrivateValue(ShapedOreRecipe.class, oreRecipe, "input")); + + } + else if (recipe instanceof ShapelessOreRecipe) + { + ShapelessOreRecipe oreRecipe = (ShapelessOreRecipe) recipe; + ArrayList oreRecipeInput = (ArrayList) ReflectionHelper.getPrivateValue(ShapelessOreRecipe.class, oreRecipe, "input"); + for (Object obj : oreRecipeInput) + { + System.out.println(obj); + } + } + } + } + } + } + + /** Grabs a list of recipes that can be used to create the given item */ + public static List getRecipes(ItemStack stack) + { + List recipes = new ArrayList(); + for (Object object : CraftingManager.getInstance().getRecipeList()) + { + if (object instanceof IRecipe) + { + if (((IRecipe) object).getRecipeOutput() != null) + { + if (AutoCraftingManager.areStacksEqual(stack, ((IRecipe) object).getRecipeOutput())) + { + recipes.add((IRecipe) object); + } + } + } + } + return recipes; + } + + /** Does this player's inventory contain the required resources to craft this item? + * + * @return Required items to make the desired item. */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Pair getIdealRecipe(ItemStack outputItem) + { + this.printDebug("IdealRecipe", outputItem.toString()); + + for (Object object : CraftingManager.getInstance().getRecipeList()) + { + if (object instanceof IRecipe) + { + if (((IRecipe) object).getRecipeOutput() != null) + { + if (AutoCraftingManager.areStacksEqual(outputItem, ((IRecipe) object).getRecipeOutput())) + { + this.printDebug("IdealRecipe", "Output Match Found"); + if (object instanceof ShapedRecipes) + { + if (this.hasResource(((ShapedRecipes) object).recipeItems) != null) + { + this.printDebug("IdealRecipe", "Shaped Recipe Found"); + return new Pair(((IRecipe) object).getRecipeOutput().copy(), ((ShapedRecipes) object).recipeItems); + } + } + else if (object instanceof ShapelessRecipes) + { + if (this.hasResource(((ShapelessRecipes) object).recipeItems.toArray(new ItemStack[1])) != null) + { + this.printDebug("IdealRecipe", "Shapeless Recipe Found"); + return new Pair(((IRecipe) object).getRecipeOutput().copy(), (ItemStack[]) ((ShapelessRecipes) object).recipeItems.toArray(new ItemStack[1])); + } + } + else if (object instanceof ShapedOreRecipe) + { + ShapedOreRecipe oreRecipe = (ShapedOreRecipe) object; + Object[] oreRecipeInput = (Object[]) ReflectionHelper.getPrivateValue(ShapedOreRecipe.class, oreRecipe, "input"); + + ArrayList hasResources = this.hasResource(oreRecipeInput); + + if (hasResources != null) + { + this.printDebug("IdealRecipe", "ShapedOre Recipe Found"); + return new Pair(((IRecipe) object).getRecipeOutput().copy(), hasResources.toArray(new ItemStack[1])); + } + } + else if (object instanceof ShapelessOreRecipe) + { + ShapelessOreRecipe oreRecipe = (ShapelessOreRecipe) object; + ArrayList oreRecipeInput = (ArrayList) ReflectionHelper.getPrivateValue(ShapelessOreRecipe.class, oreRecipe, "input"); + + List hasResources = this.hasResource(oreRecipeInput.toArray()); + + if (hasResources != null) + { + this.printDebug("IdealRecipe", "ShapelessOre Recipe Found"); + return new Pair(((IRecipe) object).getRecipeOutput().copy(), hasResources.toArray(new ItemStack[1])); + } + } + } + } + } + } + + return null; + } + + /** Gets a basic array containing all items that were used to craft the given item. Doesn't sort + * threw the recipes and will return the first possible recipe */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static ItemStack[] getReverseRecipe(ItemStack outputItem, int outputSize) + { + + for (Object object : CraftingManager.getInstance().getRecipeList()) + { + if (object instanceof IRecipe) + { + if (((IRecipe) object).getRecipeOutput() != null) + { + if (((IRecipe) object).getRecipeOutput().isItemEqual(outputItem) && (outputSize == -1 || ((IRecipe) object).getRecipeOutput().stackSize == outputItem.stackSize)) + { + if (object instanceof ShapedRecipes) + { + return ((ShapedRecipes) object).recipeItems.clone(); + + } + else if (object instanceof ShapelessRecipes) + { + return (ItemStack[]) ((ShapelessRecipes) object).recipeItems.toArray(new ItemStack[9]).clone(); + + } + else if (object instanceof ShapedOreRecipe) + { + ShapedOreRecipe oreRecipe = (ShapedOreRecipe) object; + Object[] recipeItems = (Object[]) ReflectionHelper.getPrivateValue(ShapedOreRecipe.class, oreRecipe, "input"); + ItemStack[] actualResources; + if (recipeItems != null) + { + actualResources = new ItemStack[recipeItems.length]; + for (int i = 0; i < recipeItems.length; i++) + { + if (recipeItems[i] instanceof ItemStack) + { + actualResources[i] = ((ItemStack) recipeItems[i]).copy(); + } + else if (recipeItems[i] instanceof ArrayList) + { + Object[] ingredientsArray = ((ArrayList) recipeItems[i]).toArray(); + + for (int x = 0; x < ingredientsArray.length; x++) + { + if (ingredientsArray[x] != null && ingredientsArray[x] instanceof ItemStack) + { + actualResources[i] = ((ItemStack) ingredientsArray[x]).copy(); + break; + } + } + } + } + return actualResources; + } + } + else if (object instanceof ShapelessOreRecipe) + { + ShapelessOreRecipe oreRecipe = (ShapelessOreRecipe) object; + return (ItemStack[]) ((ArrayList) ReflectionHelper.getPrivateValue(ShapelessOreRecipe.class, oreRecipe, "input")).toArray(new ItemStack[9]).clone(); + } + } + } + } + } + + return null; + } + + /** Gets the itemStacks in the inv based on slots + * + * @param inv - @IInventory instance + * @param slots - slot # to be used + * @return array of itemStack the same size as the slots input array */ + public ItemStack[] getInvItems(IInventory inv, int... slots) + { + ItemStack[] containingItems = new ItemStack[slots.length]; + + for (int slot = 0; slot < slots.length; slot++) + { + if (inv.getStackInSlot(slots[slot]) != null) + { + containingItems[slot] = inv.getStackInSlot(slots[slot]).copy(); + } + } + + return containingItems; + } + + /** Returns if the following inventory has the following resource required. + * + * @param recipeItems - The items to be checked for the recipes. */ + @SuppressWarnings("rawtypes") + public ArrayList hasResource(Object[] recipeItems) + { + try + { + ItemStack[] containingItems = this.getInvItems(this.craftingInv, ((IAutoCrafter) this.craftingEntity).getCraftingInv()); + + this.printDebug("ResourceChecker", "Looking for items"); + for (int i = 0; i < recipeItems.length && AutoCraftingManager.doDebug; i++) + { + this.printDebug("ResourceChecker", "Looking for " + recipeItems.toString()); + } + /** The actual amount of resource required. Each ItemStack will only have stacksize of 1. */ + ArrayList actualResources = new ArrayList(); + + int itemMatch = 0; + int itemInList = 0; + + for (Object obj : recipeItems) + { + itemInList++; + if (obj instanceof ItemStack) + { + ItemStack recipeItem = (ItemStack) obj; + actualResources.add(recipeItem.copy()); + + if (recipeItem != null) + { + this.printDebug("ResourceChecker", "Item0" + itemInList + " = " + recipeItem.toString()); + int match = this.doesItemExist(recipeItem, containingItems); + if (match >= 0) + { + containingItems[match] = AutoCraftingManager.decrStackSize(containingItems[match], recipeItem.stackSize); + this.printDebug("ResourceChecker", "Match found @" + match); + itemMatch++; + } + } + } + else if (obj instanceof ArrayList) + { + /** Look for various possible ingredients of the same item and try to match it. */ + ArrayList ingredientsList = (ArrayList) obj; + Object[] ingredientsArray = ingredientsList.toArray(); + + this.printDebug("ResourceChecker", "Obj0" + itemInList + " = " + obj.toString()); + + for (int x = 0; x < ingredientsArray.length; x++) + { + if (ingredientsArray[x] != null && ingredientsArray[x] instanceof ItemStack) + { + ItemStack recipeItem = (ItemStack) ingredientsArray[x]; + actualResources.add(recipeItem.copy()); + + if (recipeItem != null) + { + int match = this.doesItemExist(recipeItem, containingItems); + if (match >= 0) + { + containingItems[match] = AutoCraftingManager.decrStackSize(containingItems[match], recipeItem.stackSize); + this.printDebug("ResourceChecker", "Match found @" + match); + itemMatch++; + break; + } + } + } + } + } + else + { + this.printDebug("ResourceChecker", "Item0" + itemInList + " = null"); + } + } + boolean resourcesFound = itemMatch >= actualResources.size(); + this.printDebug("ResourceChecker", actualResources.size() + " items needed and " + itemMatch + " valid matches found"); + this.printDebug("ResourceChecker", "has all resources been found? /n A: " + resourcesFound); + return resourcesFound ? actualResources : null; + } + catch (Exception e) + { + System.out.println("Failed to find recipes in the imprinter."); + e.printStackTrace(); + } + + return null; + } + + /** Decreases the stack by a set amount + * + * @param stack - starting stack + * @param amount - amount of items + * @return the edited stack */ + public static ItemStack decrStackSize(ItemStack stack, int amount) + { + if (stack != null) + { + ItemStack itemStack = stack.copy(); + if (itemStack.stackSize <= amount) + { + return null; + } + else + { + itemStack.stackSize -= amount; + + if (itemStack.stackSize <= 0) + { + return null; + } + return itemStack; + } + } + else + { + return null; + } + } + + /** Checks if an item exist within the inv array + * + * @param recipeItem - itemstack being searched for + * @param containingItems - inv array containing the search bounds + * @return the point in the array the item was found -1 = the item was null or not valid -2 = + * the item was not found */ + private int doesItemExist(ItemStack recipeItem, ItemStack[] containingItems) + { + if (recipeItem == null || recipeItem.itemID == 0 || recipeItem.stackSize <= 0) + { + return -1; + } + this.printDebug("ResourceChecker", "Checking inv for item " + recipeItem.toString()); + for (int i = 0; i < containingItems.length; i++) + { + ItemStack checkStack = containingItems[i]; + + if (checkStack != null) + { + this.printDebug("ResourceChecker", " -----Item in slot0" + i + " = " + checkStack.toString()); + if (AutoCraftingManager.areStacksEqual(recipeItem, checkStack)) + { + this.printDebug("ResourceChecker", "Found matching item " + checkStack.toString()); + return i; + } + } + } + + return -2; + } + + /** Checks if itemstack are equal based on crafting result rather than normal itemstack this is + * done so that if the itemstack returns with + * + * @param recipeItem - itemstack being compared + * @param checkStack - itemstack being comparted + * @return true if the items are a match for each other + * + * If the item can't be stack and is able to take damage the item will be check on damaged + * status + * + * If the item's meta data is not normal or in other words equals 32767 the meta data will be + * ignored */ + public static boolean areStacksEqual(ItemStack recipeItem, ItemStack checkStack) + { + if (recipeItem == null || checkStack == null) + { + return false; + } + if (recipeItem.itemID < Block.blocksList.length && recipeItem.getItemDamage() == 32767) + { + return recipeItem.itemID == checkStack.itemID; + } + if (recipeItem.isItemStackDamageable()) + { + return !recipeItem.isItemDamaged() && recipeItem.itemID == checkStack.itemID; + } + return recipeItem.isItemEqual(checkStack); + } + + /** Consumes an item checking for extra conditions like container items + * + * @param stack - starting itemStack + * @param ammount - amount to consume + * @return what is left of the itemStack if any */ + public static ItemStack consumeItem(ItemStack itemStack, int amount) + { + if (itemStack == null) + { + return null; + } + + ItemStack stack = itemStack.copy(); + + if (stack.getItem() instanceof ItemBucket && stack.itemID != Item.bucketEmpty.itemID) + { + return new ItemStack(Item.bucketEmpty, 1); + } + + if (stack.getItem().hasContainerItem()) + { + ItemStack containerStack = stack.getItem().getContainerItemStack(stack); + + if (containerStack.isItemStackDamageable() && containerStack.getItemDamage() > containerStack.getMaxDamage()) + { + try + { + MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(null, containerStack)); + } + catch (Exception e) + { + + } + return null; + } + + if (containerStack != null && !stack.getItem().doesContainerItemLeaveCraftingGrid(stack)) + { + return containerStack; + } + } + //System.out.println("ItemGrinder: "+stack.toString()); + return decrStackSize(stack, amount); + } + + /** Used to automatically remove selected items from crafting inv + * + * @param requiredItems - items that are to be removed */ + public void consumeItems(ItemStack... requiredItems) + { + if (requiredItems != null) + { + for (ItemStack searchStack : requiredItems) + { + if (searchStack != null) + { + int[] invSlots = ((IAutoCrafter) this.craftingEntity).getCraftingInv(); + for (int i = 0; i < invSlots.length; i++) + { + ItemStack checkStack = this.craftingInv.getStackInSlot(invSlots[i]); + if (checkStack != null) + { + if (AutoCraftingManager.areStacksEqual(searchStack, checkStack)) + { + this.craftingInv.setInventorySlotContents(invSlots[i], AutoCraftingManager.consumeItem(checkStack, 1)); + break; + } + } + } + } + } + } + } + + public static interface IAutoCrafter + { + /** The slots used by the crafter for resources */ + public int[] getCraftingInv(); + } +} diff --git a/src/com/dark/helpers/ConnectionHelper.java b/src/com/dark/helpers/ConnectionHelper.java new file mode 100644 index 000000000..6e5a1560f --- /dev/null +++ b/src/com/dark/helpers/ConnectionHelper.java @@ -0,0 +1,67 @@ +package com.dark.helpers; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.vector.Vector3; + +public class ConnectionHelper +{ + /** Used to find all tileEntities sounding the location you will have to filter for selective + * tileEntities + * + * @param world - the world being searched threw + * @param x + * @param y + * @param z + * @return an array of up to 6 tileEntities */ + public static TileEntity[] getSurroundingTileEntities(TileEntity ent) + { + return getSurroundingTileEntities(ent.worldObj, ent.xCoord, ent.yCoord, ent.zCoord); + } + + public static TileEntity[] getSurroundingTileEntities(World world, Vector3 vec) + { + return getSurroundingTileEntities(world, vec.intX(), vec.intY(), vec.intZ()); + } + + public static TileEntity[] getSurroundingTileEntities(World world, int x, int y, int z) + { + TileEntity[] list = new TileEntity[6]; + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + list[direction.ordinal()] = world.getBlockTileEntity(x + direction.offsetX, y + direction.offsetY, z + direction.offsetZ); + } + return list; + } + + /** Used to find which of 4 Corners this block is in a group of blocks 0 = not a corner 1-4 = a + * corner of some direction */ + public static int corner(TileEntity entity) + { + TileEntity[] en = getSurroundingTileEntities(entity.worldObj, entity.xCoord, entity.yCoord, entity.zCoord); + TileEntity north = en[ForgeDirection.NORTH.ordinal()]; + TileEntity south = en[ForgeDirection.SOUTH.ordinal()]; + TileEntity east = en[ForgeDirection.EAST.ordinal()]; + TileEntity west = en[ForgeDirection.WEST.ordinal()]; + + if (west != null && north != null && east == null && south == null) + { + return 3; + } + if (north != null && east != null && south == null && west == null) + { + return 4; + } + if (east != null && south != null && west == null && north == null) + { + return 1; + } + if (south != null && west != null && north == null && east == null) + { + return 2; + } + + return 0; + } +} diff --git a/src/com/dark/helpers/EntityDictionary.java b/src/com/dark/helpers/EntityDictionary.java new file mode 100644 index 000000000..7a05a6e8b --- /dev/null +++ b/src/com/dark/helpers/EntityDictionary.java @@ -0,0 +1,185 @@ +package com.dark.helpers; + +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.boss.EntityDragon; +import net.minecraft.entity.boss.EntityWither; +import net.minecraft.entity.item.EntityBoat; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.item.EntityMinecart; +import net.minecraft.entity.monster.EntityCreeper; +import net.minecraft.entity.monster.EntityMob; +import net.minecraft.entity.monster.EntitySkeleton; +import net.minecraft.entity.monster.EntitySlime; +import net.minecraft.entity.monster.EntitySpider; +import net.minecraft.entity.monster.EntityZombie; +import net.minecraft.entity.passive.EntityAnimal; +import net.minecraft.entity.passive.EntityChicken; +import net.minecraft.entity.passive.EntityCow; +import net.minecraft.entity.passive.EntityPig; +import net.minecraft.entity.passive.EntitySheep; +import net.minecraft.entity.player.EntityPlayer; + +/** Dictionary to track entities by several names to be used for anything. Current use is armbot task + * so the user has an easy way to ID creatures. + * + * @author DarkGuardsman */ +public class EntityDictionary +{ + public static HashMap> entityMap = new HashMap(); + public static HashMap, Boolean> grabMap = new HashMap(); + + private static boolean init = false; + + /** Call this very last in a mod so that all mods have a chance to load there entities */ + public static void init() + { + if (!init) + { + init = true; + for (Object object : EntityList.classToStringMapping.entrySet()) + { + if (object instanceof Entry) + { + Object key = ((Entry) object).getKey(); + Object value = ((Entry) object).getKey(); + if (key instanceof Class && value instanceof String) + { + entityMap.put((String) value, (Class) key); + } + } + } + } + } + + static + { + addName("chicken", EntityChicken.class); + addName("cow", EntityCow.class); + addName("sheep", EntitySheep.class); + addName("pig", EntityPig.class); + addName("player", EntityPlayer.class); + addName("zombie", EntityZombie.class); + addName("zomb", EntityZombie.class); + addName("skeleton", EntitySkeleton.class); + addName("skel", EntitySkeleton.class); + addName("animal", EntityAnimal.class); + addName("monster", EntityMob.class); + addName("mob", EntityMob.class); + addName("creeper", EntityCreeper.class); + addName("spider", EntitySpider.class); + addName("slime", EntitySlime.class); + addName("items", EntityItem.class); + addName("item", EntityItem.class); + addName("all", Entity.class); + addName("everything", Entity.class); + addName("boat", EntityBoat.class); + addName("cart", EntityMinecart.class); + setCanNotBeGrabbed(EntityDragon.class); + setCanNotBeGrabbed(EntityWither.class); + } + + public static Class get(String name) + { + return entityMap.get(name); + } + + /** Can the entity be grabbed by something such as a robot, or another entity. By default most + * entities can be grabbed by another object. */ + public static boolean canGrab(String name) + { + if (entityMap.containsKey(name)) + { + return canGrab(entityMap.get(name)); + } + return true; + } + + /** Can the entity be grabbed by something such as a robot, or another entity. By default most + * entities can be grabbed by another object. */ + public static boolean canGrab(Entity entity) + { + if (entity != null) + { + if (canGrab(entity.getClass())) + { + return true; + } + else + { + for (Entry, Boolean> entry : grabMap.entrySet()) + { + if (entry.getKey().isInstance(entity)) + { + return entry.getValue(); + } + } + return true; + } + } + return false; + } + + /** Can the entity be grabbed by something such as a robot, or another entity. By default most + * entities can be grabbed by another object. */ + public static boolean canGrab(Class clazz) + { + if (grabMap.containsKey(clazz)) + { + return grabMap.get(clazz); + } + else + { + for (Entry, Boolean> entry : grabMap.entrySet()) + { + if (entry.getKey().isAssignableFrom(clazz)) + { + return entry.getValue(); + } + } + return true; + } + } + + public static void setCanNotBeGrabbed(Class clazz) + { + grabMap.put(clazz, false); + } + + public static void setCanBeGrabbed(Class clazz) + { + grabMap.put(clazz, true); + } + + public static void addName(Class clazz, String name) + { + entityMap.put(name, clazz); + } + + public static void addName(String name, Class clazz) + { + addName(clazz, name); + } + + public static List> getList() + { + // TODO Auto-generated method stub + return null; + } + + public static String get(Class entityToInclude) + { + for (Entry> entry : entityMap.entrySet()) + { + if (entry.getClass() != null && entry.getClass().equals(entityToInclude)) + { + return entry.getKey(); + } + } + return null; + } +} diff --git a/src/com/dark/helpers/InvInteractionHelper.java b/src/com/dark/helpers/InvInteractionHelper.java new file mode 100644 index 000000000..bb372f067 --- /dev/null +++ b/src/com/dark/helpers/InvInteractionHelper.java @@ -0,0 +1,340 @@ +package com.dark.helpers; + +import java.util.ArrayList; +import java.util.List; + +import com.dark.interfaces.IExtendedStorage; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.vector.Vector3; + +/** Helper that handles most of the interaction of the tile with the inventories around it + * + * @author Rseifert */ +public class InvInteractionHelper +{ + public World world; + Vector3 location; + List filteredItems; + boolean inverted; + + public InvInteractionHelper(World world, Vector3 location, List filters, boolean inverted) + { + this.world = world; + this.location = location; + this.filteredItems = filters; + if (filteredItems == null) + { + filteredItems = new ArrayList(); + } + this.inverted = inverted; + } + + public void setFilter(List filters, boolean inverted) + { + this.filteredItems = filters; + this.inverted = inverted; + } + + /** Throws the items from the manipulator into the world. + * + * @param outputPosition + * @param items */ + public void throwItem(Vector3 outputPosition, ItemStack items) + { + if (!world.isRemote) + { + EntityItem entityItem = new EntityItem(world, outputPosition.x + 0.5, outputPosition.y + 0.8, outputPosition.z + 0.5, items); + entityItem.motionX = 0; + entityItem.motionZ = 0; + entityItem.motionY /= 5; + entityItem.delayBeforeCanPickup = 20; + world.spawnEntityInWorld(entityItem); + } + } + + public ItemStack storeItem(ItemStack item, ForgeDirection... directions) + { + if (item != null) + { + ItemStack remainingStack = item.copy(); + for (ForgeDirection direction : directions) + { + remainingStack = tryPlaceInPosition(remainingStack, this.location.clone().modifyPositionFromSide(direction), direction.getOpposite()); + } + return remainingStack; + } + return item; + } + + /** Tries to place an itemStack in a specific position if it is an inventory. + * + * @return The ItemStack remained after place attempt */ + public ItemStack tryPlaceInPosition(ItemStack itemStack, Vector3 position, ForgeDirection dir) + { + TileEntity tileEntity = position.getTileEntity(world); + ForgeDirection direction = dir.getOpposite(); + + if (tileEntity != null && itemStack != null) + { + if (tileEntity instanceof TileEntityChest) + { + TileEntityChest[] chests = { (TileEntityChest) tileEntity, null }; + + /** Try to find a double chest. */ + for (int i = 2; i < 6; i++) + { + ForgeDirection searchDirection = ForgeDirection.getOrientation(i); + Vector3 searchPosition = position.clone(); + searchPosition.modifyPositionFromSide(searchDirection); + + if (searchPosition.getTileEntity(world) != null) + { + if (searchPosition.getTileEntity(world).getClass() == chests[0].getClass()) + { + chests[1] = (TileEntityChest) searchPosition.getTileEntity(world); + break; + } + } + } + + for (TileEntityChest chest : chests) + { + if (chest != null) + { + for (int i = 0; i < chest.getSizeInventory(); i++) + { + itemStack = this.addStackToInventory(i, chest, itemStack); + if (itemStack == null) + { + return null; + } + } + } + } + } + else if (tileEntity instanceof IExtendedStorage) + { + return ((IExtendedStorage) tileEntity).addStackToStorage(itemStack); + } + else if (tileEntity instanceof ISidedInventory) + { + ISidedInventory inventory = (ISidedInventory) tileEntity; + int[] slots = inventory.getAccessibleSlotsFromSide(direction.ordinal()); + for (int i = 0; i < slots.length; i++) + { + if (inventory.canInsertItem(slots[i], itemStack, direction.ordinal())) + { + itemStack = this.addStackToInventory(slots[i], inventory, itemStack); + } + if (itemStack == null) + { + return null; + } + } + + } + else if (tileEntity instanceof IInventory) + { + IInventory inventory = (IInventory) tileEntity; + + for (int i = 0; i < inventory.getSizeInventory(); i++) + { + itemStack = this.addStackToInventory(i, inventory, itemStack); + if (itemStack == null) + { + return null; + } + } + } + } + + if (itemStack == null || itemStack.stackSize <= 0) + { + return null; + } + + return itemStack; + } + + public ItemStack addStackToInventory(int slotIndex, IInventory inventory, ItemStack itemStack) + { + if (inventory.getSizeInventory() > slotIndex) + { + ItemStack stackInInventory = inventory.getStackInSlot(slotIndex); + + if (stackInInventory == null) + { + inventory.setInventorySlotContents(slotIndex, itemStack); + if (inventory.getStackInSlot(slotIndex) == null) + { + return itemStack; + } + return null; + } + else if (stackInInventory.isItemEqual(itemStack) && stackInInventory.isStackable()) + { + stackInInventory = stackInInventory.copy(); + int stackLim = Math.min(inventory.getInventoryStackLimit(), itemStack.getMaxStackSize()); + int rejectedAmount = Math.max((stackInInventory.stackSize + itemStack.stackSize) - stackLim, 0); + stackInInventory.stackSize = Math.min(Math.max((stackInInventory.stackSize + itemStack.stackSize - rejectedAmount), 0), inventory.getInventoryStackLimit()); + itemStack.stackSize = rejectedAmount; + inventory.setInventorySlotContents(slotIndex, stackInInventory); + } + } + + if (itemStack.stackSize <= 0) + { + return null; + } + + return itemStack; + } + + /** Tries to get an item from a position + * + * @param position - location of item + * @param direction - direction this item is from the original + * @param ammount - amount up to one stack to grab + * @return the grabbed item stack */ + public ItemStack tryGrabFromPosition(Vector3 position, ForgeDirection dir, int ammount) + { + ItemStack returnStack = null; + TileEntity tileEntity = position.getTileEntity(world); + ForgeDirection direction = dir.getOpposite(); + + if (tileEntity != null) + { + if (tileEntity.getClass() == TileEntityChest.class) + { + TileEntityChest[] chests = { (TileEntityChest) tileEntity, null }; + + /** Try to find a double chest. */ + for (int i = 2; i < 6; i++) + { + ForgeDirection searchDirection = ForgeDirection.getOrientation(i); + Vector3 searchPosition = position.clone(); + searchPosition.modifyPositionFromSide(searchDirection); + + if (searchPosition.getTileEntity(world) != null) + { + if (searchPosition.getTileEntity(world).getClass() == chests[0].getClass()) + { + chests[1] = (TileEntityChest) searchPosition.getTileEntity(world); + break; + } + } + } + + chestSearch: + for (TileEntityChest chest : chests) + { + if (chest != null) + { + for (int i = 0; i < chest.getSizeInventory(); i++) + { + ItemStack itemStack = this.removeStackFromInventory(i, chest, ammount); + + if (itemStack != null) + { + returnStack = itemStack; + break chestSearch; + } + } + } + } + } + else if (tileEntity instanceof ISidedInventory) + { + ISidedInventory inventory = (ISidedInventory) tileEntity; + int[] slots = inventory.getAccessibleSlotsFromSide(direction.ordinal()); + for (int i = 0; i < slots.length; i++) + { + int slot = slots[i]; + ItemStack slotStack = inventory.getStackInSlot(slot); + if (inventory.canExtractItem(slot, slotStack, direction.ordinal())) + { + ItemStack itemStack = this.removeStackFromInventory(slot, inventory, ammount); + if (itemStack != null) + { + returnStack = itemStack; + break; + } + } + } + } + else if (tileEntity instanceof IInventory) + { + IInventory inventory = (IInventory) tileEntity; + + for (int i = 0; i < inventory.getSizeInventory(); i++) + { + ItemStack itemStack = this.removeStackFromInventory(i, inventory, ammount); + if (itemStack != null) + { + returnStack = itemStack; + break; + } + } + } + } + + return returnStack; + } + + /** Takes an item from the given inventory */ + public ItemStack removeStackFromInventory(int slotIndex, IInventory inventory, int amount) + { + if (inventory.getStackInSlot(slotIndex) != null) + { + ItemStack itemStack = inventory.getStackInSlot(slotIndex).copy(); + + if (this.getFilters().size() == 0 || this.isFiltering(itemStack)) + { + amount = Math.min(amount, itemStack.stackSize); + itemStack.stackSize = amount; + inventory.decrStackSize(slotIndex, amount); + return itemStack; + } + } + + return null; + } + + /** is the item being restricted to a filter set */ + public boolean isFiltering(ItemStack itemStack) + { + if (this.getFilters() != null && itemStack != null) + { + for (int i = 0; i < getFilters().size(); i++) + { + if (getFilters().get(i) != null) + { + if (getFilters().get(i).isItemEqual(itemStack)) + { + return !inverted; + } + } + } + } + + return inverted; + } + + public List getFilters() + { + if (this.filteredItems == null) + { + this.filteredItems = new ArrayList(); + } + return this.filteredItems; + } + +} diff --git a/src/com/dark/helpers/ItemWorldHelper.java b/src/com/dark/helpers/ItemWorldHelper.java new file mode 100644 index 000000000..da9c5f5ab --- /dev/null +++ b/src/com/dark/helpers/ItemWorldHelper.java @@ -0,0 +1,143 @@ +package com.dark.helpers; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.command.IEntitySelector; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.item.ItemStack; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.vector.Vector3; + +public class ItemWorldHelper +{ + + /** gets all EntityItems in a location using a start and end point */ + public static List findAllItemsIn(World world, Vector3 start, Vector3 end) + { + return world.getEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getBoundingBox(start.x, start.y, start.z, end.x, end.y, end.z)); + } + + public static List getEntitiesInDirection(World world, Vector3 center, ForgeDirection dir) + { + List list = world.selectEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getAABBPool().getAABB(center.x + dir.offsetX, center.y + dir.offsetY, center.z + dir.offsetZ, center.x + dir.offsetX + 1, center.y + dir.offsetY + 1, center.z + dir.offsetZ + 1), IEntitySelector.selectAnything); + return list.size() > 0 ? list : null; + } + + /** Gets all EntityItems in an area and sorts them by a list of itemStacks + * + * @param world - world being worked in + * @param start - start point + * @param end - end point + * @param disiredItems - list of item that are being looked for + * @return a list of EntityItem that match the itemStacks desired */ + public static List findSelectItems(World world, Vector3 start, Vector3 end, List disiredItems) + { + List entityItems = ItemWorldHelper.findAllItemsIn(world, start, end); + return filterEntityItemsList(entityItems, disiredItems); + } + + /** filters an EntityItem List to a List of Items */ + public static List filterEntityItemsList(List entityItems, List disiredItems) + { + List newItemList = new ArrayList(); + for (ItemStack itemStack : disiredItems) + { + for (EntityItem entityItem : entityItems) + { + if (entityItem.getEntityItem().isItemEqual(itemStack) && !newItemList.contains(entityItem)) + { + newItemList.add(entityItem); + break; + } + } + } + return newItemList; + } + + /** filters out EnittyItems from an Entity list */ + public static List filterOutEntityItems(List entities) + { + List newEntityList = new ArrayList(); + + for (Entity entity : entities) + { + if (entity instanceof EntityItem) + { + newEntityList.add((EntityItem) entity); + } + + } + return newEntityList; + } + + /** filter a list of itemStack to another list of itemStacks + * + * @param totalItems - full list of items being filtered + * @param desiredItems - list the of item that are being filtered too + * @return a list of item from the original that are wanted */ + public static List filterItems(List totalItems, List desiredItems) + { + List newItemList = new ArrayList(); + + for (ItemStack entityItem : totalItems) + { + for (ItemStack itemStack : desiredItems) + { + if (entityItem.itemID == itemStack.itemID && entityItem.getItemDamage() == itemStack.getItemDamage() && !newItemList.contains(entityItem)) + { + newItemList.add(entityItem); + break; + } + } + } + return newItemList; + } + + /** grabs all the items that the block can drop then pass them onto dropBlockAsItem_do + * + * @param world + * @param x + * @param y + * @param z */ + public static void dropBlockAsItem(World world, Vector3 loc) + { + if (!world.isRemote) + { + int meta = loc.getBlockMetadata(world); + int id = loc.getBlockID(world); + ArrayList items = Block.blocksList[id].getBlockDropped(world, loc.intX(), loc.intY(), loc.intZ(), meta, 0); + + for (ItemStack item : items) + { + dropItemStack(world, loc, item, false); + } + } + } + + public static ItemStack dropItemStack(World world, Vector3 location, ItemStack itemStack, boolean random) + { + if (!world.isRemote && world.getGameRules().getGameRuleBooleanValue("doTileDrops")) + { + float f = 0.7F; + double xx = 0; + double yy = 0; + double zz = 0; + if (random) + { + xx = (world.rand.nextFloat() * f) + (1.0F - f) * 0.5D; + yy = (world.rand.nextFloat() * f) + (1.0F - f) * 0.5D; + zz = (world.rand.nextFloat() * f) + (1.0F - f) * 0.5D; + } + EntityItem entityitem = new EntityItem(world, location.x + xx, location.y + yy, location.z + zz, itemStack); + entityitem.delayBeforeCanPickup = 10; + world.spawnEntityInWorld(entityitem); + return null; + } + return itemStack; + } +} diff --git a/src/com/dark/helpers/MathHelper.java b/src/com/dark/helpers/MathHelper.java new file mode 100644 index 000000000..cc1e9e09a --- /dev/null +++ b/src/com/dark/helpers/MathHelper.java @@ -0,0 +1,206 @@ +package com.dark.helpers; + +import java.util.Random; + +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.vector.Vector3; + +public class MathHelper extends net.minecraft.util.MathHelper +{ + /** Generates an array of random numbers + * + * @param random - random instance to be used + * @param maxNumber - max size of the int to use + * @param arraySize - length of the array + * @return array of random numbers */ + public static int[] generateRandomIntArray(Random random, int maxNumber, int arraySize) + { + return MathHelper.generateRandomIntArray(random, 0, maxNumber, arraySize); + } + + /** Generates an array of random numbers + * + * @param random - random instance to be used + * @param minNumber - smallest random Integer to use. Warning can lead to longer than normal + * delay in returns + * @param maxNumber - max size of the int to use + * @param arraySize - length of the array + * @return array of random numbers */ + public static int[] generateRandomIntArray(Random random, int minNumber, int maxNumber, int arraySize) + { + int[] array = new int[arraySize]; + for (int i = 0; i < array.length; i++) + { + int number = random.nextInt(maxNumber); + if (minNumber != 0) + { + while (number < minNumber) + { + number = random.nextInt(maxNumber); + } + } + array[i] = number; + } + return array; + } + + /** @param vec - vector3 that is on the sphere + * @return new Vector3(radius, inclination, azimuth) */ + public static Vector3 vecToSphereAngles(Vector3 vec) + { + double radius = Math.sqrt((vec.x * vec.x) + (vec.y * vec.y) + (vec.z * vec.z)); + double inclination = Math.acos(vec.z / radius); + double azimuth = Math.atan(vec.y / vec.z); + return new Vector3(radius, inclination, azimuth); + } + + /** Turns radius and sphere cords into a vector3 + * + * @param radius - sphere radius + * @param inclination - + * @param azimuth + * @return Vector3(x,y,z) */ + public static Vector3 sphereAnglesToVec(Double radius, Double inclination, Double azimuth) + { + double x = radius * Math.sin(inclination) * Math.cos(azimuth); + double y = radius * Math.sin(inclination) * Math.sin(azimuth); + double z = radius * Math.cos(inclination); + + return new Vector3(x, y, z); + } + + /** Clamps the angles to a min max by adding or subtracting the min max. This way it maintanes + * the change in angle in the chance it goes out of bounds */ + public static float clampAngle(float var, float min, float max) + { + while (var < min) + { + var += min; + } + while (var > max) + { + var -= max; + } + return var; + } + + public static float clamp(float var, float min, float max) + { + if (var < min) + { + return min; + } + else if (var > max) + { + return max; + } + else + { + return var; + } + } + + /** Clamps an angle to 360 degree circle */ + public static float clampAngleTo360(float var) + { + return MathHelper.clampAngle(var, 0, 360); + } + + /** Find the shortest delta change to the angle goal from the current angle */ + public static float shortestAngleTo360(float angle, float angleGoal) + { + angle = clampAngleTo360(angle); + angleGoal = clampAngleTo360(angleGoal); + + if (angle == angleGoal) + { + return 0; + } + else if (angle > angleGoal) + { + return angleGoal - angle; + } + else + { + return angle - angleGoal; + } + } + + public static double updateRotation(double from, double to, double speed) + { + from = net.minecraft.util.MathHelper.wrapAngleTo180_double(from); + to = net.minecraft.util.MathHelper.wrapAngleTo180_double(to); + double delta = Math.abs(from - to); + if (delta > 0.001f) + { + if (from > to) + { + from += (delta >= 0) ? speed : -speed; + } + else + { + from += (delta >= 0) ? -speed : speed; + } + + if (delta < speed + 0.1f) + { + from = to; + } + } + return from; + } + + public static double updateRotation(float from, float to, float speed) + { + from = net.minecraft.util.MathHelper.wrapAngleTo180_float(from); + to = net.minecraft.util.MathHelper.wrapAngleTo180_float(to); + double delta = Math.abs(from - to); + if (delta > 0.001f) + { + if (from > to) + { + from += (delta >= 0) ? speed : -speed; + } + else + { + from += (delta >= 0) ? -speed : speed; + } + + if (delta < speed + 0.1f) + { + from = to; + } + } + return from; + } + + /** gets the facing direction using the yaw angle */ + public static ForgeDirection getFacingDirectionFromAngle(float yaw) + { + float angle = net.minecraft.util.MathHelper.wrapAngleTo180_float(yaw); + if (angle >= -45 && angle <= 45) + { + return ForgeDirection.SOUTH; + } + else if (angle >= 45 && angle <= 135) + { + + return ForgeDirection.WEST; + } + else if (angle >= 135 && angle <= -135) + { + + return ForgeDirection.NORTH; + } + else + { + return ForgeDirection.EAST; + } + } + + /** gets the facing direction using the yaw angle */ + public static ForgeDirection getFacingDirectionFromAngle(double yaw) + { + return getFacingDirectionFromAngle((float) yaw); + } +} diff --git a/src/com/dark/helpers/PlayerKeyHandler.java b/src/com/dark/helpers/PlayerKeyHandler.java new file mode 100644 index 000000000..d157e1185 --- /dev/null +++ b/src/com/dark/helpers/PlayerKeyHandler.java @@ -0,0 +1,65 @@ +package com.dark.helpers; + +import java.util.EnumSet; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.settings.KeyBinding; + +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +import com.dark.network.PacketManagerKeyEvent; + +import cpw.mods.fml.common.IScheduledTickHandler; +import cpw.mods.fml.common.TickType; + +/** This class handles keys already binded to the game so to avoid creating new key bindings + * + * @author DarkGuardsman */ +public class PlayerKeyHandler implements IScheduledTickHandler +{ + + @Override + public final void tickStart(EnumSet type, Object... tickData) + { + keyTick(type, false); + } + + @Override + public final void tickEnd(EnumSet type, Object... tickData) + { + keyTick(type, true); + } + + private void keyTick(EnumSet type, boolean tickEnd) + { + for (int i = 0; i < Minecraft.getMinecraft().gameSettings.keyBindings.length; i++) + { + KeyBinding keyBinding = Minecraft.getMinecraft().gameSettings.keyBindings[i]; + int keyCode = keyBinding.keyCode; + boolean state = (keyCode < 0 ? Mouse.isButtonDown(keyCode + 100) : Keyboard.isKeyDown(keyCode)); + if (state) + { + PacketManagerKeyEvent.sendPacket(keyCode); + } + } + } + + @Override + public EnumSet ticks() + { + return EnumSet.of(TickType.CLIENT); + } + + @Override + public String getLabel() + { + return "[CoreMachine]KeyBindingCatcher"; + } + + @Override + public int nextTickSpacing() + { + return 2; + } +} diff --git a/src/com/dark/helpers/RayTraceHelper.java b/src/com/dark/helpers/RayTraceHelper.java new file mode 100644 index 000000000..18ad53a41 --- /dev/null +++ b/src/com/dark/helpers/RayTraceHelper.java @@ -0,0 +1,278 @@ +package com.dark.helpers; + +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MathHelper; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class RayTraceHelper +{ + public static MovingObjectPosition raytraceEntities_fromAnEntity(World world, Entity entity, Vec3 error, double reachDistance, boolean collisionFlag) + { + + MovingObjectPosition pickedEntity = null; + Vec3 playerPosition = Vec3.createVectorHelper(entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); + Vec3 playerLook = entity.getLookVec(); + + Vec3 playerViewOffset = Vec3.createVectorHelper(playerPosition.xCoord + playerLook.xCoord * reachDistance + error.xCoord, playerPosition.yCoord + playerLook.yCoord * reachDistance + error.yCoord, playerPosition.zCoord + playerLook.zCoord * reachDistance + error.zCoord); + + double playerBorder = 1.1 * reachDistance; + AxisAlignedBB boxToScan = entity.boundingBox.expand(playerBorder, playerBorder, playerBorder); + + List entitiesHit = world.getEntitiesWithinAABBExcludingEntity(entity, boxToScan); + double closestEntity = reachDistance; + + if (entitiesHit == null || entitiesHit.isEmpty()) + { + return null; + } + for (Entity entityHit : entitiesHit) + { + if (entityHit != null && entityHit.canBeCollidedWith() && entityHit.boundingBox != null) + { + float border = entityHit.getCollisionBorderSize(); + AxisAlignedBB aabb = entityHit.boundingBox.expand(border, border, border); + MovingObjectPosition hitMOP = aabb.calculateIntercept(playerPosition, playerViewOffset); + + if (hitMOP != null) + { + if (aabb.isVecInside(playerPosition)) + { + if (0.0D < closestEntity || closestEntity == 0.0D) + { + pickedEntity = new MovingObjectPosition(entityHit); + if (pickedEntity != null) + { + pickedEntity.hitVec = hitMOP.hitVec; + closestEntity = 0.0D; + } + } + } + else + { + double distance = playerPosition.distanceTo(hitMOP.hitVec); + + if (distance < closestEntity || closestEntity == 0.0D) + { + pickedEntity = new MovingObjectPosition(entityHit); + pickedEntity.hitVec = hitMOP.hitVec; + closestEntity = distance; + } + } + } + } + } + return pickedEntity; + } + + @SuppressWarnings("unchecked") + public static MovingObjectPosition raytraceEntities(World world, Vec3 start, Vec3 end, double range, boolean collisionFlag, Entity exclude) + { + AxisAlignedBB boxToScan = AxisAlignedBB.getBoundingBox(start.xCoord, start.yCoord, start.zCoord, end.xCoord, end.yCoord, end.zCoord); + List entitiesHit = null; + if (exclude != null) + { + entitiesHit = world.getEntitiesWithinAABBExcludingEntity(exclude, boxToScan); + } + else + { + entitiesHit = world.getEntitiesWithinAABB(Entity.class, boxToScan); + } + MovingObjectPosition pickedEntity = null; + double closestEntity = range; + + if (entitiesHit == null || entitiesHit.isEmpty()) + { + return null; + } + for (Entity entityHit : entitiesHit) + { + if (entityHit != null && entityHit.canBeCollidedWith() && entityHit.boundingBox != null) + { + float border = entityHit.getCollisionBorderSize(); + AxisAlignedBB aabb = entityHit.boundingBox.expand(border, border, border); + MovingObjectPosition hitMOP = aabb.calculateIntercept(start, end); + + if (hitMOP != null) + { + if (aabb.isVecInside(start)) + { + if (0.0D < closestEntity || closestEntity == 0.0D) + { + pickedEntity = new MovingObjectPosition(entityHit); + if (pickedEntity != null) + { + pickedEntity.hitVec = hitMOP.hitVec; + closestEntity = 0.0D; + } + } + } + else + { + double distance = start.distanceTo(hitMOP.hitVec); + + if (distance < closestEntity || closestEntity == 0.0D) + { + pickedEntity = new MovingObjectPosition(entityHit); + pickedEntity.hitVec = hitMOP.hitVec; + closestEntity = distance; + } + } + } + } + } + return pickedEntity; + } + + public static MovingObjectPosition raytraceBlocks_fromAnEntity(World world, Entity entity, Vec3 error, double reachDistance, boolean collisionFlag) + { + Vec3 playerPosition = Vec3.createVectorHelper(entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); + Vec3 playerLook = entity.getLookVec(); + + Vec3 playerViewOffset = Vec3.createVectorHelper(playerPosition.xCoord + playerLook.xCoord * reachDistance + error.xCoord, playerPosition.yCoord + playerLook.yCoord * reachDistance + error.yCoord, playerPosition.zCoord + playerLook.zCoord * reachDistance + error.zCoord); + return raytraceBlocks(world, playerPosition, playerViewOffset, collisionFlag); + } + + public static MovingObjectPosition raytraceBlocks_fromAnEntity(World world, Entity entity, double reachDistance, boolean collisionFlag) + { + Vec3 playerPosition = Vec3.createVectorHelper(entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); + Vec3 playerLook = entity.getLookVec(); + + Vec3 playerViewOffset = Vec3.createVectorHelper(playerPosition.xCoord + playerLook.xCoord * reachDistance, playerPosition.yCoord + playerLook.yCoord * reachDistance, playerPosition.zCoord + playerLook.zCoord * reachDistance); + return raytraceBlocks(world, playerPosition, playerViewOffset, collisionFlag); + } + + public static MovingObjectPosition raytraceBlocks(World world, Vec3 start, Vec3 end, boolean collisionFlag) + { + return world.rayTraceBlocks_do_do(start, end, collisionFlag, !collisionFlag); + } + + public static Vector3 getPosFromRotation(final Vector3 center, float reachDistance, float yaw, float pitch) + { + return center.clone().translate(getLook(yaw, pitch, 1.0F).scale(reachDistance)); + } + + /** Does a ray trace from start to end vector + * + * @param world - world to do the ray trace in + * @param start - starting point clear of any collisions from its caster + * @param end - end point + * @param collisionFlag + * @return */ + public static MovingObjectPosition ray_trace_do(final World world, final Vec3 start, final Vec3 end, final float range, boolean collisionFlag) + { + MovingObjectPosition hitBlock = raytraceBlocks(world, new Vector3(start).toVec3(), new Vector3(end).toVec3(), collisionFlag); + MovingObjectPosition hitEntity = raytraceEntities(world, start, end, range, collisionFlag, null); + if (hitEntity == null) + { + return hitBlock; + } + else if (hitBlock == null) + { + return hitEntity; + } + else + { + if (hitEntity.hitVec.distanceTo(start) < hitBlock.hitVec.distanceTo(start)) + { + return hitEntity; + } + else + { + return hitBlock; + } + } + } + + /** Does a ray trace from an entities look angle out to a set distance from the entity + * + * @param entity - entity who's view angles will be used for finding the start and end points of + * the ray + * @param e - error(or adjustments) to add to it if this ray is being used for weapon + * calculations + * @param reachDistance - distance the ray will extend to + * @param collisionFlag + * @return */ + public static MovingObjectPosition do_rayTraceFromEntity(Entity entity, Vec3 e, double reachDistance, boolean collisionFlag) + { + + MovingObjectPosition hitBlock = raytraceBlocks_fromAnEntity(entity.worldObj, entity, e, reachDistance, collisionFlag); + MovingObjectPosition hitEntity = raytraceEntities_fromAnEntity(entity.worldObj, entity, e, reachDistance, collisionFlag); + if (hitEntity == null) + { + return hitBlock; + } + else if (hitBlock == null) + { + return hitEntity; + } + else + { + Vec3 playerPosition = Vec3.createVectorHelper(entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); + if (hitEntity.hitVec.distanceTo(playerPosition) < hitBlock.hitVec.distanceTo(playerPosition)) + { + return hitEntity; + } + else + { + return hitBlock; + } + } + } + + public static Vec3 getLook(Entity entity, float par1) + { + float f1; + float f2; + float f3; + float f4; + + if (par1 == 1.0F) + { + f1 = MathHelper.cos(-entity.rotationYaw * 0.017453292F - (float) Math.PI); + f2 = MathHelper.sin(-entity.rotationYaw * 0.017453292F - (float) Math.PI); + f3 = -MathHelper.cos(-entity.rotationPitch * 0.017453292F); + f4 = MathHelper.sin(-entity.rotationPitch * 0.017453292F); + return entity.worldObj.getWorldVec3Pool().getVecFromPool((f2 * f3), f4, (f1 * f3)); + } + else + { + f1 = entity.prevRotationPitch + (entity.rotationPitch - entity.prevRotationPitch) * par1; + f2 = entity.prevRotationYaw + (entity.rotationYaw - entity.prevRotationYaw) * par1; + f3 = MathHelper.cos(-f2 * 0.017453292F - (float) Math.PI); + f4 = MathHelper.sin(-f2 * 0.017453292F - (float) Math.PI); + float f5 = -MathHelper.cos(-f1 * 0.017453292F); + float f6 = MathHelper.sin(-f1 * 0.017453292F); + return entity.worldObj.getWorldVec3Pool().getVecFromPool((f4 * f5), f6, (f3 * f5)); + } + } + + public static Vector3 getLook(float yaw, float pitch, float distance) + { + float f1, f2, f3, f4; + + if (distance == 1.0F) + { + f1 = MathHelper.cos(-yaw * 0.017453292F - (float) Math.PI); + f2 = MathHelper.sin(-yaw * 0.017453292F - (float) Math.PI); + f3 = -MathHelper.cos(-pitch * 0.017453292F); + f4 = MathHelper.sin(-pitch * 0.017453292F); + return new Vector3((f2 * f3), f4, (f1 * f3)); + } + else + { + f1 = pitch * distance; + f2 = yaw * distance; + f3 = MathHelper.cos(-f2 * 0.017453292F - (float) Math.PI); + f4 = MathHelper.sin(-f2 * 0.017453292F - (float) Math.PI); + float f5 = -MathHelper.cos(-f1 * 0.017453292F); + float f6 = MathHelper.sin(-f1 * 0.017453292F); + return new Vector3((f4 * f5), f6, (f3 * f5)); + } + } +} diff --git a/src/com/dark/interfaces/IControlReceiver.java b/src/com/dark/interfaces/IControlReceiver.java new file mode 100644 index 000000000..9553bd535 --- /dev/null +++ b/src/com/dark/interfaces/IControlReceiver.java @@ -0,0 +1,16 @@ +package com.dark.interfaces; + +import net.minecraft.entity.player.EntityPlayer; + +/** Applied to objects that can be control by the player using the keyboard + * + * @author DarkGuardsman */ +public interface IControlReceiver +{ + /** Called when the player presses a key + * + * @param player - client player + * @param character - character code + * @param keycode - keyboard code */ + public boolean keyTyped(EntityPlayer player, int keycode); +} diff --git a/src/com/dark/interfaces/IExtendedStorage.java b/src/com/dark/interfaces/IExtendedStorage.java new file mode 100644 index 000000000..5a5021872 --- /dev/null +++ b/src/com/dark/interfaces/IExtendedStorage.java @@ -0,0 +1,11 @@ +package com.dark.interfaces; + +import net.minecraft.item.ItemStack; + +/** Applied to blocks that store items in stacks above 64 and as one large collective of items + * + * @author DarkGuardsman */ +public interface IExtendedStorage +{ + public ItemStack addStackToStorage(ItemStack stack); +} diff --git a/src/com/dark/interfaces/IPowerLess.java b/src/com/dark/interfaces/IPowerLess.java new file mode 100644 index 000000000..4c7819aa4 --- /dev/null +++ b/src/com/dark/interfaces/IPowerLess.java @@ -0,0 +1,14 @@ +package com.dark.interfaces; + +/** Applied to devices that have the option to run without power. Normally this option is only shown + * to creative mode players + * + * @author DarkGuardsman */ +public interface IPowerLess +{ + /** Should this run without power */ + public boolean runPowerLess(); + + /** Set if this should run powerless */ + public void setPowerLess(boolean bool); +} diff --git a/src/com/dark/network/IPacketManager.java b/src/com/dark/network/IPacketManager.java new file mode 100644 index 000000000..4b596b7cc --- /dev/null +++ b/src/com/dark/network/IPacketManager.java @@ -0,0 +1,17 @@ +package com.dark.network; + +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet250CustomPayload; + +import com.google.common.io.ByteArrayDataInput; + +import cpw.mods.fml.common.network.Player; + +public interface IPacketManager +{ + public int getID(); + + public void setID(int maxID); + + public void handlePacket(INetworkManager network, Packet250CustomPayload packet, Player player, ByteArrayDataInput data); +} diff --git a/src/com/dark/network/ISimplePacketReceiver.java b/src/com/dark/network/ISimplePacketReceiver.java new file mode 100644 index 000000000..495226ab2 --- /dev/null +++ b/src/com/dark/network/ISimplePacketReceiver.java @@ -0,0 +1,20 @@ +package com.dark.network; + +import com.google.common.io.ByteArrayDataInput; + +import cpw.mods.fml.common.network.Player; + +/** Simplified version of IPackerReceiver for tiles that only need a packet ID, data, and player + * Reference + * + * @author DarkGuardsman */ +public interface ISimplePacketReceiver +{ + /** Simplified version of IPacketReceiver's HandlePacketData + * + * @param id - packet ID as a string + * @param data - data from the packet, after location has been read + * @param player - player that the packet was sent to or came from + * @return true if the packet was used */ + public boolean simplePacket(String id, ByteArrayDataInput data, Player player); +} diff --git a/src/com/dark/network/PacketDataWatcher.java b/src/com/dark/network/PacketDataWatcher.java new file mode 100644 index 000000000..182b90a96 --- /dev/null +++ b/src/com/dark/network/PacketDataWatcher.java @@ -0,0 +1,79 @@ +package com.dark.network; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import net.minecraft.item.Item; +import net.minecraft.network.packet.Packet250CustomPayload; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatMessageComponent; +import net.minecraft.world.World; +import net.minecraftforge.event.ForgeSubscribe; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; +import universalelectricity.core.vector.Vector3; + +import com.builtbroken.common.Pair; + +public class PacketDataWatcher +{ + HashMap, List> packetSizes = new HashMap, List>(); + + public static PacketDataWatcher instance = new PacketDataWatcher(); + + public boolean enable = false; + + public void onPacketData(TileEntity entity, Packet250CustomPayload data, long t) + { + if (entity != null && enable) + { + Pair location = new Pair(entity.worldObj, new Vector3(entity)); + List l = this.packetSizes.get(location); + if (l == null) + { + l = new ArrayList(); + } + l.add(data.getPacketSize()); + this.packetSizes.put(location, l); + } + } + + @ForgeSubscribe + public void playerRightClickEvent(PlayerInteractEvent event) + { + if (event.action == Action.RIGHT_CLICK_BLOCK && event.entityPlayer.capabilities.isCreativeMode && event.entityPlayer.getHeldItem() != null && event.entityPlayer.getHeldItem().itemID == Item.blazeRod.itemID) + { + if (event.entityPlayer.worldObj.isRemote) + { + if (event.entityPlayer.isSneaking()) + { + this.enable = !this.enable; + event.entityPlayer.sendChatToPlayer(ChatMessageComponent.createFromText("PacketWatcher is now " + (this.enable ? "Enabled. Now caching packet sizes." : "Disabled. Data cache has been cleared"))); + this.packetSizes.clear(); + } + else + { + TileEntity ent = event.entityPlayer.worldObj.getBlockTileEntity(event.x, event.y, event.z); + if (ent != null) + { + System.out.println("Entity Check"); + Pair location = new Pair(ent.worldObj, new Vector3(ent)); + int p = 0, a = 0; + if (this.packetSizes.get(location) != null) + { + for (int i : this.packetSizes.get(location)) + { + a += i; + } + p = this.packetSizes.get(location).size(); + a /= (p > 0 ? p : 1); + } + event.entityPlayer.sendChatToPlayer(ChatMessageComponent.createFromText("AveragePacketSize: " + a + "bits for " + p + " packets")); + + } + } + } + } + } +} diff --git a/src/com/dark/network/PacketHandler.java b/src/com/dark/network/PacketHandler.java new file mode 100644 index 000000000..a34ab4137 --- /dev/null +++ b/src/com/dark/network/PacketHandler.java @@ -0,0 +1,346 @@ +package com.dark.network; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.Packet250CustomPayload; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.network.IPacketReceiver; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; + +import cpw.mods.fml.common.network.IPacketHandler; +import cpw.mods.fml.common.network.PacketDispatcher; +import cpw.mods.fml.common.network.Player; +import dark.machines.PacketManagerEffects; + +/** Packet manager based off the PacketManager from UE created by Calclavia. However changed so it + * can easily be extended without changing the base handler file. Instead of changing the base file + * manager can be registered to the handle that pickup on ids and then handle there own data from + * those ids. This lets new and complex handling to be created without many overlap or long methods + * in the packet handler + * + * @author DarkGuardsman */ +public class PacketHandler implements IPacketHandler, IPacketReceiver +{ + protected static PacketHandler instance; + + public static HashMap packetTypes = new HashMap(); + + public static PacketManagerTile tile = new PacketManagerTile(); + public static PacketManagerEffects effects = new PacketManagerEffects(); + + public static int maxID = 0; + static + { + registerManager(new PacketManagerTile()); + registerManager(new PacketManagerEffects()); + registerManager(PacketManagerKeyEvent.instance()); + registerManager(new PacketManagerEntity()); + } + + public static void registerManager(IPacketManager manager) + { + if (manager != null) + { + packetTypes.put(maxID, manager); + manager.setID(maxID); + maxID++; + + } + } + + public static IPacketManager getManager(int id) + { + return packetTypes.get(id); + } + + public static PacketHandler instance() + { + if (instance == null) + { + instance = new PacketHandler(); + } + return instance; + } + + /** Writes a compressed NBTTagCompound to the OutputStream */ + public void writeNBTTagCompound(NBTTagCompound tag, DataOutputStream dataStream) throws IOException + { + if (tag == null) + { + dataStream.writeShort(-1); + } + else + { + byte[] var2 = CompressedStreamTools.compress(tag); + dataStream.writeShort((short) var2.length); + dataStream.write(var2); + } + } + + public void writeNBTTagCompound(NBTTagCompound tag, ByteArrayDataOutput dataStream) throws IOException + { + if (tag == null) + { + dataStream.writeShort(-1); + } + else + { + byte[] var2 = CompressedStreamTools.compress(tag); + dataStream.writeShort((short) var2.length); + dataStream.write(var2); + } + } + + /** Reads a compressed NBTTagCompount in a ByteStream. */ + public NBTTagCompound readNBTTagCompound(DataInputStream dataStream) throws IOException + { + short var1 = dataStream.readShort(); + + if (var1 < 0) + { + return null; + } + else + { + byte[] var2 = new byte[var1]; + dataStream.readFully(var2); + return CompressedStreamTools.decompress(var2); + } + } + + public NBTTagCompound readNBTTagCompound(ByteArrayDataInput dataStream) throws IOException + { + short var1 = dataStream.readShort(); + + if (var1 < 0) + { + return null; + } + else + { + byte[] var2 = new byte[var1]; + dataStream.readFully(var2); + return CompressedStreamTools.decompress(var2); + } + } + + public static Vector3 readVector3(ByteArrayDataInput data) throws IOException + { + return new Vector3(data.readDouble(), data.readDouble(), data.readDouble()); + } + + @SuppressWarnings("resource") + public Packet getPacketWithID(String channelName, int id, Object... sendData) + { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + + try + { + data.writeInt(id); + data = encodeDataStream(data, sendData); + + Packet250CustomPayload packet = new Packet250CustomPayload(); + packet.channel = channelName; + packet.data = bytes.toByteArray(); + packet.length = packet.data.length; + + return packet; + } + catch (IOException e) + { + System.out.println("Failed to create packet."); + e.printStackTrace(); + } + + return null; + } + + public Packet getPacket(String channelName, Object... sendData) + { + return getPacketWithID(channelName, -1, sendData); + } + + /** Gets a packet for the tile entity. + * + * @return */ + @SuppressWarnings("resource") + public Packet getTilePacket(String channelName, TileEntity sender, Object... sendData) + { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + + try + { + data.writeInt(PacketHandler.tile.getID()); + + data.writeInt(sender.xCoord); + data.writeInt(sender.yCoord); + data.writeInt(sender.zCoord); + data = encodeDataStream(data, sendData); + + Packet250CustomPayload packet = new Packet250CustomPayload(); + packet.channel = channelName; + packet.data = bytes.toByteArray(); + packet.length = packet.data.length; + + return packet; + } + catch (IOException e) + { + System.out.println("Failed to create packet."); + e.printStackTrace(); + } + + return null; + } + + /** Sends packets to clients around a specific coordinate. A wrapper using Vector3. See + * {@PacketDispatcher} for detailed information. */ + public void sendPacketToClients(Packet packet, World worldObj, Vector3 position, double range) + { + try + { + PacketDispatcher.sendPacketToAllAround(position.x, position.y, position.z, range, worldObj.provider.dimensionId, packet); + } + catch (Exception e) + { + System.out.println("Sending packet to client failed."); + e.printStackTrace(); + } + } + + /** Sends a packet to all the clients on this server. */ + public void sendPacketToClients(Packet packet, World worldObj) + { + try + { + PacketDispatcher.sendPacketToAllInDimension(packet, worldObj.provider.dimensionId); + } + catch (Exception e) + { + System.out.println("Sending packet to client failed."); + e.printStackTrace(); + } + } + + public void sendPacketToClients(Packet packet) + { + try + { + PacketDispatcher.sendPacketToAllPlayers(packet); + } + catch (Exception e) + { + System.out.println("Sending packet to client failed."); + e.printStackTrace(); + } + } + + public DataOutputStream encodeDataStream(DataOutputStream data, Object... sendData) + { + try + { + for (Object dataValue : sendData) + { + if (dataValue instanceof Vector3) + { + data.writeDouble(((Vector3) dataValue).x); + data.writeDouble(((Vector3) dataValue).y); + data.writeDouble(((Vector3) dataValue).z); + } + else if (dataValue instanceof Integer) + { + data.writeInt((Integer) dataValue); + } + else if (dataValue instanceof Float) + { + data.writeFloat((Float) dataValue); + } + else if (dataValue instanceof Double) + { + data.writeDouble((Double) dataValue); + } + else if (dataValue instanceof Byte) + { + data.writeByte((Byte) dataValue); + } + else if (dataValue instanceof Boolean) + { + data.writeBoolean((Boolean) dataValue); + } + else if (dataValue instanceof String) + { + data.writeUTF((String) dataValue); + } + else if (dataValue instanceof Short) + { + data.writeShort((Short) dataValue); + } + else if (dataValue instanceof Long) + { + data.writeLong((Long) dataValue); + } + else if (dataValue instanceof NBTTagCompound) + { + writeNBTTagCompound((NBTTagCompound) dataValue, data); + } + } + + return data; + } + catch (IOException e) + { + System.out.println("Packet data encoding failed."); + e.printStackTrace(); + } + + return data; + } + + @Override + public void onPacketData(INetworkManager network, Packet250CustomPayload packet, Player player) + { + try + { + ByteArrayDataInput data = ByteStreams.newDataInput(packet.data); + + int packetTypeID = data.readInt(); + + IPacketManager packetType = getManager(packetTypeID); + + if (packetType != null) + { + packetType.handlePacket(network, packet, player, data); + } + else + { + this.handlePacketData(network, packetTypeID, packet, ((EntityPlayer) player), data); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + @Override + public void handlePacketData(INetworkManager network, int packetType, Packet250CustomPayload packet, EntityPlayer player, ByteArrayDataInput dataStream) + { + + } +} \ No newline at end of file diff --git a/src/com/dark/network/PacketManagerEntity.java b/src/com/dark/network/PacketManagerEntity.java new file mode 100644 index 000000000..05105679b --- /dev/null +++ b/src/com/dark/network/PacketManagerEntity.java @@ -0,0 +1,78 @@ +package com.dark.network; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.Packet250CustomPayload; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +import com.dark.DarkCore; +import com.google.common.io.ByteArrayDataInput; + +import cpw.mods.fml.common.network.PacketDispatcher; +import cpw.mods.fml.common.network.Player; + +public class PacketManagerEntity implements IPacketManager +{ + static int packetID = 0; + + @Override + public int getID() + { + return packetID; + } + + @Override + public void setID(int maxID) + { + packetID = maxID; + } + + @Override + public void handlePacket(INetworkManager network, Packet250CustomPayload packet, Player player, ByteArrayDataInput data) + { + try + { + int entityId = data.readInt(); + + World world = ((EntityPlayer) player).worldObj; + if (world != null) + { + Entity entity = world.getEntityByID(entityId); + if (entity instanceof ISimplePacketReceiver) + { + String id = data.readUTF(); + ((ISimplePacketReceiver) entity).simplePacket(id, data, player); + } + } + } + catch (Exception e) + { + System.out.println("[CoreMachine] Error reading packet for an entity"); + e.printStackTrace(); + } + + } + + public static void sendEntityUpdatePacket(Entity entity, boolean toServer, String id, Object... objects) + { + Object[] obj = new Object[2 + objects.length]; + obj[0] = entity.entityId; + obj[1] = id; + for (int i = 0; i < objects.length; i++) + { + obj[2 + i] = objects[i]; + } + Packet packet = PacketHandler.instance().getPacketWithID(DarkCore.CHANNEL, packetID, obj); + if (toServer) + { + PacketDispatcher.sendPacketToServer(packet); + } + else + { + PacketHandler.instance().sendPacketToClients(packet, entity.worldObj, new Vector3(entity), 64); + } + } +} diff --git a/src/com/dark/network/PacketManagerKeyEvent.java b/src/com/dark/network/PacketManagerKeyEvent.java new file mode 100644 index 000000000..08aba16eb --- /dev/null +++ b/src/com/dark/network/PacketManagerKeyEvent.java @@ -0,0 +1,84 @@ +package com.dark.network; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet250CustomPayload; + +import com.dark.DarkCore; +import com.dark.interfaces.IControlReceiver; +import com.google.common.io.ByteArrayDataInput; + +import cpw.mods.fml.common.network.PacketDispatcher; +import cpw.mods.fml.common.network.Player; + +public class PacketManagerKeyEvent implements IPacketManager +{ + static int packetID = 0; + + private static PacketManagerKeyEvent instance; + + private List receivers = new ArrayList(); + + public static PacketManagerKeyEvent instance() + { + if (instance == null) + { + instance = new PacketManagerKeyEvent(); + } + return instance; + } + + public void register(IControlReceiver rec) + { + if (!this.receivers.contains(rec)) + { + this.receivers.add(rec); + } + } + + public void remove(IControlReceiver rec) + { + this.receivers.remove(rec); + } + + @Override + public int getID() + { + return packetID; + } + + @Override + public void setID(int maxID) + { + packetID = maxID; + } + + @Override + public void handlePacket(INetworkManager network, Packet250CustomPayload packet, Player player, ByteArrayDataInput data) + { + try + { + int key = data.readInt(); + for (IControlReceiver receiver : instance().receivers) + { + if (receiver.keyTyped((EntityPlayer) player, key)) + { + break; + } + } + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + + public static void sendPacket(int key) + { + PacketDispatcher.sendPacketToServer(PacketHandler.instance().getPacketWithID(DarkCore.CHANNEL, PacketManagerKeyEvent.packetID, key)); + } +} diff --git a/src/com/dark/network/PacketManagerTile.java b/src/com/dark/network/PacketManagerTile.java new file mode 100644 index 000000000..172738827 --- /dev/null +++ b/src/com/dark/network/PacketManagerTile.java @@ -0,0 +1,67 @@ +package com.dark.network; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet250CustomPayload; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import universalelectricity.prefab.network.IPacketReceiver; + +import com.google.common.io.ByteArrayDataInput; + +import cpw.mods.fml.common.network.Player; + +public class PacketManagerTile implements IPacketManager +{ + static int packetID = 0; + + @Override + public int getID() + { + return packetID; + } + + @Override + public void setID(int maxID) + { + packetID = maxID; + } + + @Override + public void handlePacket(INetworkManager network, Packet250CustomPayload packet, Player player, ByteArrayDataInput data) + { + try + { + int x = data.readInt(); + int y = data.readInt(); + int z = data.readInt(); + + World world = ((EntityPlayer) player).worldObj; + + if (world != null) + { + TileEntity tileEntity = world.getBlockTileEntity(x, y, z); + + if (tileEntity != null) + { + PacketDataWatcher.instance.onPacketData(tileEntity, packet, System.currentTimeMillis()); + if (tileEntity instanceof ISimplePacketReceiver) + { + String pId = data.readUTF(); + ((ISimplePacketReceiver) tileEntity).simplePacket(pId, data, player); + } + if (tileEntity instanceof IPacketReceiver) + { + ((IPacketReceiver) tileEntity).handlePacketData(network, 0, packet, ((EntityPlayer) player), data); + } + } + } + } + catch (Exception e) + { + System.out.println("[CoreMachine] Error reading packet at tile packet manager"); + e.printStackTrace(); + } + + } +} diff --git a/src/com/dark/prefab/ItemBasic.java b/src/com/dark/prefab/ItemBasic.java new file mode 100644 index 000000000..2b5a8e8a2 --- /dev/null +++ b/src/com/dark/prefab/ItemBasic.java @@ -0,0 +1,20 @@ +package com.dark.prefab; + +import net.minecraft.item.Item; +import net.minecraftforge.common.Configuration; + +import com.dark.DarkCore; + +public class ItemBasic extends Item +{ + public ItemBasic(int itemID, String name, Configuration config) + { + super(config.getItem(name, itemID).getInt()); + this.setUnlocalizedName(name); + } + + public ItemBasic(String name, Configuration config) + { + this(DarkCore.getNextID(), name, config); + } +} diff --git a/src/com/dark/prefab/ItemBlockHolder.java b/src/com/dark/prefab/ItemBlockHolder.java new file mode 100644 index 000000000..8e74fcf6c --- /dev/null +++ b/src/com/dark/prefab/ItemBlockHolder.java @@ -0,0 +1,30 @@ +package com.dark.prefab; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +/** Simple itemBlock class for quick use with a block + * + * @author Darkguardsman */ +public class ItemBlockHolder extends ItemBlock +{ + public ItemBlockHolder(int id) + { + super(id); + this.setMaxDamage(0); + this.setHasSubtypes(true); + } + + @Override + public int getMetadata(int damage) + { + return damage; + } + + @Override + public String getUnlocalizedName(ItemStack itemStack) + { + return Block.blocksList[this.getBlockID()].getUnlocalizedName() + "." + itemStack.getItemDamage(); + } +} diff --git a/src/com/dark/prefab/tile/network/NetworkItemSupply.java b/src/com/dark/prefab/tile/network/NetworkItemSupply.java new file mode 100644 index 000000000..97c2eef69 --- /dev/null +++ b/src/com/dark/prefab/tile/network/NetworkItemSupply.java @@ -0,0 +1,120 @@ +package com.dark.prefab.tile.network; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.vector.Vector3; + +import com.builtbroken.common.Pair; +import com.dark.tile.network.IMotionPath; +import com.dark.tile.network.INetworkPart; + + +/** Class that acts like the redpower pipes system. Each item is marked with a destination. Intended + * use it to improve the assembly line network + * + * @author DarkGuardsman */ +public class NetworkItemSupply extends NetworkTileEntities +{ + List> trackingList = new ArrayList>(); + List ignoreList = new ArrayList(); + /** Same as valid directions from forge direction enum but Unknown was added so that is gets + * check and checked first */ + public static final ForgeDirection[] VALID_DIRECTIONS = { ForgeDirection.UNKNOWN, ForgeDirection.DOWN, ForgeDirection.UP, ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST }; + + public NetworkItemSupply(INetworkPart... parts) + { + super(parts); + } + + @Override + public void updateTick() + { + Iterator> it = trackingList.iterator(); + while (it.hasNext()) + { + Pair entry = it.next(); + if (entry.left() == null || !this.isOnPath(entry.left())) + { + it.remove(); + } + else + { + if (entry.right() == null) + { + entry.setRight(new Vector3(entry.left())); + } + else + { + entry.left().setPosition(entry.right().x, entry.right().y, entry.right().z); + } + } + } + + } + + @Override + public int getUpdateRate() + { + return 1; + } + + /** Remove an entity from the tracking list */ + public void removeEntity(Entity entity) + { + this.trackingList.remove(entity); + } + + /** Ignores an entity so that is can be controlled by something else for a while. Eg armbots, and + * drones */ + public void ignoreEntity(Entity entity) + { + if (!this.ignoreList.contains(entity)) + { + this.ignoreList.add(entity); + } + } + + /** Add and entity to the tracking list */ + public void addEntity(Entity entity) + { + if (!this.trackingList.contains(entity)) + { + this.trackingList.add(new Pair(entity, new Vector3(entity))); + } + } + + public boolean isTrackingEntity(Entity entity) + { + return this.trackingList.contains(entity); + } + + public boolean isOnPath(Entity entity) + { + if (entity != null) + { + Vector3 ent = new Vector3(entity); + //Check all directions including the current position of the entity + for (ForgeDirection direction : NetworkItemSupply.VALID_DIRECTIONS) + { + TileEntity a = ent.clone().modifyPositionFromSide(direction).getTileEntity(entity.worldObj); + if (a instanceof IMotionPath && ((IMotionPath) a).canMoveEntity(entity) && this.networkMembers.contains(a)) + { + return true; + } + } + } + return false; + } + + @Override + public boolean isValidMember(INetworkPart part) + { + return super.isValidMember(part) && part instanceof IMotionPath; + } + +} diff --git a/src/com/dark/prefab/tile/network/NetworkPathFinder.java b/src/com/dark/prefab/tile/network/NetworkPathFinder.java new file mode 100644 index 000000000..c01b86bf2 --- /dev/null +++ b/src/com/dark/prefab/tile/network/NetworkPathFinder.java @@ -0,0 +1,54 @@ +package com.dark.prefab.tile.network; + +import java.util.HashSet; +import java.util.Set; + +import com.dark.tile.network.INetworkPart; + + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import universalelectricity.core.path.IPathCallBack; +import universalelectricity.core.path.Pathfinder; +import universalelectricity.core.vector.Vector3; + +/** Check if a conductor connects with another. */ +public class NetworkPathFinder extends Pathfinder +{ + public NetworkPathFinder(final World world, final INetworkPart targetPoint, final INetworkPart... ignoredTiles) + { + super(new IPathCallBack() + { + @Override + public Set getConnectedNodes(Pathfinder finder, Vector3 currentNode) + { + Set neighbors = new HashSet(); + TileEntity tile = currentNode.getTileEntity(world); + if (tile instanceof INetworkPart) + { + for (TileEntity ent : ((INetworkPart) tile).getNetworkConnections()) + { + if (ent instanceof INetworkPart) + { + neighbors.add(new Vector3(ent)); + } + } + } + + return neighbors; + } + + @Override + public boolean onSearch(Pathfinder finder, Vector3 node) + { + if (node.getTileEntity(world) == targetPoint) + { + finder.results.add(node); + return true; + } + + return false; + } + }); + } +} diff --git a/src/com/dark/prefab/tile/network/NetworkResourceSupply.java b/src/com/dark/prefab/tile/network/NetworkResourceSupply.java new file mode 100644 index 000000000..8287f89b7 --- /dev/null +++ b/src/com/dark/prefab/tile/network/NetworkResourceSupply.java @@ -0,0 +1,31 @@ +package com.dark.prefab.tile.network; + +import java.util.HashMap; +import java.util.List; + +import com.dark.tile.network.INetworkPart; + + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; + +/** Network that supplies resources to tiles that demand a set resource + * + * @param C - Storage class used to handle what the network transports + * @param I - Base acceptor class + * @author DarkGuardsman */ +public class NetworkResourceSupply extends NetworkTileEntities +{ + protected C storage; + protected HashMap> acceptors = new HashMap(); + + public NetworkResourceSupply(INetworkPart... parts) + { + super(parts); + } + + public boolean isValidAcceptor(TileEntity entity) + { + return entity != null && !entity.isInvalid(); + } +} diff --git a/src/com/dark/prefab/tile/network/NetworkSharedPower.java b/src/com/dark/prefab/tile/network/NetworkSharedPower.java new file mode 100644 index 000000000..b051ef734 --- /dev/null +++ b/src/com/dark/prefab/tile/network/NetworkSharedPower.java @@ -0,0 +1,182 @@ +package com.dark.prefab.tile.network; + +import com.dark.interfaces.IPowerLess; +import com.dark.tile.network.INetworkEnergyPart; +import com.dark.tile.network.INetworkPart; + +import net.minecraft.tileentity.TileEntity; +import universalelectricity.core.block.IElectricalStorage; +import universalelectricity.core.electricity.ElectricityPack; + +/** Used for tile networks that only need to share power or act like a group battery that doesn't + * store power on world save + * + * @author DarkGuardsman */ +public class NetworkSharedPower extends NetworkTileEntities implements IElectricalStorage, IPowerLess +{ + private float energy, energyMax; + private boolean runPowerLess; + + public NetworkSharedPower(INetworkPart... parts) + { + super(parts); + } + + @Override + public boolean isValidMember(INetworkPart part) + { + return super.isValidMember(part) && part instanceof INetworkEnergyPart; + } + + public float receiveElectricity(TileEntity source, float power, boolean doFill) + { + if (!this.runPowerLess && this.networkMembers.contains(source)) + { + return this.receiveElectricity(power, doFill); + } + return 0; + } + + public float receiveElectricity(ElectricityPack receive, boolean doReceive) + { + if (receive != null) + { + float prevEnergyStored = this.getEnergyStored(); + float newStoredEnergy = Math.min(this.getEnergyStored() + receive.getWatts(), this.getMaxEnergyStored()); + + if (doReceive) + { + this.setEnergyStored(newStoredEnergy); + } + + return Math.max(newStoredEnergy - prevEnergyStored, 0); + } + return 0; + } + + public float receiveElectricity(float energy, boolean doReceive) + { + return this.receiveElectricity(ElectricityPack.getFromWatts(energy, .120f), doReceive); + } + + public boolean drainPower(TileEntity source, float power, boolean doDrain) + { + if (this.networkMembers.contains(source) && (this.getEnergyStored() >= power || this.runPowerLess)) + { + if (doDrain && !this.runPowerLess) + { + this.setEnergyStored(this.getEnergyStored() - power); + } + return true; + } + return false; + } + + @Override + public void cleanUpMembers() + { + super.cleanUpMembers(); + boolean set = false; + this.energyMax = 0; + for (INetworkPart part : this.networkMembers) + { + if (!set && part instanceof IPowerLess && ((IPowerLess) part).runPowerLess()) + { + this.setPowerLess(((IPowerLess) part).runPowerLess()); + set = true; + } + if (part instanceof INetworkEnergyPart) + { + this.energyMax += ((INetworkEnergyPart) part).getPartMaxEnergy(); + } + } + + } + + @Override + public boolean runPowerLess() + { + return this.runPowerLess; + } + + @Override + public void setPowerLess(boolean bool) + { + this.runPowerLess = bool; + for (INetworkPart part : this.networkMembers) + { + if (part instanceof IPowerLess) + { + ((IPowerLess) part).setPowerLess(bool); + } + + } + } + + @Override + public void setEnergyStored(float energy) + { + this.energy = energy; + if (this.energy > this.getMaxEnergyStored()) + { + this.energy = this.getMaxEnergyStored(); + } + } + + @Override + public float getEnergyStored() + { + if (this.energy < 0) + { + this.energy = 0; + } + return this.energy; + } + + @Override + public float getMaxEnergyStored() + { + if (this.energyMax < 0) + { + this.energyMax = Math.abs(this.energyMax); + } + return this.energyMax; + } + + /** Space left to store more energy */ + public float getEnergySpace() + { + return Math.max(this.getMaxEnergyStored() - this.getEnergyStored(), 0); + } + + @Override + public void save() + { + this.cleanUpMembers(); + float energyRemaining = this.getEnergyStored(); + for (INetworkPart part : this.getMembers()) + { + float watts = energyRemaining / this.getMembers().size(); + if (part instanceof INetworkEnergyPart) + { + ((INetworkEnergyPart) part).setEnergyStored(Math.min(watts, ((INetworkEnergyPart) part).getMaxEnergyStored())); + energyRemaining -= Math.min(watts, ((INetworkEnergyPart) part).getMaxEnergyStored()); + } + } + } + + @Override + public void load() + { + this.setEnergyStored(0); + this.cleanUpMembers(); + for (INetworkPart part : this.getMembers()) + { + if (part instanceof INetworkEnergyPart) + { + this.setEnergyStored(this.getEnergyStored() + ((INetworkEnergyPart) part).getPartEnergy()); + } + } + } + +} diff --git a/src/com/dark/prefab/tile/network/NetworkTileEntities.java b/src/com/dark/prefab/tile/network/NetworkTileEntities.java new file mode 100644 index 000000000..0504d8007 --- /dev/null +++ b/src/com/dark/prefab/tile/network/NetworkTileEntities.java @@ -0,0 +1,280 @@ +package com.dark.prefab.tile.network; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.dark.tile.network.INetworkPart; +import com.dark.tile.network.ITileNetwork; + + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.path.Pathfinder; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; + +public class NetworkTileEntities implements ITileNetwork +{ + protected Set networkMembers = new HashSet(); + + public NetworkTileEntities() + { + NetworkUpdateHandler.instance().registerNetwork(this); + } + + public NetworkTileEntities(INetworkPart... parts) + { + this(); + if (parts != null) + { + for (INetworkPart part : parts) + { + if (this.isValidMember(part)) + { + part.setTileNetwork(this); + networkMembers.add(part); + } + } + } + } + + @Override + public String getName() + { + return "TileNetwork"; + } + + @Override + public Set getMembers() + { + if (this.networkMembers == null) + { + this.networkMembers = new HashSet(); + } + return networkMembers; + } + + @Override + public void onCreated() + { + this.load(); + this.cleanUpMembers(); + } + + @Override + public int getUpdateRate() + { + return -1; + } + + @Override + public void updateTick() + { + // TODO Auto-generated method stub + + } + + @Override + public void refreshTick() + { + // TODO Auto-generated method stub + + } + + @Override + public boolean addTile(TileEntity ent, boolean member) + { + if (ent == null || ent.isInvalid()) + { + return false; + } + else if (ent instanceof INetworkPart && this.isValidMember((INetworkPart) ent) && member) + { + ((INetworkPart) ent).setTileNetwork(this); + if (this.networkMembers.contains(ent)) + { + return true; + } + return this.networkMembers.add((INetworkPart) ent); + } + return false; + } + + @Override + public boolean removeTile(TileEntity ent) + { + return this.networkMembers.remove(ent); + } + + /** Cleans the list of networkMembers and remove those that no longer belong */ + public void cleanUpMembers() + { + Iterator it = this.networkMembers.iterator(); + + while (it.hasNext()) + { + INetworkPart part = it.next(); + if (!this.isValidMember(part)) + { + it.remove(); + } + else + { + part.setTileNetwork(this); + } + } + + } + + /** Is this part a valid member of the network */ + public boolean isValidMember(INetworkPart part) + { + return part != null && part instanceof TileEntity && !((TileEntity) part).isInvalid(); + } + + @Override + public void save() + { + // TODO Auto-generated method stub + + } + + @Override + public void load() + { + // TODO Auto-generated method stub + + } + + @Override + public void mergeNetwork(ITileNetwork network, INetworkPart mergePoint) + { + if (network != null && network != this && network.getClass().equals(this.getClass())) + { + if (this.preMergeProcessing(network, mergePoint)) + { + this.mergeDo(network); + } + } + } + + /** Processing that needs too be done before the network merges. Use this to do final network + * merge calculations and to cause network merge failure + * + * @param network the network that is to merge with this one + * @param part the part at which started the network merge. Use this to cause damage if two + * networks merge with real world style failures + * + * @return false if the merge needs to be canceled. + * + * Cases in which the network should fail to merge are were the two networks merge with error. + * Or, in the case of pipes the two networks merge and the merge point was destroyed by + * combination of liquids. + * + * Ex Lava and water */ + public boolean preMergeProcessing(ITileNetwork network, INetworkPart part) + { + this.save(); + return true; + } + + /** Merges the two networks together */ + protected void mergeDo(ITileNetwork network) + { + ITileNetwork newNetwork = NetworkUpdateHandler.createNewNetwork(NetworkUpdateHandler.getID(this.getClass())); + if (newNetwork != null) + { + newNetwork.getMembers().addAll(this.getMembers()); + newNetwork.getMembers().addAll(network.getMembers()); + newNetwork.onCreated(); + this.invalidate(); + } + else + { + System.out.println("[CoreMachine]NetworkTileEntities: Failed to merge network due to network creation failure"); + } + } + + @Override + public void splitNetwork(INetworkPart splitPoint) + { + this.getMembers().remove(splitPoint); + if (splitPoint instanceof TileEntity) + { + List connections = splitPoint.getNetworkConnections(); + + for (final TileEntity connectionStart : connections) + { + if (connectionStart instanceof INetworkPart) + { + for (final TileEntity connectionEnd : connections) + { + if (connectionStart != connectionEnd && connectionEnd instanceof INetworkPart) + { + Pathfinder finder = new NetworkPathFinder(connectionEnd.worldObj, (INetworkPart) connectionEnd, splitPoint); + finder.init(new Vector3(connectionStart)); + + if (finder.results.size() <= 0) + { + this.save(); + /* NO LONGER CONNECTED ELSE WHERE SO SPLIT AND REFRESH */ + ITileNetwork newNetwork = NetworkUpdateHandler.createNewNetwork(NetworkUpdateHandler.getID(this.getClass())); + if (newNetwork != null) + { + for (Vector3 node : finder.closedSet) + { + TileEntity entity = node.getTileEntity(connectionEnd.worldObj); + if (entity instanceof INetworkPart) + { + if (node != splitPoint) + { + newNetwork.getMembers().add((INetworkPart) entity); + } + } + } + newNetwork.onCreated(); + } + } + } + } + } + } + + } + + } + + @Override + public String toString() + { + return this.getName() + "[" + this.hashCode() + "| Parts:" + this.networkMembers.size() + "]"; + } + + @Override + public boolean isInvalid() + { + return this.networkMembers.isEmpty(); + } + + @Override + public void invalidate() + { + this.networkMembers.clear(); + } + + public static void invalidate(TileEntity tileEntity) + { + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + TileEntity checkTile = VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction); + + if (checkTile instanceof INetworkPart && ((INetworkPart) checkTile).getTileNetwork() != null) + { + ((INetworkPart) checkTile).getTileNetwork().removeTile(tileEntity); + } + } + } + +} diff --git a/src/com/dark/prefab/tile/network/NetworkUpdateHandler.java b/src/com/dark/prefab/tile/network/NetworkUpdateHandler.java new file mode 100644 index 000000000..0f80e256f --- /dev/null +++ b/src/com/dark/prefab/tile/network/NetworkUpdateHandler.java @@ -0,0 +1,159 @@ +package com.dark.prefab.tile.network; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.dark.tile.network.ITileNetwork; + + +import cpw.mods.fml.common.ITickHandler; +import cpw.mods.fml.common.TickType; + +/** Manages all the tile networks making sure they get world save events, and updates every so often + * + * @author DarkGuardsman */ +public class NetworkUpdateHandler implements ITickHandler +{ + private static HashMap> nameToClassMap = new HashMap>(); + private static HashMap, String> classToNameMap = new HashMap, String>(); + + private int count = 0; + private static int refreshTicks = 6000; + + private Set activeNetworks = new HashSet(); + private Set allNetworks = new HashSet(); + + private static NetworkUpdateHandler instance; + + static + { + registerNetworkClass("base", NetworkTileEntities.class); + } + + public static NetworkUpdateHandler instance() + { + if (instance == null) + { + instance = new NetworkUpdateHandler(); + } + return instance; + } + + public void registerNetwork(ITileNetwork network) + { + if (network != null && !activeNetworks.contains(network)) + { + this.allNetworks.add(network); + if (network.getUpdateRate() > 0) + { + this.activeNetworks.add(network); + } + } + } + + public static void registerNetworkClass(String id, Class clazz) + { + if (!nameToClassMap.containsKey(id) && !classToNameMap.containsKey(clazz)) + { + nameToClassMap.put(id, clazz); + classToNameMap.put(clazz, id); + } + } + + public static String getID(Class clazz) + { + return classToNameMap.get(clazz); + } + + public static Class getClazz(String id) + { + return nameToClassMap.get(id); + } + + public static ITileNetwork createNewNetwork(String id) + { + Class clazz = getClazz(id); + if (clazz != null) + { + try + { + Object object = clazz.newInstance(); + if (object instanceof ITileNetwork) + { + return (ITileNetwork) object; + } + } + catch (Exception e) + { + System.out.println("[CoreMachine]TileNetworkHandler: Failed to create a new network object"); + e.printStackTrace(); + } + } + else + { + System.out.println("[CoreMachine]TileNetworkHandler: Unkown id: " + id); + } + + return null; + } + + @Override + public void tickStart(EnumSet type, Object... tickData) + { + if (count + 1 >= NetworkUpdateHandler.refreshTicks) + { + count = 0; + for (ITileNetwork network : allNetworks) + { + if (!network.isInvalid()) + { + network.refreshTick(); + } + } + } + else + { + count++; + for (ITileNetwork network : activeNetworks) + { + if (!network.isInvalid()) + { + network.updateTick(); + } + } + } + + } + + @Override + public void tickEnd(EnumSet type, Object... tickData) + { + Iterator it = activeNetworks.iterator(); + while (it.hasNext()) + { + ITileNetwork network = it.next(); + if (network.isInvalid()) + { + network.invalidate(); + it.remove(); + allNetworks.remove(network); + } + } + + } + + @Override + public EnumSet ticks() + { + return EnumSet.of(TickType.SERVER); + } + + @Override + public String getLabel() + { + return "[CoreMachine]TileNetworkHandler"; + } +} diff --git a/src/com/dark/tile/network/IMotionPath.java b/src/com/dark/tile/network/IMotionPath.java new file mode 100644 index 000000000..7cf8882f8 --- /dev/null +++ b/src/com/dark/tile/network/IMotionPath.java @@ -0,0 +1,24 @@ +package com.dark.tile.network; + +import net.minecraft.entity.Entity; +import universalelectricity.core.vector.Vector3; + +/** Use by tiles to control the path of motion of an item threw a tile network such as items pipes + * + * @author DarkGuardsman */ +public interface IMotionPath +{ + + /** Gets the motion applied to the entity while its on the tile **/ + public Vector3 getMotion(Entity entity); + + /** Can the path controller move the entity over this tile. Make sure to check the position of + * the tile as the controller doesn't know the range of control of the tile. Though it does + * limit itself to blocks around the entity. So if your tile only effects entities above it + * within its bound then make sure the tile is inside those bounds + * + * @param entity - entity in question + * @param from - direction the entity came from + * @return true if it can, false if something is wrong like no power, or solid side */ + public boolean canMoveEntity(Entity entity); +} diff --git a/src/com/dark/tile/network/INetworkContainer.java b/src/com/dark/tile/network/INetworkContainer.java new file mode 100644 index 000000000..4105b229d --- /dev/null +++ b/src/com/dark/tile/network/INetworkContainer.java @@ -0,0 +1,18 @@ +package com.dark.tile.network; + +/** Used on tiles that can contain more than one tile network. Currently WIP so don't use unless you + * know what your doing. When using this use networks like items and store them in slots. + * + * @author DarkGuardsman */ +public interface INetworkContainer +{ + /** Gets a list of all networks slots and their connected networks. Used both to see the max + * limit of networks this tile may contain, and if there are networks currently in use */ + public ITileNetwork[] getContainedNetworks(); + + /** Sets the network in the given slot */ + public boolean setNetwork(int slot, ITileNetwork network); + + /** Gets the network in the slot */ + public ITileNetwork getNetwork(int slot); +} diff --git a/src/com/dark/tile/network/INetworkEnergyPart.java b/src/com/dark/tile/network/INetworkEnergyPart.java new file mode 100644 index 000000000..facae8be6 --- /dev/null +++ b/src/com/dark/tile/network/INetworkEnergyPart.java @@ -0,0 +1,20 @@ +package com.dark.tile.network; + +import universalelectricity.core.block.IElectricalStorage; + +/** Tiles that use NetworkSharedPower class should implements this. All methods in IElectricalStorage + * should point to the network instead of the tile. This is why more energy methods are added to + * this interface + * + * @author DarkGuardsman */ +public interface INetworkEnergyPart extends INetworkPart, IElectricalStorage +{ + /** Gets the energy stored in the part */ + public float getPartEnergy(); + + /** Gets the max energy storage limit of the part */ + public float getPartMaxEnergy(); + + /** Sets the energy stored in the part */ + public void setPartEnergy(float energy); +} diff --git a/src/com/dark/tile/network/INetworkPart.java b/src/com/dark/tile/network/INetworkPart.java new file mode 100644 index 000000000..2d1a5f0c2 --- /dev/null +++ b/src/com/dark/tile/network/INetworkPart.java @@ -0,0 +1,20 @@ +package com.dark.tile.network; + +import java.util.List; + +import net.minecraft.tileentity.TileEntity; + +public interface INetworkPart extends ITileConnector +{ + /** Array of connections this tile has to other tiles */ + public List getNetworkConnections(); + + /** Update the connection this tile has to other tiles */ + public void refresh(); + + /** Gets the networkPart's primary network */ + public ITileNetwork getTileNetwork(); + + /** Sets the networkPart's primary network */ + public void setTileNetwork(ITileNetwork network); +} diff --git a/src/com/dark/tile/network/ITileConnector.java b/src/com/dark/tile/network/ITileConnector.java new file mode 100644 index 000000000..b56c30b98 --- /dev/null +++ b/src/com/dark/tile/network/ITileConnector.java @@ -0,0 +1,43 @@ +package com.dark.tile.network; + +import net.minecraftforge.common.ForgeDirection; + +/** Used on tiles that want control over what can connect to there device. It is suggest that other + * interfaces for connection be routed threw this to reduce the need to change things + * + * @author DarkGuardsman */ +public interface ITileConnector +{ + /** Can this tile connect on the given side */ + public boolean canTileConnect(Connection type, ForgeDirection dir); + + /** Types of connections */ + public static enum Connection + { + /** Energy from BC, UE, IC2 */ + Eletricity(), + /** Fluids from anything including BC pipes, DM pipes, Mek pipes */ + FLUIDS(), + /** Force mainly from rotating rods */ + FORCE(), + /** Hydraulic pressure from DM pipe */ + FLUID_PRESSURE(), + AIR_PRESSURE(), + /** Item pipe */ + ITEMS(), + /** Data line input */ + DATA(), + /** Another tile entity */ + TILE(), + /** Network of tile entities */ + NETWORK(), + /** Thermal connection */ + HEAT(), + /** Wire containing several wires of unknown color */ + MULTI_WIRE(), + /** Bundle of pipes containing several colored pipes */ + MULTI_PIPE(), + /** Device that contains several networks that can be of any type */ + MULTI_NETWORK(); + } +} diff --git a/src/com/dark/tile/network/ITileNetwork.java b/src/com/dark/tile/network/ITileNetwork.java new file mode 100644 index 000000000..66583bb7f --- /dev/null +++ b/src/com/dark/tile/network/ITileNetwork.java @@ -0,0 +1,60 @@ +package com.dark.tile.network; + +import java.util.Set; + +import net.minecraft.tileentity.TileEntity; + +/** Applies to objects that act as a collection of tile entities. + * + * @author DarkGuardsman */ +public interface ITileNetwork +{ + /** Gets the name of the network */ + public String getName(); + + /** Gets a list of all tiles that are part of this network */ + public Set getMembers(); + + /** Called when something want the network to add the tile + * + * @param entity - tile in question + * @param member - add it as a member if true + * @return true if added without issue */ + public boolean addTile(TileEntity ent, boolean member); + + /** Removes a tile from all parts of the network */ + public boolean removeTile(TileEntity ent); + + /** Called when this network is just created */ + public void onCreated(); + + /** How many ticks should base between updates, return 0 or bellow for no ticks */ + public int getUpdateRate(); + + /** Called every so many ticks so the network has a chance to update */ + public void updateTick(); + + /** Called every so many mins when the networks needs to refresh and repair. Each part should + * still handle there own refresh when edited, or updated. This is more for the network to do + * house cleaning */ + public void refreshTick(); + + /** Called when two networks try to merge together */ + public void mergeNetwork(ITileNetwork network, INetworkPart mergePoint); + + /** Called when a peace of the network is removed and might need to split in two */ + public void splitNetwork(INetworkPart splitPoint); + + /** Check by the network handle if this network is invalid or no longer functional */ + public boolean isInvalid(); + + /** This is called when your network is considered invalid. You should cut all ties in the + * network to its object so GC will delete it */ + public void invalidate(); + + /** Called when the network needs to save */ + public void save(); + + /** Called when the network needs to load */ + public void load(); +}