diff --git a/src/common/basicpipes/conductors/BlockRod.java b/src/common/basicpipes/conductors/BlockRod.java index 5098f8a4..ea4eb87a 100644 --- a/src/common/basicpipes/conductors/BlockRod.java +++ b/src/common/basicpipes/conductors/BlockRod.java @@ -1,5 +1,6 @@ package basicpipes.conductors; +import basicpipes.ItemRenderHelper; import steampower.TileEntityMachine; import net.minecraft.src.Block; import net.minecraft.src.CreativeTabs; @@ -37,9 +38,7 @@ public class BlockRod extends universalelectricity.prefab.BlockMachine { case 2: meta = 3;dZ++;break; case 3: meta = 4;dX++;break; } - //ForgeDirection dir = ForgeDirection.getOrientation(meta); world.setBlockAndMetadataWithUpdate(i, j, k,blockID, meta, true); - // world.setBlockAndMetadataWithUpdate(i+dir.offsetX, j, k+dir.offsetZ,blockID, meta, true); } @Override public boolean onUseWrench(World world, int x, int y, int z, EntityPlayer par5EntityPlayer) @@ -78,7 +77,7 @@ public class BlockRod extends universalelectricity.prefab.BlockMachine { */ public int getRenderType() { - return -1; + return ItemRenderHelper.renderID; } } diff --git a/src/common/basicpipes/machines/BlockMachine.java b/src/common/basicpipes/machines/BlockMachine.java index ca99f0a2..99bef5ea 100644 --- a/src/common/basicpipes/machines/BlockMachine.java +++ b/src/common/basicpipes/machines/BlockMachine.java @@ -8,6 +8,7 @@ import net.minecraft.src.Material; import net.minecraft.src.TileEntity; import net.minecraft.src.World; import basicpipes.BasicPipesMain; +import basicpipes.ItemRenderHelper; public class BlockMachine extends BlockContainer { @@ -36,7 +37,7 @@ public class BlockMachine extends BlockContainer */ public int getRenderType() { - return -1; + return ItemRenderHelper.renderID; } /** @@ -58,11 +59,6 @@ public class BlockMachine extends BlockContainer } return 0; } - //Per tick - public int conductorCapacity() - { - return 1; - } @Override public TileEntity createNewTileEntity(World var1,int meta) { // TODO Auto-generated method stub diff --git a/src/common/basicpipes/machines/ItemMachine.java b/src/common/basicpipes/machines/ItemMachine.java index cfb994b5..b1488aea 100644 --- a/src/common/basicpipes/machines/ItemMachine.java +++ b/src/common/basicpipes/machines/ItemMachine.java @@ -42,7 +42,7 @@ public class ItemMachine extends ItemBlock { par3List.add(new ItemStack(this, 1, 0)); - par3List.add(new ItemStack(this, 1, 4)); + //par3List.add(new ItemStack(this, 1, 4)); } public String getTextureFile() { diff --git a/src/common/ic2/api/BaseSeed.java b/src/common/ic2/api/BaseSeed.java new file mode 100644 index 00000000..6f4e57a5 --- /dev/null +++ b/src/common/ic2/api/BaseSeed.java @@ -0,0 +1,56 @@ +package ic2.api; + +/** + * Base agriculture seed. Used to determine the state of a plant once it is planted from an item. + */ +public class BaseSeed { + /** + * Plant ID. + */ + public int id; + + /** + * Plant size. + */ + public int size; + + /** + * Plant growth stat. + */ + public int statGrowth; + + /** + * Plant gain stat. + */ + public int statGain; + + /** + * Plant resistance stat. + */ + public int statResistance; + + /** + * For internal usage only. + */ + public int stackSize; + + /** + * Create a BaseSeed object. + * + * @param id plant ID + * @param size plant size + * @param statGrowth plant growth stat + * @param statGain plant gain stat + * @param statResistance plant resistance stat + * @param stackSize for internal usage only + */ + public BaseSeed(int id, int size, int statGrowth, int statGain, int statResistance, int stackSize) { + super(); + this.id = id; + this.size = size; + this.statGrowth = statGrowth; + this.statGain = statGain; + this.statResistance = statResistance; + this.stackSize = stackSize; + } +} diff --git a/src/common/ic2/api/CropCard.java b/src/common/ic2/api/CropCard.java new file mode 100644 index 00000000..79d1f3d8 --- /dev/null +++ b/src/common/ic2/api/CropCard.java @@ -0,0 +1,475 @@ +package ic2.api; + +import java.util.HashMap; + +import net.minecraft.src.Entity; +import net.minecraft.src.EntityLiving; +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ItemStack; + +/** + * Base agriculture crop. + * + * Any crop extending this can be registered using registerCrop to be added into the game. + */ +public abstract class CropCard +{ + /** + * Plant name. Will be displayed to the player. + * + * @return Plant name + */ + public abstract String name(); + + /** + * Your name here, will be shown in "Discovered by:" when analyzing seeds. + * + * @return Your name + */ + public String discoveredBy() {return "Alblaka";} + + /** + * Description of your plant. Keep it short, a few characters per line for up to two lines. + * Default is showing attributes of your plant, 2 per line. + * + * @param i line to get, starting from 0 + * @return The line + */ + public String desc(int i) + { + String[] att = attributes(); + if (att == null || att.length==0) return ""; + if (i == 0) + { + String s = att[0]; + if (att.length >= 2) + { + s+=", "+att[1]; + if (att.length >= 3) s+=","; + } + return s; + } + else + { + if (att.length < 3) return ""; + String s = att[2]; + if (att.length >= 4) s+=", "+att[3]; + return s; + } + } + + /** + * Tier of the plant. Ranges from 1 to 16, 0 is Weed. + * Valuable and powerful crops have higher tiers, useless and weak ones have lower tiers. + * + * @return Tier + */ + public abstract int tier(); + + /** + * Describe the plant through a set of stats, influencing breeding. + * Plants sharing stats and attributes will tend to cross-breed more often. + * + * Stats: + * - 0: Chemistry (Industrial uses based on chemical plant components) + * - 1: Consumable (Food, potion ingredients, stuff meant to be eaten or similarly used) + * - 2: Defensive (Plants with defense capabilities (damaging, explosive, chemical) or special abilities in general) + * - 3: Colorful (How colorful/aesthetically/beautiful is the plant, like dye-plants or plants without actual effects) + * - 4: Weed (Is this plant weed-like and rather unwanted/quick-spreading? Rare super-breed plants should have low values here) + * + * @param n index of the requested stat + * @return The requested value of the stats + */ + public abstract int stat(int n); + + /** + * Additional attributes of the plant, also influencing breeding. + * Plants sharing stats and attributes will tend to cross-breed more often. + * + * @return Attributes as an array of strings + */ + public abstract String[] attributes(); + + /** + * Sprite index the crop is meant to be rendered with. + * + * @param crop reference to TECrop + * @return 0-255, representing the sprite index on the crop's spritesheet. + */ + public abstract int getSpriteIndex(TECrop crop); + + /** + * Get the crop's spritesheet. + * Per default crops_0.png of ic2-sprites + * @return Texture file path + */ + public String getTextureFile() { + return "/ic2/sprites/crops_0.png"; + } + + /** + * Amount of growth points needed to increase the plant's size. + * Default is 200 * tier. + */ + public int growthDuration(TECrop crop) + { + return tier()*200; + } + + /** + * Check whether the plant can grow further. + * + * Consider: + * - Humidity, nutrients and air quality + * - Current size + * - Light level + * - Special biomes or conditions, accessible through crop.worldObj + * + * This method will be called upon empty upgraded crops to check whether a neighboring plant can cross onto it! Don't check if the size is greater than 0 and if the ID is real. + * + * @param crop reference to TECrop + * @return Whether the crop can grow + */ + public abstract boolean canGrow(TECrop crop); + + /** + * Calculate the influence for the plant to grow based on humidity, nutrients and air. + * Normal behavior is rating the three stats "normal", with each of them ranging from 0-30. + * Basic rule: Assume everything returns 10. All together must equal 30. Add the factors to your likings, for example (humidity*0.7)+(nutrients*0.9)+(air*1.4) + * + * Default is humidity + nutrients + air (no factors). + * + * @param crop reference to TECrop + * @param humidity ground humidity, influenced by hydration + * @param nutrients nutrient quality in ground, based on fertilizers + * @param air air quality, influences by open gardens and less crops surrounding this one + * @return 0-30 + */ + public int weightInfluences(TECrop crop, float humidity, float nutrients, float air) + { + return (int) (humidity+nutrients+air); + } + + /** + * Used to determine whether the plant can crossbreed with another crop. + * Default is allow crossbreeding if the size is greater or equal than 3. + * + * @param crop crop to crossbreed with + */ + public boolean canCross(TECrop crop) + { + return crop.size >= 3; + } + + + /** + * Called when the plant is rightclicked by a player. + * Default action is harvesting. + * + * @param crop reference to TECrop + * @param player player rightclicking the crop + * @return Whether the plant has changed + */ + public boolean rightclick(TECrop crop, EntityPlayer player) + { + return crop.harvest(true); + } + + /** + * Check whether the crop can be harvested. + * + * @param crop reference to TECrop + * @return Whether the crop can be harvested in its current state. + */ + public abstract boolean canBeHarvested(TECrop crop); + + /** + * Base chance for dropping the plant's gains, specify values greater than 1 for multiple drops. + * Default is 0.95^tier. + * + * @return Chance to drop the gains + */ + public float dropGainChance() + { + float base = 1F; + for (int i = 0; i < tier(); i++) {base*=0.95;} + return base; + } + + /** + * Item obtained from harvesting the plant. + * + * @param crop reference to TECrop + * @return Item obtained + */ + public abstract ItemStack getGain(TECrop crop); + + /** + * Get the size of the plant after harvesting. + * Default is 1. + * + * @param crop reference to TECrop + * @return Plant size after harvesting + */ + public byte getSizeAfterHarvest(TECrop crop) {return 1;} + + + /** + * Called when the plant is leftclicked by a player. + * Default action is picking the plant. + * + * @param crop reference to TECrop + * @param player player leftclicked the crop + * @return Whether the plant has changed + */ + public boolean leftclick(TECrop crop, EntityPlayer player) + { + return crop.pick(true); + } + + /** + * Base chance for dropping seeds when the plant is picked. + * Default is 0.5*0.8^tier with a bigger chance for sizes greater than 2 and absolutely no chance for size 0. + * + * @param crop reference to TECrop + * @return Chance to drop the seeds + */ + public float dropSeedChance(TECrop crop) + { + if (crop.size == 1) return 0; + float base = 0.5F; + if (crop.size == 2) base/=2F; + for (int i = 0; i < tier(); i++) {base*=0.8;} + return base; + } + + /** + * Obtain seeds dropped when the plant is picked. + * Multiple drops of the returned ItemStack can occur. + * Default action is generating a seed from this crop. + * + * @param crop reference to TECrop + * @return Seeds + */ + public ItemStack getSeeds(TECrop crop) + { + return crop.generateSeeds(crop.id, crop.statGrowth, crop.statGain, crop.statResistance, crop.scanLevel); + } + + /** + * Called when a neighbor block to the crop has changed. + * + * @param crop reference to TECrop + */ + public void onNeighbourChange(TECrop crop){} + + /** + * Check if the crop should emit redstone. + * + * @return Whether the crop should emit redstone + */ + public boolean emitRedstone(TECrop crop){return false;} + + /** + * Called when the crop is destroyed. + * + * @param crop reference to TECrop + */ + public void onBlockDestroyed(TECrop crop){} + + /** + * Get the light value emitted by the plant. + * + * @param crop reference to TECrop + * @return Light value emitted + */ + public int getEmittedLight(TECrop crop) {return 0;} + + /** + * Default is true if the entity is an EntityLiving in jumping or sprinting state. + * + * @param crop reference to TECrop + * @param entity entity colliding + * @return Whether trampling calculation should happen, return false if the plant is no longer valid. + */ + public boolean onEntityCollision(TECrop crop, Entity entity) + { + if (entity instanceof EntityLiving) + { + return ((EntityLiving)entity).isSprinting(); + } + return false; + } + + + /** + * Called every time the crop ticks. + * Should be called every 256 ticks or around 13 seconds. + * + * @param crop reference to TECrop + */ + public void tick(TECrop crop) {} + + /** + * Check whether this plant spreads weed to surrounding tiles. + * Default is true if the plant has a high growth stat (or is weeds) and size greater or equal than 2. + * + * @param crop reference to TECrop + * @return Whether the plant spreads weed + */ + public boolean isWeed(TECrop crop) + { + return crop.size>=2 && (crop.id==0 || crop.statGrowth>=24); + } + + + /** + * Get this plant's ID. + * + * @return ID of this CropCard or -1 if it's not registered + */ + public final int getId() + { + for (int i = 0; i < cropCardList.length; i++) + { + if (this == cropCardList[i]) + { + return i; + } + } + return -1; + } + + private static final CropCard[] cropCardList = new CropCard[256]; + + /** + * Get the size of the plant list. + * + * @return Plant list size + */ + public static int cropCardListLength() {return cropCardList.length;} + + /** + * Return the CropCard assigned to the given ID. + * If the ID is out of bounds, weed should be returned. If the ID is not registered, weed should be returned and a console print will notify. + * + * @param id plant ID + * @return Plant class + */ + public static final CropCard getCrop(int id) + { + if (id < 0 || id >= cropCardList.length) + {// Out of bounds + return cropCardList[0]; + } + if (cropCardList[id]==null) + {// Out of bounds + System.out.println("[IndustrialCraft] Something tried to access non-existant cropID #"+id+"!!!"); + return cropCardList[0]; + } + + return cropCardList[id]; + } + + /** + * Check whether the specified plant ID is already assigned. + * @param id ID to be checked + * @return true if the the given id is inbounds and the registered slot is not null + */ + public static final boolean idExists(int id) + { + return !(id < 0 || id >= cropCardList.length || cropCardList[id]==null); + } + + /** + * Auto-assign an ID to a plant and register it. + * Usage of this method is not recommended! Other plants could take your IDs and cause your plants to turn into other plants. + * + * @param crop plant to register + * @return The ID assigned to the plant + */ + public static final short registerCrop(CropCard crop) + { + for (short x = 0; x < cropCardList.length; x++) + {// Iterate through list + if (cropCardList[x]==null) + {// Found empty slot, add crop here + cropCardList[x]=crop; + nameReference.addLocal("item.cropSeed"+x+".name", crop.name()+" Seeds"); + return x; + } + } + //No free slot avaible + return -1; + } + + /** + * Attempt to register a plant to an ID. + * If the ID is taken, the crop will not be registered and a console print will notify the user. + * + * @param crop plant to register + * @param i ID to register the plant to + * @return Whether the crop was registered + */ + public static final boolean registerCrop(CropCard crop, int i) + { + if (i < 0 || i >= cropCardList.length) + {// Out of bounds + return false; + } + if (cropCardList[i]==null) + { + cropCardList[i]=crop; + nameReference.addLocal("item.cropSeed"+i+".name", crop.name()+" Seeds"); + return true; + } + System.out.println("[IndustrialCraft] Cannot add crop:"+crop.name()+" on ID #"+i+", slot already occupied by crop:"+cropCardList[i].name()); + return false; + } + + /** + * For internal usage only. + */ + public static TECrop nameReference; + + private static HashMap baseseeds = new HashMap(); + + /** + * Registers a base seed, an item used to plant a crop. + * + * @param stack item + * @param id plant ID + * @param size initial size + * @param growth initial growth stat + * @param gain initial gain stat + * @param resistance initial resistance stat + * @return True if successful + */ + public static boolean registerBaseSeed(ItemStack stack, int id, int size, int growth, int gain, int resistance) + { + for (ItemStack key : baseseeds.keySet()) + if (key.itemID==stack.itemID && key.getItemDamage()==stack.getItemDamage()) return false; + + baseseeds.put(stack, new BaseSeed(id, size, growth, gain, resistance, stack.stackSize)); + return true; + } + + /** + * Finds a base seed from the given item. + * + * @return Base seed or null if none found + */ + public static BaseSeed getBaseSeed(ItemStack stack) + { + if (stack == null) return null; + for (ItemStack key : baseseeds.keySet()) + { + if (key.itemID == stack.itemID && + (key.getItemDamage() == -1 || key.getItemDamage() == stack.getItemDamage())) + { + return baseseeds.get(key); + } + } + return null; + } +} diff --git a/src/common/ic2/api/Crops.java b/src/common/ic2/api/Crops.java new file mode 100644 index 00000000..e2fbe1aa --- /dev/null +++ b/src/common/ic2/api/Crops.java @@ -0,0 +1,47 @@ +package ic2.api; + +import java.util.HashMap; + +import net.minecraft.src.BiomeGenBase; + +/** + * General management of the crop system. All crop management methods will be moved here in the 2.00 update. + */ +public class Crops { + private static final HashMap humidityBiomeBonus = new HashMap(); + private static final HashMap nutrientBiomeBonus = new HashMap(); + + /** + * Add a crop humidity and nutrient biome bonus. + * + * 0 indicates no bonus and negative values indicate a penalty. + * + * @param biome Biome to apply the bonus in + * @param humidityBonus Humidity stat bonus + * @param nutrientsBonus Nutrient stat bonus + */ + public static void addBiomeBonus(BiomeGenBase biome, int humidityBonus, int nutrientsBonus) { + humidityBiomeBonus.put(biome, humidityBonus); + nutrientBiomeBonus.put(biome, nutrientsBonus); + } + + /** + * Get the humidity bonus for a biome. + * + * @param biome biome to check + * @return Humidity bonus or 0 if none + */ + public static int getHumidityBiomeBonus(BiomeGenBase biome) { + return humidityBiomeBonus.containsKey(biome) ? humidityBiomeBonus.get(biome) : 0; + } + + /** + * Get the nutrient bonus for a biome. + * + * @param biome biome to check + * @return Nutrient bonus or 0 if none + */ + public static int getNutrientBiomeBonus(BiomeGenBase biome) { + return nutrientBiomeBonus.containsKey(biome) ? nutrientBiomeBonus.get(biome) : 0; + } +} diff --git a/src/common/ic2/api/Direction.java b/src/common/ic2/api/Direction.java new file mode 100644 index 00000000..52381c16 --- /dev/null +++ b/src/common/ic2/api/Direction.java @@ -0,0 +1,106 @@ +package ic2.api; + +import net.minecraft.src.TileEntity; +import net.minecraftforge.common.ForgeDirection; + +/** + * Represents the 6 possible directions along the axis of a block. + */ +public enum Direction { + /** + * -X + */ + XN(0), + /** + * +X + */ + XP(1), + + /** + * -Y + */ + YN(2), //MC-Code starts with 0 here + /** + * +Y + */ + YP(3), // 1... + + /** + * -Z + */ + ZN(4), + /** + * +Z + */ + ZP(5); + + Direction(int dir) { + this.dir = dir; + } + + /*public CoordinateTuple ApplyToCoordinates(CoordinateTuple coordinates) { + CoordinateTuple ret = new CoordinateTuple(coordinates); + + ret.coords[dir/2] += GetSign(); + + return ret; + }*/ + + /** + * Get the tile entity next to a tile entity following this direction. + * + * @param tileEntity tile entity to check + * @return Adjacent tile entity or null if none exists + */ + public TileEntity applyToTileEntity(TileEntity tileEntity) { + int coords[] = { tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord }; + + coords[dir/2] += getSign(); + + if (tileEntity.worldObj != null && tileEntity.worldObj.blockExists(coords[0], coords[1], coords[2])) { + return tileEntity.worldObj.getBlockTileEntity(coords[0], coords[1], coords[2]); + } else { + return null; + } + } + + /** + * Get the inverse of this direction (XN -> XP, XP -> XN, etc.) + * + * @return Inverse direction + */ + public Direction getInverse() { + int inverseDir = dir - getSign(); + + for (Direction direction: Direction.values()) { + if (direction.dir == inverseDir) return direction; + } + + return this; + } + + /** + * Convert this direction to a Minecraft side value. + * + * @return Minecraft side value + */ + public int toSideValue() { + return (dir + 4) % 6; + } + + /** + * Determine direction sign (N for negative or P for positive). + * + * @return -1 if the direction is negative, +1 if the direction is positive + */ + private int getSign() { + return (dir % 2) * 2 - 1; + } + + public ForgeDirection toForgeDirection() { + return ForgeDirection.getOrientation(toSideValue()); + } + + private int dir; +} + diff --git a/src/common/ic2/api/ElectricItem.java b/src/common/ic2/api/ElectricItem.java new file mode 100644 index 00000000..3f4a4972 --- /dev/null +++ b/src/common/ic2/api/ElectricItem.java @@ -0,0 +1,128 @@ +package ic2.api; + +import java.lang.reflect.Method; + +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ItemStack; + +/** + * Allows for charging, discharging and using electric items (IElectricItem). + * + * The charge or remaining capacity of an item can be determined by calling charge/discharge with + * ignoreTransferLimit and simulate set to true. + */ +public final class ElectricItem { + /** + * Charge an item with a specified amount of energy + * + * @param itemStack electric item's stack + * @param amount amount of energy to charge in EU + * @param tier tier of the charging device, has to be at least as high as the item to charge + * @param ignoreTransferLimit ignore the transfer limit specified by getTransferLimit() + * @param simulate don't actually change the item, just determine the return value + * @return Energy transferred into the electric item + */ + public static int charge(ItemStack itemStack, int amount, int tier, boolean ignoreTransferLimit, boolean simulate) { + try { + if (ElectricItem_charge == null) ElectricItem_charge = Class.forName(getPackage() + ".common.ElectricItem").getMethod("charge", ItemStack.class, Integer.TYPE, Integer.TYPE, Boolean.TYPE, Boolean.TYPE); + + return (Integer) ElectricItem_charge.invoke(null, itemStack, amount, tier, ignoreTransferLimit, simulate); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Discharge an item by a specified amount of energy + * + * @param itemStack electric item's stack + * @param amount amount of energy to charge in EU + * @param tier tier of the discharging device, has to be at least as high as the item to discharge + * @param ignoreTransferLimit ignore the transfer limit specified by getTransferLimit() + * @param simulate don't actually discharge the item, just determine the return value + * @return Energy retrieved from the electric item + */ + public static int discharge(ItemStack itemStack, int amount, int tier, boolean ignoreTransferLimit, boolean simulate) { + try { + if (ElectricItem_discharge == null) ElectricItem_discharge = Class.forName(getPackage() + ".common.ElectricItem").getMethod("discharge", ItemStack.class, Integer.TYPE, Integer.TYPE, Boolean.TYPE, Boolean.TYPE); + + return (Integer) ElectricItem_discharge.invoke(null, itemStack, amount, tier, ignoreTransferLimit, simulate); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Determine if the specified electric item has at least a specific amount of EU. + * This is supposed to be used in the item code during operation, for example if you want to implement your own electric item. + * BatPacks are not taken into account. + * + * @param itemStack electric item's stack + * @param amount minimum amount of energy required + * @return true if there's enough energy + */ + public static boolean canUse(ItemStack itemStack, int amount) { + try { + if (ElectricItem_canUse == null) ElectricItem_canUse = Class.forName(getPackage() + ".common.ElectricItem").getMethod("canUse", ItemStack.class, Integer.TYPE); + + return (Boolean) ElectricItem_canUse.invoke(null, itemStack, amount); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Try to retrieve a specific amount of energy from an Item, and if applicable, a BatPack. + * This is supposed to be used in the item code during operation, for example if you want to implement your own electric item. + * + * @param itemStack electric item's stack + * @param amount amount of energy to discharge in EU + * @param player player holding the item + * @return true if the operation succeeded + */ + public static boolean use(ItemStack itemStack, int amount, EntityPlayer player) { + try { + if (ElectricItem_use == null) ElectricItem_use = Class.forName(getPackage() + ".common.ElectricItem").getMethod("use", ItemStack.class, Integer.TYPE, EntityPlayer.class); + + return (Boolean) ElectricItem_use.invoke(null, itemStack, amount, player); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Charge an item from the BatPack a player is wearing. + * This is supposed to be used in the item code during operation, for example if you want to implement your own electric item. + * use() already contains this functionality. + * + * @param itemStack electric item's stack + * @param player player holding the item + */ + public static void chargeFromArmor(ItemStack itemStack, EntityPlayer player) { + try { + if (ElectricItem_chargeFromArmor == null) ElectricItem_chargeFromArmor = Class.forName(getPackage() + ".common.ElectricItem").getMethod("chargeFromArmor", ItemStack.class, EntityPlayer.class); + + ElectricItem_chargeFromArmor.invoke(null, itemStack, player); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Get the base IC2 package name, used internally. + * + * @return IC2 package name, if unable to be determined defaults to ic2 + */ + private static String getPackage() { + Package pkg = ElectricItem.class.getPackage(); + if (pkg != null) return pkg.getName().substring(0, pkg.getName().lastIndexOf('.')); + else return "ic2"; + } + + private static Method ElectricItem_charge; + private static Method ElectricItem_discharge; + private static Method ElectricItem_canUse; + private static Method ElectricItem_use; + private static Method ElectricItem_chargeFromArmor; +} + diff --git a/src/common/ic2/api/EnergyNet.java b/src/common/ic2/api/EnergyNet.java new file mode 100644 index 00000000..2e98537e --- /dev/null +++ b/src/common/ic2/api/EnergyNet.java @@ -0,0 +1,119 @@ +package ic2.api; + +import java.lang.reflect.Method; + +import net.minecraft.src.TileEntity; +import net.minecraft.src.World; + +/** + * Provides access to the energy network. + */ +public final class EnergyNet { + /** + * Gets the EnergyNet instance for the specified world. + * + * @param world world + * @return EnergyNet instance for the world + */ + public static EnergyNet getForWorld(World world) { + try { + if (EnergyNet_getForWorld == null) EnergyNet_getForWorld = Class.forName(getPackage() + ".common.EnergyNet").getMethod("getForWorld", World.class); + + return new EnergyNet(EnergyNet_getForWorld.invoke(null, world)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private EnergyNet(Object energyNetInstance) { + this.energyNetInstance = energyNetInstance; + } + + /** + * Add a tile entity to the energy network. + * The tile entity has to be valid and initialized. + * + * @param addedTileEntity tile entity to add + */ + public void addTileEntity(TileEntity addedTileEntity) { + try { + if (EnergyNet_addTileEntity == null) EnergyNet_addTileEntity = Class.forName(getPackage() + ".common.EnergyNet").getMethod("addTileEntity", TileEntity.class); + + EnergyNet_addTileEntity.invoke(energyNetInstance, addedTileEntity); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Removes a tile entity from the energy network. + * The tile entity has to be still valid. + * + * @param removedTileEntity tile entity to remove + */ + public void removeTileEntity(TileEntity removedTileEntity) { + try { + if (EnergyNet_removeTileEntity == null) EnergyNet_removeTileEntity = Class.forName(getPackage() + ".common.EnergyNet").getMethod("removeTileEntity", TileEntity.class); + + EnergyNet_removeTileEntity.invoke(energyNetInstance, removedTileEntity); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Emit energy from an energy source to the energy network. + * + * @param energySource energy source to emit energy from + * @param amount amount of energy to emit in EU + * @return Leftover (unused) power + */ + public int emitEnergyFrom(IEnergySource energySource, int amount) { + try { + if (EnergyNet_emitEnergyFrom == null) EnergyNet_emitEnergyFrom = Class.forName(getPackage() + ".common.EnergyNet").getMethod("emitEnergyFrom", IEnergySource.class, Integer.TYPE); + + return ((Integer) EnergyNet_emitEnergyFrom.invoke(energyNetInstance, energySource, amount)).intValue(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Get the amount of energy currently being conducted by a conductor. + * Call this twice with a delay to get the average conducted power by doing (call2 - call1) / 2. + * + * @param tileEntity conductor + */ + public long getTotalEnergyConducted(TileEntity tileEntity) { + try { + if (EnergyNet_getTotalEnergyConducted == null) EnergyNet_getTotalEnergyConducted = Class.forName(getPackage() + ".common.EnergyNet").getMethod("getTotalEnergyConducted", TileEntity.class); + + return ((Long) EnergyNet_getTotalEnergyConducted.invoke(energyNetInstance, tileEntity)).longValue(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Get the base IC2 package name, used internally. + * + * @return IC2 package name, if unable to be determined defaults to ic2 + */ + private static String getPackage() { + Package pkg = EnergyNet.class.getPackage(); + if (pkg != null) return pkg.getName().substring(0, pkg.getName().lastIndexOf('.')); + else return "ic2"; + } + + /** + * Instance of the energy network. + */ + Object energyNetInstance; + + private static Method EnergyNet_getForWorld; + private static Method EnergyNet_addTileEntity; + private static Method EnergyNet_removeTileEntity; + private static Method EnergyNet_emitEnergyFrom; + private static Method EnergyNet_getTotalEnergyConducted; +} + diff --git a/src/common/ic2/api/ExplosionWhitelist.java b/src/common/ic2/api/ExplosionWhitelist.java new file mode 100644 index 00000000..d36ccc36 --- /dev/null +++ b/src/common/ic2/api/ExplosionWhitelist.java @@ -0,0 +1,46 @@ +package ic2.api; + +import java.util.*; + +import net.minecraft.src.Block; + +/** + * Blocks on this whitelist will not resist an explosion but won't be destroyed. + * + * The explosion code by default ignores blocks which absorb more than 1000 explosion power to + * prevent abusing personal safes, Trade-O-Mats and other blocks to serve as a cheap and + * invulnerable reactor chambers. Said blocks will not shield the explosion and won't get + * destroyed. + */ +public final class ExplosionWhitelist { + /** + * Add a block to the whitelist. + * + * @param block block to add + */ + public static void addWhitelistedBlock(Block block) { + whitelist.add(block); + } + + /** + * Remove a block from the whitelist. + * + * @param block block to remove + */ + public static void removeWhitelistedBlock(Block block) { + whitelist.remove(block); + } + + /** + * Check if a block is on the whitelist. + * + * @param block block to check if whitelisted + * @return Whether the block is whitelisted + */ + public static boolean isBlockWhitelisted(Block block) { + return whitelist.contains(block); + } + + private static Set whitelist = new HashSet(); +} + diff --git a/src/common/ic2/api/IBoxable.java b/src/common/ic2/api/IBoxable.java new file mode 100644 index 00000000..24dc5716 --- /dev/null +++ b/src/common/ic2/api/IBoxable.java @@ -0,0 +1,18 @@ +package ic2.api; + +import net.minecraft.src.ItemStack; + +/** + * Provides custom toolbox storage behavior for items. + * + * The normal condition for storing an item in a toolbox is having a maximum stack size of 1. + */ +public interface IBoxable { + /** + * Determine whether an item can be stored in a toolbox or not. + * + * @param itemstack item to be stored + * @return Whether to store the item in the toolbox or not + */ + public abstract boolean canBeStoredInToolbox(ItemStack itemstack); +} diff --git a/src/common/ic2/api/IElectricItem.java b/src/common/ic2/api/IElectricItem.java new file mode 100644 index 00000000..20a19e47 --- /dev/null +++ b/src/common/ic2/api/IElectricItem.java @@ -0,0 +1,52 @@ +package ic2.api; + +/** + * Provides the ability to store energy on the implementing item. + * + * The item should have a maximum damage of 13. + */ +public interface IElectricItem { + /** + * Determine if the item can be used in a machine to supply energy. + * + * @return Whether the item can supply energy + */ + boolean canProvideEnergy(); + + /** + * Get the item ID to use for a charge energy greater than 0. + * + * @return Item ID to use + */ + int getChargedItemId(); + + /** + * Get the item ID to use for a charge energy of 0. + * + * @return Item ID to use + */ + int getEmptyItemId(); + + /** + * Get the item's maximum charge energy in EU. + * + * @return Maximum charge energy + */ + int getMaxCharge(); + + /** + * Get the item's tier, lower tiers can't send energy to higher ones. + * Batteries are Tier 1, Energy Crystals are Tier 2, Lapotron Crystals are Tier 3. + * + * @return Item's tier + */ + int getTier(); + + /** + * Get the item's transfer limit in EU per transfer operation. + * + * @return Transfer limit + */ + int getTransferLimit(); +} + diff --git a/src/common/ic2/api/IEnergyAcceptor.java b/src/common/ic2/api/IEnergyAcceptor.java new file mode 100644 index 00000000..4b001923 --- /dev/null +++ b/src/common/ic2/api/IEnergyAcceptor.java @@ -0,0 +1,20 @@ +package ic2.api; + +import net.minecraft.src.TileEntity; + +/** + * For internal usage only. + * + * @see IEnergySink + * @see IEnergyConductor + */ +public interface IEnergyAcceptor extends IEnergyTile { + /** + * Determine if this acceptor can accept current from an adjacent emitter in a direction. + * + * @param emitter energy emitter + * @param direction direction the energy is being received from + */ + boolean acceptsEnergyFrom(TileEntity emitter, Direction direction); +} + diff --git a/src/common/ic2/api/IEnergyConductor.java b/src/common/ic2/api/IEnergyConductor.java new file mode 100644 index 00000000..3d755404 --- /dev/null +++ b/src/common/ic2/api/IEnergyConductor.java @@ -0,0 +1,51 @@ +package ic2.api; + +/** + * Tile entities which conduct energy pulses without buffering (mostly cables) have to implement this + * interface. + */ +public interface IEnergyConductor extends IEnergyAcceptor, IEnergyEmitter { + /** + * Energy loss for the conductor in EU per block. + * + * @return Energy loss + */ + double getConductionLoss(); + + /** + * Amount of energy the insulation will handle before shocking nearby players and mobs. + * + * @return Insulation energy absorption in EU + */ + int getInsulationEnergyAbsorption(); + + /** + * Amount of energy the insulation will handle before it is destroyed. + * Ensure that this value is greater than the insulation energy absorption + 64. + * + * @return Insulation-destroying energy in EU + */ + int getInsulationBreakdownEnergy(); + + /** + * Amount of energy the conductor will handle before it melts. + * + * @return Conductor-destroying energy in EU + */ + int getConductorBreakdownEnergy(); + + /** + * Remove the conductor's insulation if the insulation breakdown energy was exceeded. + * + * @see #getInsulationBreakdownEnergy() + */ + void removeInsulation(); + + /** + * Remove the conductor if the conductor breakdown energy was exceeded. + * + * @see #getConductorBreakdownEnergy() + */ + void removeConductor(); +} + diff --git a/src/common/ic2/api/IEnergyEmitter.java b/src/common/ic2/api/IEnergyEmitter.java new file mode 100644 index 00000000..94699b9a --- /dev/null +++ b/src/common/ic2/api/IEnergyEmitter.java @@ -0,0 +1,21 @@ +package ic2.api; + +import net.minecraft.src.TileEntity; + +/** + * For internal usage only. + * + * @see IEnergySource + * @see IEnergyConductor + */ +public interface IEnergyEmitter extends IEnergyTile { + /** + * Determine if this emitter can emit energy to an adjacent receiver. + * + * @param receiver receiver + * @param direction direction the receiver is from the emitter + * @return Whether energy should be emitted + */ + boolean emitsEnergyTo(TileEntity receiver, Direction direction); +} + diff --git a/src/common/ic2/api/IEnergySink.java b/src/common/ic2/api/IEnergySink.java new file mode 100644 index 00000000..a0ed9a55 --- /dev/null +++ b/src/common/ic2/api/IEnergySink.java @@ -0,0 +1,23 @@ +package ic2.api; + +/** + * Allows a tile entity (mostly a machine) to receive energy. + */ +public interface IEnergySink extends IEnergyAcceptor { + /** + * Determine whether the sink requires energy. + * + * @return Whether the sink is requiring energy + */ + boolean demandsEnergy(); + + /** + * Transfer energy to the sink. + * + * @param directionFrom direction from which the energy comes from + * @param amount energy to be transferred + * @return Energy not consumed (leftover) + */ + int injectEnergy(Direction directionFrom, int amount); +} + diff --git a/src/common/ic2/api/IEnergySource.java b/src/common/ic2/api/IEnergySource.java new file mode 100644 index 00000000..39d14a20 --- /dev/null +++ b/src/common/ic2/api/IEnergySource.java @@ -0,0 +1,15 @@ +package ic2.api; + +/** + * Allows a tile entity (mostly a generator) to emit energy. + */ +public interface IEnergySource extends IEnergyEmitter { + /** + * Maximum energy output provided by the source. + * If unsure, use Integer.MAX_VALUE. + * + * @return Maximum energy output + */ + int getMaxEnergyOutput(); +} + diff --git a/src/common/ic2/api/IEnergyStorage.java b/src/common/ic2/api/IEnergyStorage.java new file mode 100644 index 00000000..a89bd7dc --- /dev/null +++ b/src/common/ic2/api/IEnergyStorage.java @@ -0,0 +1,27 @@ +package ic2.api; + +/** + * Interface implemented by the tile entity of energy storage blocks. + */ +public interface IEnergyStorage { + /** + * Get the amount of energy currently stored in the block. + * + * @return Energy stored in the block + */ + public int getStored(); + + /** + * Get the maximum amount of energy the block can store. + * + * @return Maximum energy stored + */ + public int getCapacity(); + + /** + * Get the block's energy output. + * + * @return Energy output in EU/t + */ + public int getOutput(); +} diff --git a/src/common/ic2/api/IEnergyTile.java b/src/common/ic2/api/IEnergyTile.java new file mode 100644 index 00000000..10445432 --- /dev/null +++ b/src/common/ic2/api/IEnergyTile.java @@ -0,0 +1,18 @@ +package ic2.api; + +/** + * For internal usage only. + * + * @see IEnergySink + * @see IEnergySource + * @see IEnergyConductor + */ +public interface IEnergyTile { + /** + * Determine if this tile entity has been added to the energy network + * + * @return Whether the tile entity has been added + */ + boolean isAddedToEnergyNet(); +} + diff --git a/src/common/ic2/api/IMetalArmor.java b/src/common/ic2/api/IMetalArmor.java new file mode 100644 index 00000000..fe8db2ed --- /dev/null +++ b/src/common/ic2/api/IMetalArmor.java @@ -0,0 +1,20 @@ +package ic2.api; + +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ItemStack; + +/** + * Armor items implementing this can be considered metal armor. + * + * Currently used for determining which boots can be used to slide up a magnetic pole. + */ +public interface IMetalArmor { + /** + * Determine if the given armor piece is metal armor. + * + * @param itemstack Armor piece as worn by the player + * @param player The player + * @return Whether the armor piece is metal armor + */ + public boolean isMetalArmor(ItemStack itemstack, EntityPlayer player); +} diff --git a/src/common/ic2/api/INetworkClientTileEntityEventListener.java b/src/common/ic2/api/INetworkClientTileEntityEventListener.java new file mode 100644 index 00000000..594f1d7f --- /dev/null +++ b/src/common/ic2/api/INetworkClientTileEntityEventListener.java @@ -0,0 +1,17 @@ +package ic2.api; + +import net.minecraft.src.EntityPlayer; + +/** + * Allows a tile entity to receive network events received from clients. + */ +public interface INetworkClientTileEntityEventListener { + /** + * Called when a network event is received. + * + * @param player client which sent the event + * @param event event ID + */ + void onNetworkEvent(EntityPlayer player, int event); +} + diff --git a/src/common/ic2/api/INetworkDataProvider.java b/src/common/ic2/api/INetworkDataProvider.java new file mode 100644 index 00000000..da393868 --- /dev/null +++ b/src/common/ic2/api/INetworkDataProvider.java @@ -0,0 +1,18 @@ +package ic2.api; + +import java.util.List; + +/** + * Tile entities which want to synchronized specific fields between client and server have to implement this. + * + * The fields don't update themselves, a field update must be sent every time a synchronized field changes. + */ +public interface INetworkDataProvider { + /** + * Get the list of synchronized fields. + * + * @return Names of the synchronized fields + */ + List getNetworkedFields(); +} + diff --git a/src/common/ic2/api/INetworkItemEventListener.java b/src/common/ic2/api/INetworkItemEventListener.java new file mode 100644 index 00000000..a0126b39 --- /dev/null +++ b/src/common/ic2/api/INetworkItemEventListener.java @@ -0,0 +1,18 @@ +package ic2.api; + +import net.minecraft.src.EntityPlayer; + +/** + * Allows an item to receive network events received from the server. + */ +public interface INetworkItemEventListener { + /** + * Called when a network event is received. + * + * @param metaData item metadata + * @param player player containing the item + * @param event event ID + */ + void onNetworkEvent(int metaData, EntityPlayer player, int event); +} + diff --git a/src/common/ic2/api/INetworkTileEntityEventListener.java b/src/common/ic2/api/INetworkTileEntityEventListener.java new file mode 100644 index 00000000..4433cb89 --- /dev/null +++ b/src/common/ic2/api/INetworkTileEntityEventListener.java @@ -0,0 +1,14 @@ +package ic2.api; + +/** + * Allows a tile entity to receive network events received from the server. + */ +public interface INetworkTileEntityEventListener { + /** + * Called when a network event is received. + * + * @param event Event ID + */ + void onNetworkEvent(int event); +} + diff --git a/src/common/ic2/api/INetworkUpdateListener.java b/src/common/ic2/api/INetworkUpdateListener.java new file mode 100644 index 00000000..be2adb88 --- /dev/null +++ b/src/common/ic2/api/INetworkUpdateListener.java @@ -0,0 +1,14 @@ +package ic2.api; + +/** + * Allows a tile entity to receive field sync updates received from the server. + */ +public interface INetworkUpdateListener { + /** + * Called when a field is synchronized. + * + * @param field field synchronized + */ + void onNetworkUpdate(String field); +} + diff --git a/src/common/ic2/api/IPaintableBlock.java b/src/common/ic2/api/IPaintableBlock.java new file mode 100644 index 00000000..9ee2a6b0 --- /dev/null +++ b/src/common/ic2/api/IPaintableBlock.java @@ -0,0 +1,21 @@ +package ic2.api; + +import net.minecraft.src.World; + +/** + * Allows a block to be painted by a Painter. + */ +public interface IPaintableBlock +{ + /** + * Color the block. + * + * @param world block's world + * @param x block X position + * @param y block Y position + * @param z block Z position + * @param color painter color, same as dye metadata values + * @return Whether the block was painted and the painter should be damaged + */ + public boolean colorBlock(World world, int x, int y, int z, int color); +} diff --git a/src/common/ic2/api/IReactor.java b/src/common/ic2/api/IReactor.java new file mode 100644 index 00000000..8c6a9291 --- /dev/null +++ b/src/common/ic2/api/IReactor.java @@ -0,0 +1,134 @@ +package ic2.api; + +import net.minecraft.src.ChunkCoordinates; +import net.minecraft.src.ItemStack; +import net.minecraft.src.World; + +/** + * Interface implemented by the tile entity of nuclear reactors. + */ +public interface IReactor { + /** + * Get the reactor's position in the world. + * + * @return Position of the reactor + */ + public ChunkCoordinates getPosition(); + + /** + * Get the reactor's corresponding world. + * + * @return The reactor's world + */ + public World getWorld(); + + /** + * Get the reactor's heat. + * + * @return The reactor's heat + */ + public int getHeat(); + + /** + * Set the reactor's heat. + * + * @param heat reactor heat + */ + public void setHeat(int heat); + + /** + * Increase the reactor's heat. + * + * Use negative values to decrease. + * + * @param amount amount of heat to add + * @return The reactor's heat after adding the specified amount + */ + public int addHeat(int amount); + + /** + * Get the reactor's maximum heat before exploding. + * + * @return Maximum heat value + */ + public int getMaxHeat(); + + /** + * Set the reactor's stored maxHeat variable. + * Used by plating to increase the reactors MaxHeat capacity. + * Needs to be called during each cycle process. + */ + public void setMaxHeat(int newMaxHeat); + + /** + * Get's the reactor's HEM (Heat Effect Modifier) + * Basic value is 1.0F. + * Reducing the value causes a weakening/reduction of the heat-based sideeffects of reactors + * (F.e. water evaporation, melting, damaging entitys, etc) + * + * @return HEM + */ + public float getHeatEffectModifier(); + + /** + * Set's the reactor's HEM + * Needs to be called during each cycle process. + */ + public void setHeatEffectModifier(float newHEM); + + /** + * Get the reactor's energy output. + * + * @return Energy output in EU/t + */ + public int getOutput(); + + /** + * Add's the given amount of energy to the Reactor's output. + * + * @return Energy output after adding the value, in EU/t + */ + public int addOutput(int energy); + + /** + * Get's the EU worth of a single basic Uranium pulse + * Please use this variable to alter energy output, as it represents the config modifiers as well. + */ + public int getPulsePower(); + + /** + * Get the item at the specified grid coordinates. + * + * @param x X position of the item + * @param y Y position of the item + * @return The item or null if there is no item + */ + public ItemStack getItemAt(int x, int y); + + /** + * Set the item at the specified grid coordinates. + * + * @param x X position of the item + * @param y Y position of the item + * @param item The item to set. + */ + public void setItemAt(int x, int y, ItemStack item); + + /** + * Explode the reactor. + */ + public void explode(); + + /** + * Get the reactor's tick rate (game ticks per reactor tick). + * + * @return Tick rate + */ + public int getTickRate(); + + /** + * Get whether the reactor is active and supposed to produce energy + * @return Whether the reactor is active + */ + public boolean produceEnergy(); +} diff --git a/src/common/ic2/api/IReactorChamber.java b/src/common/ic2/api/IReactorChamber.java new file mode 100644 index 00000000..fad40c27 --- /dev/null +++ b/src/common/ic2/api/IReactorChamber.java @@ -0,0 +1,13 @@ +package ic2.api; + +/** + * Interface implemented by the reactor chamber tile entity. + */ +public interface IReactorChamber { + /** + * Get the chamber's reactor. + * + * @return The reactor + */ + public IReactor getReactor(); +} diff --git a/src/common/ic2/api/IReactorComponent.java b/src/common/ic2/api/IReactorComponent.java new file mode 100644 index 00000000..26de8f2c --- /dev/null +++ b/src/common/ic2/api/IReactorComponent.java @@ -0,0 +1,97 @@ +package ic2.api; + +import net.minecraft.src.ItemStack; + +/** + * Design custom Reactor components by implementing this Interface + * Items implementing the interface will not be ejected from Reactors in their clean-up + * and can/will be interacted with by other elements, f.e. Uranium Cells. + * + * All IC2 ReactorComponents implement and use this Interface + * + */ +public interface IReactorComponent +{ + /** + * Called by reactor upon iterating through it's inventory (every cycle). + * Perform all necessary calculation/interaction here + * + * @param reactor Reference to the Reactor + * @param yourStack Reference to the specific instance of iterated ItemStack + * @param x X-coordinate of the stack in the grid + * @param y Y-coordinate of the stack in the grid + */ + public void processChamber(IReactor reactor, ItemStack yourStack, int x, int y); + + /** + * Can be called by Uranium-Components who attempt to generate energy by pulsing to other components. + * Uranium-Uranium interaction (f.e.) uses this method. + * @param reactor Reference to the Reactor + * @param yourStack Reference to the specific instance of called ItemStack + * @param pulsingStack Reference to the specific instance of pulsing ItemStack + * @param youX X-coordinate of your stack in the grid + * @param youY Y-coordinate of your stack in the grid + * @param pulseX X-coordinate of pulsing stack in the grid + * @param pulseY Y-coordinate of pulsing stack in the grid + * @return true if this component reacts to the pulse (and pulse is therefore meant to produce heat) + */ + public boolean acceptUraniumPulse(IReactor reactor, ItemStack yourStack, ItemStack pulsingStack, int youX, int youY, int pulseX, int pulseY); + + /** + * Called by components to determine whether your component can be heated. + * @param reactor Reference to the Reactor + * @param yourStack Reference to the specific instance of iterated ItemStack + * @param x X-coordinate of the stack in the grid + * @param y Y-coordinate of the stack in the grid + * @return true if your component can take heat + */ + public boolean canStoreHeat(IReactor reactor, ItemStack yourStack, int x, int y); + + /** + * Called by heat-switches to determine how much heat to distribute into which direction. + * Please return the maximum capacity of your heat-containing component here. + * @param reactor Reference to the Reactor + * @param yourStack Reference to the specific instance of iterated ItemStack + * @param x X-coordinate of the stack in the grid + * @param y Y-coordinate of the stack in the grid + * @return Maximum heat + */ + public int getMaxHeat(IReactor reactor, ItemStack yourStack, int x, int y); + + /** + * Called by heat-switches to determine how much heat to distribute into which direction. + * Please return the current amount of heat stored in this component + * @param reactor Reference to the Reactor + * @param yourStack Reference to the specific instance of iterated ItemStack + * @param x X-coordinate of the stack in the grid + * @param y Y-coordinate of the stack in the grid + * @return Current Heat + */ + public int getCurrentHeat(IReactor reactor, ItemStack yourStack, int x, int y); + + /** + * Called by components to distribute heat to your component. + * Perform heating-calculations and increase your heat (dmg) level accordingly. + * This method will as well be called to REDUCE heat, by providing a negative amount. + * + * @param reactor Reference to the Reactor + * @param yourStack Reference to the specific instance of iterated ItemStack + * @param x X-coordinate of the stack in the grid + * @param y Y-coordinate of the stack in the grid + * @param heat Amount of heat to be added (may be negative to subtract heat) + * @return 0 if the 'order' was accepted, return >0 to indicate the 'remaining' heat which couldn't be absorbed (and vice versa for <0) + */ + public int alterHeat(IReactor reactor, ItemStack yourStack, int x, int y, int heat); + + /** + * Called upon reactor explosion + * Alter the explosion size. + * Returning a float 0 < f < 1 will be counted as multiplier. + * Anything else will be counted as a flat addition (in case of <0 = reduction). + * + * @param reactor Reference to the Reactor + * @param yourStack Reference to the specific instance of iterated ItemStack + * @return your explosion modifier + */ + public float influenceExplosion(IReactor reactor, ItemStack yourStack); +} diff --git a/src/common/ic2/api/ITerraformingBP.java b/src/common/ic2/api/ITerraformingBP.java new file mode 100644 index 00000000..490d4ee2 --- /dev/null +++ b/src/common/ic2/api/ITerraformingBP.java @@ -0,0 +1,35 @@ +package ic2.api; + +import net.minecraft.src.World; + +/** + * Allows an item to act as a terraformer blueprint. + */ +public interface ITerraformingBP +{ + /** + * Get the energy consumption per operation of the blueprint. + * + * @return Energy consumption in EU + */ + public abstract int getConsume(); + + /** + * Get the maximum range of the blueprint. + * Should be a divisor of 5. + * + * @return Maximum range in blocks + */ + public abstract int getRange(); + + /** + * Perform the terraforming operation. + * + * @param world world to terraform + * @param x X position to terraform + * @param z Z position to terraform + * @param yCoord Y position of the terraformer + * @return Whether the operation was successful and the terraformer should consume energy. + */ + public abstract boolean terraform(World world, int x, int z, int yCoord); +} diff --git a/src/common/ic2/api/IWrenchable.java b/src/common/ic2/api/IWrenchable.java new file mode 100644 index 00000000..f2925361 --- /dev/null +++ b/src/common/ic2/api/IWrenchable.java @@ -0,0 +1,50 @@ +package ic2.api; + +import net.minecraft.src.EntityPlayer; + +/** + * Allows a tile entity to make use of the wrench's removal and rotation functions. + */ +public interface IWrenchable { + /** + * Determine if the wrench can be used to set the block's facing. + * Called before wrenchCanRemove(). + * + * @param entityPlayer player using the wrench + * @param side block's side the wrench was clicked on + * @return Whether the wrenching was done and the wrench should be damaged + */ + boolean wrenchCanSetFacing(EntityPlayer entityPlayer, int side); + + /** + * Get the block's facing. + * + * @return Block facing + */ + short getFacing(); + + /** + * Set the block's facing + * + * @param facing facing to set the block to + */ + void setFacing(short facing); + + /** + * Determine if the wrench can be used to remove the block. + * Called if wrenchSetFacing fails. + * + * @param entityPlayer player using the wrench + * @return Whether the wrenching was done and the wrench should be damaged + */ + boolean wrenchCanRemove(EntityPlayer entityPlayer); + + /** + * Determine the probability to drop the block as it is. + * The first entry in getBlockDropped will be replaced by blockid:meta if the drop is successful. + * + * @return Probability from 0 to 1 + */ + float getWrenchDropRate(); +} + diff --git a/src/common/ic2/api/Ic2Recipes.java b/src/common/ic2/api/Ic2Recipes.java new file mode 100644 index 00000000..6d286cb1 --- /dev/null +++ b/src/common/ic2/api/Ic2Recipes.java @@ -0,0 +1,358 @@ +package ic2.api; + +import java.lang.reflect.Array; +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; + +import net.minecraft.src.Block; +import net.minecraft.src.Item; +import net.minecraft.src.ItemStack; + +/** + * Provides access to Compressor, Extractor and Macerator recipes, as well as charge-aware recipes + * and the Recycler blacklist. + * + * The recipes are only valid after IC2 has been loaded and are metadata and stack size sensitive, + * for example you can create a recipe to compress 3 wooden planks into 2 sticks. + */ +public final class Ic2Recipes { + /** + * Add a charge-aware shaped crafting recipe. + */ + public static void addCraftingRecipe(ItemStack result, Object... args) { + try { + Class.forName(getPackage() + ".common.AdvRecipe").getMethod("addAndRegister", ItemStack.class, Array.newInstance(Object.class, 0).getClass()).invoke(null, result, args); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Add a charge-aware shapeless crafting recipe. + */ + public static void addShapelessCraftingRecipe(ItemStack result, Object... args) { + try { + Class.forName(getPackage() + ".common.AdvShapelessRecipe").getMethod("addAndRegister", ItemStack.class, Array.newInstance(Object.class, 0).getClass()).invoke(null, result, args); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Retrieve the registered Compressor recipes. + * + * @return Recipe list as a list of map entries, the key is the input and the value is the output + */ + public static List > getCompressorRecipes() { + if (TileEntityCompressor_recipes == null) { + try { + TileEntityCompressor_recipes = (List >) Class.forName(getPackage() + ".common.TileEntityCompressor").getField("recipes").get(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + return TileEntityCompressor_recipes; + } + + /** + * Add a Compressor recipe. + * + * @param input Input + * @param output Output + */ + public static void addCompressorRecipe(ItemStack input, ItemStack output) { + getCompressorRecipes().add(new AbstractMap.SimpleEntry(input, output)); + } + + + /** + * Get the Compressor output for an input item. + * + * @param input input item + * @param adjustInput remove the processing requirements from input + * @return Output item as an independent stack + */ + public static ItemStack getCompressorOutputFor(ItemStack input, boolean adjustInput) { + return getOutputFor(input, adjustInput, getCompressorRecipes()); + } + + /** + * Retrieve the registered Extractor recipes. + * + * @return Recipe list as a list of map entries, the key is the input and the value is the output + */ + public static List > getExtractorRecipes() { + if (TileEntityExtractor_recipes == null) { + try { + TileEntityExtractor_recipes = (List >) Class.forName(getPackage() + ".common.TileEntityExtractor").getField("recipes").get(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + return TileEntityExtractor_recipes; + } + + /** + * Add a Extractor recipe. + * + * @param input Input + * @param output Output + */ + public static void addExtractorRecipe(ItemStack input, ItemStack output) { + getExtractorRecipes().add(new AbstractMap.SimpleEntry(input, output)); + } + + + /** + * Get the Extractor output for an input item. + * + * @param input input item + * @param adjustInput remove the processing requirements from input + * @return Output item as an independent stack + */ + public static ItemStack getExtractorOutputFor(ItemStack input, boolean adjustInput) { + return getOutputFor(input, adjustInput, getExtractorRecipes()); + } + + /** + * Retrieve the registered Macerator recipes. + * + * @return Recipe list as a list of map entries, the key is the input and the value is the output + */ + public static List > getMaceratorRecipes() { + if (TileEntityMacerator_recipes == null) { + try { + TileEntityMacerator_recipes = (List >) Class.forName(getPackage() + ".common.TileEntityMacerator").getField("recipes").get(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + return TileEntityMacerator_recipes; + } + + /** + * Add a Macerator recipe. + * + * @param input Input + * @param output Output + */ + public static void addMaceratorRecipe(ItemStack input, ItemStack output) { + getMaceratorRecipes().add(new AbstractMap.SimpleEntry(input, output)); + } + + + /** + * Get the Macerator output for an input item. + * + * @param input input item + * @param adjustInput remove the processing requirements from input + * @return Output item as an independent stack + */ + public static ItemStack getMaceratorOutputFor(ItemStack input, boolean adjustInput) { + return getOutputFor(input, adjustInput, getMaceratorRecipes()); + } + + + private static ItemStack getOutputFor(ItemStack input, boolean adjustInput, List > recipeList) { + assert input != null; + + for (Map.Entry entry: recipeList) { + if (entry.getKey().isItemEqual(input) && input.stackSize >= entry.getKey().stackSize) { + if (adjustInput) input.stackSize -= entry.getKey().stackSize; + + return entry.getValue().copy(); + } + } + + return null; + } + + + /** + * Retrieve the registered Recycler blacklist items. + * + * @return Blacklist + */ + public static List getRecyclerBlacklist() { + if (TileEntityRecycler_blacklist == null) { + try { + TileEntityRecycler_blacklist = (List) Class.forName(getPackage() + ".common.TileEntityRecycler").getField("blacklist").get(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + return TileEntityRecycler_blacklist; + } + + /** + * Add an item stack to the Recycler blacklist. + * + * @param newBlacklistedItem item stack to add + */ + public static void addRecyclerBlacklistItem(ItemStack newBlacklistedItem) { + getRecyclerBlacklist().add(newBlacklistedItem); + } + + /** + * Add an item to the Recycler blacklist. + * + * @param newBlacklistedItem item to add + */ + public static void addRecyclerBlacklistItem(Item newBlacklistedItem) { + addRecyclerBlacklistItem(new ItemStack(newBlacklistedItem, 1, -1)); + } + + /** + * Add a block to the Recycler blacklist. + * + * @param newBlacklistedBlock block to add + */ + public static void addRecyclerBlacklistItem(Block newBlacklistedBlock) { + addRecyclerBlacklistItem(new ItemStack(newBlacklistedBlock, 1, -1)); + } + + + /** + * Determine if an item is in the Recycler blacklist. + * + * @param itemStack item to check + * @return Whether the item is blacklisted or not + */ + public static boolean isRecyclerInputBlacklisted(ItemStack itemStack) { + for (ItemStack blackItem: getRecyclerBlacklist()) { + if (itemStack.isItemEqual(blackItem)) return true; + } + + return false; + } + + /** + * Retrieve the registered Scrap Box drops. + * + * @return Drops as a list of item stack and float (chance) pairs + */ + public static List> getScrapboxDrops() { + try { + return (List>) Class.forName(getPackage() + ".common.ItemScrapbox").getMethod("getDropList").invoke(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /* + * Reference scrap box chance values: + * + * 0.1: Diamond + * 0.5: Cake, Gold Helmet, Iron Ore, Gold Ore + * 1.0: Wooden tools, Soul Sand, Sign, Leather, Feather, Bone + * 1.5: Apple, Bread + * 2.0: Netherrack, Rotten Flesh + * 3.0: Grass, Gravel + * 4.0: Stick + * 5.0: Dirt, Wooden Hoe + */ + + /** + * Add an item stack to the Scrap Box drops. + * + * @param dropItem item stack to add + * @param chance chance for the item to drop, see the code comments for reference values + */ + public static void addScrapboxDrop(ItemStack dropItem, float chance) { + try { + Class.forName(getPackage() + ".common.ItemScrapbox").getMethod("addDrop", ItemStack.class, float.class).invoke(null, dropItem, chance); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Add an item to the Scrap Box drops. + * + * @param dropItem item to add + * @param chance chance for the item to drop, see the code comments for reference values + */ + public static void addScrapboxDrop(Item dropItem, float chance) { + addScrapboxDrop(new ItemStack(dropItem, 1), chance); + } + + /** + * Add a block to the Scrap Box drops. + * + * @param dropItem item to add + * @param chance chance for the item to drop, see the code comments for reference values + */ + public static void addScrapboxDrop(Block dropItem, float chance) { + addScrapboxDrop(new ItemStack(dropItem), chance); + } + + /** + * Retrieve the registered Mass Fabricator amplifiers. + * + * @return Amplifiers as a list of item stack and integer (amplifier value) pairs + */ + public static List > getMatterAmplifiers() { + if (TileEntityMatter_amplifiers == null) { + try { + TileEntityMatter_amplifiers = (List >) Class.forName(getPackage() + ".common.TileEntityMatter").getField("amplifiers").get(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + return TileEntityMatter_amplifiers; + } + + /** + * Add an item stack to the Mass Fabricator amplifiers. + * + * @param amplifierItem item stack to add + * @param value amplifier value for the item, scrap is 5000 + */ + public static void addMatterAmplifier(ItemStack amplifierItem, int value) { + getMatterAmplifiers().add(new AbstractMap.SimpleEntry(amplifierItem, value)); + } + + /** + * Add an item to the Mass Fabricator amplifiers. + * + * @param amplifierItem item to add + * @param value amplifier value for the item, scrap is 5000 + */ + public static void addMatterAmplifier(Item amplifierItem, int value) { + addMatterAmplifier(new ItemStack(amplifierItem, 1, -1), value); + } + + /** + * Add a block to the Mass Fabricator amplifiers. + * + * @param amplifierItem item to add + * @param value amplifier value for the item, scrap is 5000 + */ + public static void addMatterAmplifier(Block amplifierItem, int value) { + addMatterAmplifier(new ItemStack(amplifierItem, 1, -1), value); + } + + /** + * Get the base IC2 package name, used internally. + * + * @return IC2 package name, if unable to be determined defaults to ic2 + */ + private static String getPackage() { + Package pkg = Ic2Recipes.class.getPackage(); + if (pkg != null) return pkg.getName().substring(0, pkg.getName().lastIndexOf('.')); + else return "ic2"; + } + + private static List > TileEntityCompressor_recipes; + private static List > TileEntityExtractor_recipes; + private static List > TileEntityMacerator_recipes; + private static List TileEntityRecycler_blacklist; + private static List > TileEntityMatter_amplifiers; +} + diff --git a/src/common/ic2/api/Items.java b/src/common/ic2/api/Items.java new file mode 100644 index 00000000..5835eb5d --- /dev/null +++ b/src/common/ic2/api/Items.java @@ -0,0 +1,401 @@ +package ic2.api; + +import net.minecraft.src.ItemStack; + +/** + * Provides access to IC2 blocks and items. + * + * Some items can be acquired through the ore dictionary which is the recommended way. + * The items are initialized while IC2 is being loaded - try to use ModsLoaded() or load your mod after IC2. + * Some blocks/items can be disabled by a config setting, so it's recommended to check if they're null first. + * + * Getting the associated Block/Item for an ItemStack x: + * Blocks: Block.blocksList[x.itemID] + * Items: x.getItem() + */ +public final class Items { + /** + * Get an ItemStack for a specific item name, example: Items.getItem("resin") + * See the list below for item names. + * Make sure to copy() the ItemStack if you want to modify it. + * + * @param name item name + * @return The item or null if the item does not exist or an error occurred + */ + public static ItemStack getItem(String name) { + try { + if (Ic2Items == null) Ic2Items = Class.forName(getPackage() + ".common.Ic2Items"); + + Object ret = Ic2Items.getField(name).get(null); + + if (ret instanceof ItemStack) { + return (ItemStack) ret; + } else { + return null; + } + } catch (Exception e) { + System.out.println("IC2 API: Call getItem failed for "+name); + + return null; + } + } + + /* Possible values: + + ----- blocks ----- + + ores + copperOre Copper Ore block, currently not meta sensitive, meta in ItemStack set to 0, ore dictionary: oreCopper, null with enableWorldGenOreCopper=false + tinOre Tin Ore block, currently not meta sensitive, meta in ItemStack set to 0, ore dictionary: oreTin, null with enableWorldGenOreTin=false + uraniumOre Tin Ore block, currently not meta sensitive, meta in ItemStack set to 0, ore dictionary: oreUranium, null with enableWorldGenOreUranium=false + + rubber related + Rubber wood block, meta reflects the state, meta in ItemStack set to 0, ore dictionary: woodRubber (with meta 0), null with enableWorldGenTreeRubber=false + dropped (as an item) -> metadata 0 + block, no resin spot -> metadata 0 or 1 + block, wet resin spot -> metadata 2-5 (according to the side) + block, dry resin spot -> metadata 8-11 (wet state + 6) + + rubberWood + rubberLeaves Rubber Leaves block, currently not meta sensitive, meta in ItemStack set to 0, null with enableWorldGenTreeRubber=false + rubberSapling Rubber Sapling block, currently not meta sensitive, meta in ItemStack set to 0, null with enableWorldGenTreeRubber=false + resinSheet Resin Sheet block, currently not meta sensitive + rubberTrampoline Rubber Trampoline block, meta reflects internal state, meta in ItemStack set to 0 + + building/storage + ironFence Iron Fence block, currently not meta sensitive + + reinforcedStone Reinforced Stone block, currently not meta sensitive + reinforcedGlass Reinforced Glass block, currently not meta sensitive + reinforcedDoorBlock Reinforced Door block, meta reflects the state (see vanilla doors), meta in ItemStack set to 0 + + constructionFoam Construction Foam block, currently not meta sensitive + constructionFoamWall Construction Foam Wall block, meta = color, implements IPaintableBlock + scaffold Scaffold block, meta reflects internal physical model data + + bronzeBlock Bronze block, meta sensitive + copperBlock Copper block, meta sensitive + tinBlock Tin block, meta sensitive + uraniumBlock Uranium block, meta sensitive + + cables (when placed as a block, inventory items are different TE implements IEnergyConductor) + copperCableBlock Copper Cable block, meta sensitive + insulatedCopperCableBlock Insulated Copper Cable block, meta sensitive + + goldCableBlock Gold Cable block, meta sensitive + insulatedGoldCableBlock Insulated Gold Cable block, meta sensitive + doubleInsulatedGoldCableBlock Double Insulated Gold Cable block, meta sensitive + + ironCableBlock Iron Cable block, meta sensitive + insulatedIronCableBlock Insulated Iron Cable block, meta sensitive + doubleInsulatedIronCableBlock Double Insulated Iron Cable block, meta sensitive + trippleInsulatedIronCableBlock Tripple Insulated Iron Cable block, meta sensitive + + glassFiberCableBlock Glass Fiber Cable block, meta sensitive + + tinCableBlock Tin Cable block, meta sensitive + + detectorCableBlock Detector Cable block, meta sensitive + splitterCableBlock Splitter Cable block, meta sensitive + + generators + related (TE implements IEnergySource ex. reactorChamber) + generator Generator block, meta sensitive + geothermalGenerator Geothermal Generator block, meta sensitive + waterMill Water Mill block, meta sensitive + solarPanel Solar Panel block, meta sensitive + windMill Wind Mill block, meta sensitive + nuclearReactor Nuclear Reactor block, meta sensitive + reactorChamber Reactor Chamber block, currently not meta sensitive + + energy storages (TE implements IEnergySource and IEnergyConductor) + batBox BatBox block, meta sensitive + mfeUnit MFE Unit block, meta sensitive + mfsUnit MFS Unit block, meta sensitive + + transformers (TE implements IEnergySource and IEnergyConductor) + lvTransformer LV Transformer block, meta sensitive + mvTransformer MV Transformer block, meta sensitive + hvTransformer HV Transformer block, meta sensitive + + machines + related (TE implements IEnergySink ex. machine, miningPipe, miningPipeTip) + machine Machine block, meta sensitive + advancedMachine Advanced Machine block, meta sensitive + + ironFurnace Iron Furnace block, meta sensitive + electroFurnace Electro Furnace block, meta sensitive + macerator Macerator block, meta sensitive + extractor Extractor block, meta sensitive + compressor Compressor block, meta sensitive + canner Canner block, meta sensitive + miner Miner block, meta sensitive + pump Pump block, meta sensitive + magnetizer Magnetizer block, meta sensitive + electrolyzer Electrolyzer block, meta sensitive + recycler Recycler block, meta sensitive + inductionFurnace Induction Furnace block, meta sensitive + massFabricator Mass Fabricator block, meta sensitive + terraformer Terraformer block, meta sensitive + teleporter Teleporter block, meta sensitive + teslaCoil Tesla Coil block, meta sensitive + luminator Passive (dark) Luminator block, meta = facing + activeLuminator Active (bright) Luminator block, meta = facing + + miningPipe Mining Pipe block, currently not meta sensitive, meta in ItemStack set to 0 + miningPipeTip Mining Pipe Tip block, currently not meta sensitive, meta in ItemStack set to 0 + + personal blocks + personalSafe Personal Safe block, meta sensitive + tradeOMat Trade-O-Mat block, meta sensitive + energyOMat Energy-O-Mat block, meta sensitive + + explosives + industrialTnt Industrial TNT block, currently not meta sensitive + nuke Nuke block, currently not meta sensitive + dynamiteStick Dynamite Stick block, meta = placement, meta in ItemStack set to 0 + dynamiteStickWithRemote Dynamite Stick with Remote block, meta = placement, meta in ItemStack set to 0 + + Agriculture Stuff + crop Crop Block, empty, not meta sensitive + + + ----- items ----- + + rubber + related + resin Resin item, currently not meta sensitive + rubber Rubber item, currently not meta sensitive, ore dictionary: itemRubber + + ore drops + uraniumDrop Uranium Drop item, currently not meta sensitive, ore dictionary: itemDropUranium + + dusts + bronzeDust Bronze Dust item, currently not meta sensitive + clayDust Clay Dust item, currently not meta sensitive + coalDust Coal Dust item, currently not meta sensitive + copperDust Copper Dust item, currently not meta sensitive + goldDust Gold Dust item, currently not meta sensitive + ironDust Iron Dust item, currently not meta sensitive + silverDust Silver Dust item, currently not meta sensitive + smallIronDust Small Iron Dust item, currently not meta sensitive + tinDust Tin Dust item, currently not meta sensitive + hydratedCoalDust Hydrated Coal Dust item, currently not meta sensitive + + ingots + refinedIronIngot Refined Iron Ingot item, currently not meta sensitive, ore dictionary: ingotRefinedIron + copperIngot Copper Ingot item, currently not meta sensitive, ore dictionary: ingotCopper + tinIngot Tin Ingot item, currently not meta sensitive, ore dictionary: ingotTin + bronzeIngot Bronze Ingot item, currently not meta sensitive, ore dictionary: ingotBronze + mixedMetalIngot Mixed Metal Ingot item, currently not meta sensitive + uraniumIngot Uranium Ingot item, currently not meta sensitive, ore dictionary: ingotUranium + + tools/weapons (without electric tools) + treetap Treetap item, meta = damage value + wrench Wrench item, meta = damage value + cutter Insulation Cutter item, meta = damage value + constructionFoamSprayer Construction Foam Sprayer item, meta = charges (as of v1.45) + + bronzePickaxe Bronze Pickaxe item, meta = damage value + bronzeAxe Bronze Axe item, meta = damage value + bronzeSword Bronze Sword item, meta = damage value + bronzeShovel Bronze Shovel item, meta = damage value + bronzeHoe Bronze Hoe item, meta = damage value + + el. tools/devices/weapons + miningDrill Mining Drill item, meta = visual charge indicator, implements IElectricItem + diamondDrill Diamond Tipped Mining Drill item, meta = visual charge indicator, implements IElectricItem + chainsaw Chainsaw item, meta = visual charge indicator, implements IElectricItem + electricWrench Electric Wrench item, meta = visual charge indicator, implements IElectricItem + electricTreetap Electric Treetap item, meta = visual charge indicator, implements IElectricItem + miningLaser Mining Laser item, meta = visual charge indicator, implements IElectricItem + + ecMeter EC-Mater item, currently not meta sensitive + odScanner Ore Density Scanner item, meta = damage value for charge level, implements IElectricItem + ovScanner Ore Value Scanner item, meta = visual charge indicator, implements IElectricItem + + frequencyTransmitter Frequency Transmitter item, currently not meta sensitive + + nanoSaber Idle Nano Saber item, meta = visual charge indicator, implements IElectricItem + enabledNanoSaber Enabled Nano Saber item, meta = visual charge indicator, implements IElectricItem + + armor/wearable + rubberBoots Rubber Boots item, meta = damage value + + bronzeHelmet Bronze Helmet Armor item, meta = damage value + bronzeChestplate Bronze Chestplate Armor item, meta = damage value + bronzeLeggings Bronze Leggings Armor item, meta = damage value + bronzeBoots Bronze Boots Armor item, meta = damage value + + compositeArmor Composite Armor item, meta = damage value for charge level + + nanoHelmet Nano Helmet Armor item, meta = visual charge indicator, implements IElectricItem + nanoBodyarmor Nano Bodyarmor item, meta = visual charge indicator, implements IElectricItem + nanoLeggings Nano Leggings Armor item, meta = visual charge indicator, implements IElectricItem + nanoBoots Nano Boots Armor item, meta = visual charge indicator, implements IElectricItem + + quantumHelmet Quantum Helmet Armor item, meta = visual charge indicator, implements IElectricItem + quantumBodyarmor Quantum Bodyarmor item, meta = visual charge indicator, implements IElectricItem + quantumLeggings Quantum Leggings Armor item, meta = visual charge indicator, implements IElectricItem + quantumBoots Quantum Boots Armor item, meta = visual charge indicator, implements IElectricItem + + jetpack Jetpack item, meta = damage value for fuel level + electricJetpack Electric Jetpack item, meta = visual charge indicator, implements IElectricItem + + batPack BatPack item, meta = visual charge indicator, implements IElectricItem, can provide energy + lapPack LapPack item, meta = visual charge indicator, implements IElectricItem, can provide energy + + cfPack CF Pack item, meta = charges (as of v1.45) + + solarHelmet Solar Helmet item, currently not meta sensitive + staticBoots Static Boots item, currently not meta sensitive + + batteries + reBattery Empty RE Battery item, currently not meta sensitive, implements IElectricItem + chargedReBattery RE Battery item, meta = visual charge indicator, implements IElectricItem, can provide energy + energyCrystal Energy Crystal item, meta = visual charge indicator, implements IElectricItem, can provide energy + lapotronCrystal Lapotron Crystal item, meta = visual charge indicator, implements IElectricItem, can provide energy + suBattery SU Battery item, currently not meta sensitive + + cables + copperCableItem Copper Cable item, meta sensitive + insulatedCopperCableItem Insulated Copper Cable item, meta sensitive + + goldCableItem Gold Cable item, meta sensitive + insulatedGoldCableItem Insulated Gold Cable item, meta sensitive + doubleInsulatedGoldCableItem Double Insulated Gold Cable item, meta sensitive + + ironCableItem Iron Cable item, meta sensitive + insulatedIronCableItem Insulated Iron Cable item, meta sensitive + doubleInsulatedIronCableItem Double Insulated Iron Cable item, meta sensitive + trippleInsulatedIronCableItem Tripple Insulated Iron Cable item, meta sensitive + + glassFiberCableItem Glass Fiber Cable item, meta sensitive + + tinCableItem Tin Cable item, meta sensitive + + detectorCableItem Detector Cable item, meta sensitive + splitterCableItem Splitter Cable item, meta sensitive + + cells/containers (without reactor components) + cell Empty Cell item, currently not meta sensitive + lavaCell Lava Cell item, currently not meta sensitive + hydratedCoalCell Hydrated Coal Cell item, currently not meta sensitive + bioCell Bio Cell item, currently not meta sensitive + coalfuelCell Coalfuel Cell item, currently not meta sensitive + biofuelCell Biofuel Cell item, currently not meta sensitive + waterCell Water Cell item, currently not meta sensitive + electrolyzedWaterCell Electrolyzed Water Cell item, currently not meta sensitive + + fuelCan Empty Fuel Can item, currently not meta sensitive + filledFuelCan Fuel Can item, meta = fuel value (as of v1.45) + + tinCan Empty Tin Can item, currently not meta sensitive + filledTinCan Filled Tin Can item, currently not meta sensitive + + reactor components + uraniumCell Uranium Cell item, meta = damage value + coolingCell Cooling Cell item, meta = damage value + + depletedIsotopeCell Depleted Isotope Cell item, meta = damage value + reEnrichedUraniumCell Re-Enriched Uranium Cell item, currently not meta sensitive + nearDepletedUraniumCell Near-Depleted Uranium Cell item, currently not meta sensitive + + integratedReactorPlating Integrated Reactor Plating item, meta = damage value + integratedHeatDisperser Integrated Heat Disperser item, meta = damage value + + terraformer blueprints + terraformerBlueprint Empty Terraformer Blueprint item, currently not meta sensitive + cultivationTerraformerBlueprint Cultivation Terraformer Blueprint item, currently not meta sensitive + irrigationTerraformerBlueprint Irrigation Terraformer Blueprint item, currently not meta sensitive + chillingTerraformerBlueprint Chilling Terraformer Blueprint item, currently not meta sensitive + desertificationTerraformerBlueprint Desertification Terraformer Blueprint item, currently not meta sensitive + flatificatorTerraformerBlueprint Flatificator Terraformer Blueprint item, currently not meta sensitive + mushroomTerraformerBlueprint Mushroom Terraformer Blueprint item, currently not meta sensitive + + diamond chain + coalBall Coal Ball item, currently not meta sensitive + compressedCoalBall Compressed Coal Ball item, currently not meta sensitive + coalChunk Coal Chunk item, currently not meta sensitive + industrialDiamond Industrial Diamond item, currently not meta sensitive, DEPRECATED + + recycler chain + scrap Scrap item, currently not meta sensitive + scrapBox Scrap Box item, currently not meta sensitive + + fuel production chain + hydratedCoalClump Hydrated Coal Clump item, currently not meta sensitive + plantBall Plant Ball item, currently not meta sensitive + compressedPlantBall Compressed Plant Ball item, currently not meta sensitive + + painting + painter Painter item, currently not meta sensitive + + blackPainter Black Painter item, meta = damage value + redPainter Red Painter item, meta = damage value + greenPainter Green Painter item, meta = damage value + brownPainter Brown Painter item, meta = damage value + bluePainter Blue Painter item, meta = damage value + purplePainter Purple Painter item, meta = damage value + cyanPainter Cyan Painter item, meta = damage value + lightGreyPainter Light Grey Painter item, meta = damage value + darkGreyPainter Dark Grey Painter item, meta = damage value + pinkPainter Pink Painter item, meta = damage value + limePainter Lime Painter item, meta = damage value + yellowPainter Yellow Painter item, meta = damage value + cloudPainter Cloud Painter item, meta = damage value + magentaPainter Magenta Painter item, meta = damage value + orangePainter Orange Painter item, meta = damage value + whitePainter White Painter item, meta = damage value + + explosives + related + dynamite Throwable Dynamite item, currently not meta sensitive + stickyDynamite Throwable Sticky Dynamite item, currently not meta sensitive + + remote Dynamite Remote item, currently not meta sensitive + + misc intermediate recipe ingredients + electronicCircuit Electronic Circuit item, currently not meta sensitive + advancedCircuit Advanced Circuit item, currently not meta sensitive + + advancedAlloy Advanced Alloy item, currently not meta sensitive + + carbonFiber Raw Carbon Fiber item, currently not meta sensitive + carbonMesh Raw Carbon Mesh item, currently not meta sensitive + carbonPlate Carbon Plate item, currently not meta sensitive + + matter UU-Matter item, currently not meta sensitive + iridiumOre Iridium Ore item, currently not meta sensitive + iridiumPlate Iridium Plate item, currently not meta sensitive + + upgrade modules + overclockerUpgrade overclocker upgrade item, meta sensitive + transformerUpgrade transformer upgrade item, meta sensitive + energyStorageUpgrade energy storage upgrade item, meta sensitive + + misc + coin Coin item, currently not meta sensitive + reinforcedDoor Reinforced Door item, currently not meta sensitive + constructionFoamPellet Construction Foam Pellet item, currently not meta sensitive + cropSeed Crop seeds, stuff stored in NBT, don't use for crafting recipes! + cropnalyzer Cropnalyzer handheld device + fertilizer Basic IC2Item, used to provide nutrients toCropBlocks + hydratingCell Cell used to hydrate Crops, meta = Content, 0 = Full, 9999 = Near empty + electricHoe Electric Hoe, meta = charge level + solarHelmet Solar Helmet item, currently not meta sensitive + terraWart Terra Wart item, cures potion effects + weedEx Weed-EX can, meta = uses left + + */ + + /** + * Get the base IC2 package name, used internally. + * + * @return IC2 package name, if unable to be determined defaults to ic2 + */ + private static String getPackage() { + Package pkg = Items.class.getPackage(); + if (pkg != null) return pkg.getName().substring(0, pkg.getName().lastIndexOf('.')); + else return "ic2"; + } + + private static Class Ic2Items; +} + diff --git a/src/common/ic2/api/NetworkHelper.java b/src/common/ic2/api/NetworkHelper.java new file mode 100644 index 00000000..5287671b --- /dev/null +++ b/src/common/ic2/api/NetworkHelper.java @@ -0,0 +1,236 @@ +package ic2.api; + +import java.lang.reflect.Method; + +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ItemStack; +import net.minecraft.src.TileEntity; +import net.minecraft.src.World; + +/** + * Provides methods to initiate events and synchronize tile entity fields in SMP. + * + * The methods are transparent between singleplayer and multiplayer - if a method is called in + * singleplayer, the associated callback will be locally executed. The implementation is different + * between the client and server versions of IC2. + * + * You'll usually want to use the server->client methods defined here to synchronize information + * which is needed by the clients outside the GUI, such as rendering the block, playing sounds or + * producing effects. Anything which is only visible inside the GUI should be synchronized through + * the Container class associated to the GUI in Container.updateProgressBar(). + */ +public final class NetworkHelper { + // server -> client + + + /** + * Schedule a TileEntity's field to be updated to the clients in range. + * + * The updater will query the field's value during the next update, updates happen usually + * every 2 ticks. If low latency is important use initiateTileEntityEvent instead. + * + * IC2's network updates have to get triggered every time, it doesn't continuously poll/send + * the field value. Just call updateTileEntityField after every change to a field which needs + * network synchronization. + * + * The following field data types are currently supported: + * - int, int[], short, short[], byte, byte[], long, long[] + * - float, float[], double, double[] + * - boolean, boolean[] + * - String, String[] + * - ItemStack + * - NBTBase (includes NBTTagCompound) + * - Block, Item, Achievement, Potion, Enchantment + * - ChunkCoordinates, ChunkCoordIntPair + * - TileEntity (does not sync the actual tile entity, instead looks up the tile entity by its position in the client world) + * - World (does not sync the actual world, instead looks up the world by its dimension ID) + * + * Once the update has been processed by the client, it'll call onNetworkUpdate on the client- + * side TileEntity if it implements INetworkUpdateListener. + * + * If this method is being executed on the client (i.e. Singleplayer), it'll just call + * INetworkUpdateListener.onNetworkUpdate (if implemented by the te). + * + * @param te TileEntity to update + * @param field Name of the field to update + */ + public static void updateTileEntityField(TileEntity te, String field) { + try { + if (NetworkManager_updateTileEntityField == null) NetworkManager_updateTileEntityField = Class.forName(getPackage() + ".common.NetworkManager").getMethod("updateTileEntityField", TileEntity.class, String.class); + if (instance == null) instance = getInstance(); + + NetworkManager_updateTileEntityField.invoke(instance, te, field); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Immediately send an event for the specified TileEntity to the clients in range. + * + * If this method is being executed on the client (i.e. Singleplayer), it'll just call + * INetworkTileEntityEventListener.onNetworkEvent (if implemented by the te). + * + * @param te TileEntity to notify, should implement INetworkTileEntityEventListener + * @param event Arbitrary integer to represent the event, choosing the values is up to you + * @param limitRange Limit the notification range to (currently) 20 blocks instead of the + * tracking distance if true + */ + public static void initiateTileEntityEvent(TileEntity te, int event, boolean limitRange) { + try { + if (NetworkManager_initiateTileEntityEvent == null) NetworkManager_initiateTileEntityEvent = Class.forName(getPackage() + ".common.NetworkManager").getMethod("initiateTileEntityEvent", TileEntity.class, Integer.TYPE, Boolean.TYPE); + if (instance == null) instance = getInstance(); + + NetworkManager_initiateTileEntityEvent.invoke(null, te, event, limitRange); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Immediately send an event for the specified Item to the clients in range. + * + * The item should implement INetworkItemEventListener to receive the event. + * + * If this method is being executed on the client (i.e. Singleplayer), it'll just call + * INetworkItemEventListener.onNetworkEvent (if implemented by the item). + * + * @param player EntityPlayer holding the item + * @param itemStack ItemStack containing the item + * @param event Arbitrary integer to represent the event, choosing the values is up to you + * @param limitRange Limit the notification range to (currently) 20 blocks instead of the + * tracking distance if true + */ + public static void initiateItemEvent(EntityPlayer player, ItemStack itemStack, int event, boolean limitRange) { + try { + if (NetworkManager_initiateItemEvent == null) NetworkManager_initiateItemEvent = Class.forName(getPackage() + ".common.NetworkManager").getMethod("initiateItemEvent", EntityPlayer.class, ItemStack.class, Integer.TYPE, Boolean.TYPE); + if (instance == null) instance = getInstance(); + + NetworkManager_initiateItemEvent.invoke(instance, player, itemStack, event, limitRange); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Schedule a block update (re-render) on the clients in range. + * + * If this method is being executed on the client (i.e. Singleplayer), it'll just trigger the + * block update locally. + * + * @param world World containing the block + * @param x The block's x coordinate + * @param y The block's y coordinate + * @param z The block's z coordinate + */ + public static void announceBlockUpdate(World world, int x, int y, int z) { + try { + if (NetworkManager_announceBlockUpdate == null) NetworkManager_announceBlockUpdate = Class.forName(getPackage() + ".common.NetworkManager").getMethod("announceBlockUpdate", World.class, Integer.TYPE, Integer.TYPE, Integer.TYPE); + + NetworkManager_announceBlockUpdate.invoke(null, world, x, y, z); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + + // client -> server + + + /** + * Ask the server to send the values of the fields specified. + * + * See updateTileEntityField for the supported field types. + * + * The implementation is currently limited to TileEntitys as data providers. The tile entity + * has to be fully initialized when executing this method (i.e. valid worldObj+coords). + * + * This method doesn't do anything if executed on the server. + * + * @param dataProvider Object implementing the INetworkDataProvider interface + */ + public static void requestInitialData(INetworkDataProvider dataProvider) { + try { + if (NetworkManager_requestInitialData == null) NetworkManager_requestInitialData = Class.forName(getPackage() + ".common.NetworkManager").getMethod("requestInitialData", INetworkDataProvider.class); + if (instance == null) instance = getInstance(); + + NetworkManager_requestInitialData.invoke(instance, dataProvider); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Immediately send an event for the specified TileEntity to the server. + * + * This method doesn't do anything if executed on the server. + * + * @param te TileEntity to notify, should implement INetworkClientTileEntityEventListener + * @param event Arbitrary integer to represent the event, choosing the values is up to you + */ + public static void initiateClientTileEntityEvent(TileEntity te, int event) { + try { + if (NetworkManager_initiateClientTileEntityEvent == null) NetworkManager_initiateClientTileEntityEvent = Class.forName(getPackage() + ".common.NetworkManager").getMethod("initiateClientTileEntityEvent", TileEntity.class, Integer.TYPE); + if (instance == null) instance = getInstance(); + + NetworkManager_initiateClientTileEntityEvent.invoke(instance, te, event); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Immediately send an event for the specified Item to the clients in range. + * + * The item should implement INetworkItemEventListener to receive the event. + * + * This method doesn't do anything if executed on the server. + * + * @param itemStack ItemStack containing the item + * @param event Arbitrary integer to represent the event, choosing the values is up to you + */ + public static void initiateClientItemEvent(ItemStack itemStack, int event) { + try { + if (NetworkManager_initiateClientItemEvent == null) NetworkManager_initiateClientItemEvent = Class.forName(getPackage() + ".common.NetworkManager").getMethod("initiateClientItemEvent", ItemStack.class, Integer.TYPE); + if (instance == null) instance = getInstance(); + + NetworkManager_initiateClientItemEvent.invoke(instance, itemStack, event); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Get the base IC2 package name, used internally. + * + * @return IC2 package name, if unable to be determined defaults to ic2 + */ + private static String getPackage() { + Package pkg = NetworkHelper.class.getPackage(); + if (pkg != null) return pkg.getName().substring(0, pkg.getName().lastIndexOf('.')); + else return "ic2"; + } + + /** + * Get the NetworkManager instance, used internally. + * + * @return NetworkManager instance + */ + private static Object getInstance() { + try { + return Class.forName(getPackage() + ".common.IC2").getDeclaredField("network").get(null); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + private static Object instance; + private static Method NetworkManager_updateTileEntityField; + private static Method NetworkManager_initiateTileEntityEvent; + private static Method NetworkManager_initiateItemEvent; + private static Method NetworkManager_announceBlockUpdate; + private static Method NetworkManager_requestInitialData; + private static Method NetworkManager_initiateClientTileEntityEvent; + private static Method NetworkManager_initiateClientItemEvent; +} + diff --git a/src/common/ic2/api/TECrop.java b/src/common/ic2/api/TECrop.java new file mode 100644 index 00000000..a261953a --- /dev/null +++ b/src/common/ic2/api/TECrop.java @@ -0,0 +1,161 @@ +package ic2.api; + +import net.minecraft.src.Block; +import net.minecraft.src.ItemStack; +import net.minecraft.src.TileEntity; + +/** + * Provides access to a crop tile entity. Contains all methods and fields you can access from your CropCard. + */ +public abstract class TECrop extends TileEntity +{ + /** + * ID of the plant currently on the crop. + * -1 if there is no plant currently on the crop. + */ + public short id = -1; + + /** + * Current size of the plant. + * 1 is the starting size and the maximum size varies from plant to plant. + */ + public byte size = 0; + + /** + * Growth ability of a plant. + * Higher values give faster growth. + */ + public byte statGrowth = 0; + /** + * Chances and amount of gain and seeds from harvested crops. + * Higher values give more drops. + */ + public byte statGain = 0; + /** + * Ability for the plant to resist trampling. + * Higher values give more resistance against trampling. + */ + public byte statResistance = 0; + + /** + * Scan level, increases each time a seed goes through analysis. + */ + public byte scanLevel = 0; + + /** + * Custom data stored along a TECrop. + */ + public short[] custumData = new short[16]; + + /** + * Crop nutrients. + * Ranges from 0 (empty) to 100 (full). + */ + public int nutrientStorage = 0; + /** + * Crop hydration. + * Values are: + * - 0 for nothing + * - 1-10 for water hydration + * - 11-100 for distilled water (hydration cell) hydration + */ + public int waterStorage = 0; + /** + * Remaining duration of WeedEX + * PRevents weed from growing and protects against (unimplemented) insects or similar stuff + */ + public int exStorage = 0; + + /** + * Crop humidity. + * Ranges from 0 (dry) to 10 (humid). + * Updates every couple of seconds or when an update is requested. + * + * @see #updateState() + */ + public abstract byte getHumidity(); + + /** + * Get the crop's nutrient level. + * Ranges from 0 (empty) to 10 (full). + * Updates every couple of seconds or when an update is requested. + * + * @see #updateState() + */ + public abstract byte getNutrients(); + + /** + * Get the crop's air quality. + * Ranges from 0 (cluttered) to 10 (fresh). + * Updates every couple of seconds or when an update is requested. + * + * @see #updateState() + * + * @return Crop air quality + */ + public abstract byte getAirQuality(); + + /** + * Get the crop's light level. + * + * @return Crop light level + */ + public int getLightLevel() + { + return worldObj.getBlockLightValue(xCoord, yCoord, zCoord); + } + + + /** + * Pick the crop, removing and giving seeds for the plant. + * + * @param manual whether it was done by hand (not automated) + * @return true if successfully picked + */ + public abstract boolean pick(boolean manual); + + /** + * Harvest the crop, turning it into gain and resetting its size. + * + * @param manual whether it one by hand (not automated) + * @return true if successfully harvested + */ + public abstract boolean harvest(boolean manual); + + /** + * Fully clears the crop without dropping anything. + */ + public abstract void reset(); + + /** + * Request a texture and lighting update. + */ + public abstract void updateState(); + + /** + * Check if a block is under the farmland containing the crop. + * Searches up to 2 blocks below the farmland or an air space, whichever appears first. + * + * @param block block to search + * @return Whether the block was found + */ + public abstract boolean isBlockBelow(Block block); + + /** + * Generate plant seeds with the given parameters. + * + * @param plant plant ID + * @param growth plant growth stat + * @param gain plant gain stat + * @param resis plant resistance stat + * @param scan plant scan level + * @return Plant seed item + */ + public abstract ItemStack generateSeeds(short plant, byte growth, byte gain, byte resis, byte scan); + + /** + * For internal usage only. + */ + public abstract void addLocal(String s1, String s2); + +} diff --git a/src/common/railcraft/common/api/carts/CartBase.java b/src/common/railcraft/common/api/carts/CartBase.java new file mode 100644 index 00000000..d3403ba1 --- /dev/null +++ b/src/common/railcraft/common/api/carts/CartBase.java @@ -0,0 +1,118 @@ +package railcraft.common.api.carts; + +import net.minecraft.src.EntityItem; +import net.minecraft.src.EntityMinecart; +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ItemStack; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.minecart.MinecartInteractEvent; + +/** + * Generally minecarts should extend this class or there will be + * oddities if a user links two carts with different max speeds. + * + * It also contains some generic code that most carts will find useful. + * + * @author CovertJaguar + */ +public abstract class CartBase extends EntityMinecart implements IMinecart +{ + + private float trainSpeed = 1.2f; + + public CartBase(World world) + { + super(world); + CartTools.setCartOwner(this, "[Railcraft]"); + } + + public World getWorld() + { + return worldObj; + } + + @Override + public final float getMaxSpeedRail() + { + return Math.min(getCartMaxSpeed(), trainSpeed); + } + + @Override + public float getCartMaxSpeed() + { + return 1.2f; + } + + @Override + public final void setTrainSpeed(float speed) + { + this.trainSpeed = speed; + } + + @Override + public final boolean interact(EntityPlayer player) + { + if(MinecraftForge.EVENT_BUS.post(new MinecartInteractEvent(this, player))) { + return true; + } + if(CartTools.getCartOwner(this).equals("[Railcraft]")) { + CartTools.setCartOwner(this, player); + } + return doInteract(player); + } + + public boolean doInteract(EntityPlayer player) + { + return super.interact(player); + } + + @Override + public boolean doesCartMatchFilter(ItemStack stack, EntityMinecart cart) + { + if(stack == null || cart == null) { + return false; + } + ItemStack cartItem = cart.getCartItem(); + return cartItem != null && stack.isItemEqual(cartItem); + } + + @Override + public void setDead() + { + for(int var1 = 0; var1 < this.getSizeInventory(); ++var1) { + ItemStack var2 = this.getStackInSlot(var1); + this.setInventorySlotContents(var1, null); + + if(!worldObj.isRemote && var2 != null) { + float var3 = this.rand.nextFloat() * 0.8F + 0.1F; + float var4 = this.rand.nextFloat() * 0.8F + 0.1F; + float var5 = this.rand.nextFloat() * 0.8F + 0.1F; + + while(var2.stackSize > 0) { + int var6 = this.rand.nextInt(21) + 10; + + if(var6 > var2.stackSize) { + var6 = var2.stackSize; + } + + var2.stackSize -= var6; + EntityItem var7 = new EntityItem(this.worldObj, this.posX + (double)var3, this.posY + (double)var4, this.posZ + (double)var5, new ItemStack(var2.itemID, var6, var2.getItemDamage())); + + if(var2.hasTagCompound()) { + var7.item.setTagCompound((NBTTagCompound)var2.getTagCompound().copy()); + } + + float var8 = 0.05F; + var7.motionX = (double)((float)this.rand.nextGaussian() * var8); + var7.motionY = (double)((float)this.rand.nextGaussian() * var8 + 0.2F); + var7.motionZ = (double)((float)this.rand.nextGaussian() * var8); + this.worldObj.spawnEntityInWorld(var7); + } + } + } + + super.setDead(); + } +} diff --git a/src/common/railcraft/common/api/carts/CartTools.java b/src/common/railcraft/common/api/carts/CartTools.java new file mode 100644 index 00000000..c889872d --- /dev/null +++ b/src/common/railcraft/common/api/carts/CartTools.java @@ -0,0 +1,364 @@ +package railcraft.common.api.carts; + +import railcraft.common.api.core.items.IMinecartItem; +import cpw.mods.fml.common.registry.EntityRegistry; +import java.util.ArrayList; +import java.util.List; +import net.minecraft.src.AxisAlignedBB; +import net.minecraft.src.BlockRail; +import net.minecraft.src.EntityMinecart; +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ItemMinecart; +import net.minecraft.src.ItemStack; +import net.minecraft.src.World; +import net.minecraftforge.common.ForgeDirection; + +public abstract class CartTools +{ + + public static ILinkageManager serverLinkageManager; + + /** + * Registers a subclass of EntityMinecart with the game engine. + * + * This is just a convenience function, it is not required to call this function + * if you call ModLoader.registerEntityID() and MinecraftForge.registerEntity() + * elsewhere. + * + * @param mod The mod doing the registration + * @param type The class of the cart + * @param tag The String identifier + * @param internalId The mods internal entity id + */ + public static void registerMinecart(Object mod, Class type, String tag, int internalId) { + EntityRegistry.registerModEntity(type, tag, internalId, mod, 80, 3, true); + } + + /** + * Returns an instance of ILinkageManager. + * + * Will return null if Railcraft is not installed. + * + * @param world The World, may be required in the future + * @return an instance of ILinkageManager + */ + public static ILinkageManager getLinkageManager(World world) { + return serverLinkageManager; + } + + /** + * Sets a carts owner. + * + * The is really only needed by the bukkit ports. + * + * @param owner + */ + public static void setCartOwner(EntityMinecart cart, EntityPlayer owner) { + cart.getEntityData().setString("owner", owner.username); + } + + /** + * Sets a carts owner. + * + * The is really only needed by the bukkit ports. + * + * @param owner + */ + public static void setCartOwner(EntityMinecart cart, String owner) { + cart.getEntityData().setString("owner", owner); + } + + /** + * Gets a carts owner. (player.username) + * + * The is really only needed by the bukkit ports. + * + * @param owner + */ + public static String getCartOwner(EntityMinecart cart) { + return cart.getEntityData().getString("owner"); + } + + /** + * Will return true if the cart matches the provided filter item. + * + * @param stack the Filter + * @param cart the Cart + * @return true if the item matches the cart + * @see IMinecart + */ + public static boolean doesCartMatchFilter(ItemStack stack, EntityMinecart cart) { + if(stack == null) { + return false; + } + if(cart instanceof IMinecart) { + return ((IMinecart)cart).doesCartMatchFilter(stack, cart); + } + ItemStack cartItem = cart.getCartItem(); + return cartItem != null && isItemEqual(stack, cartItem); + } + + private static boolean isItemEqual(ItemStack a, ItemStack b) { + if(a == null || b == null) { + return false; + } + if(a.itemID != b.itemID) { + return false; + } + if(a.stackTagCompound != null && !a.stackTagCompound.equals(b.stackTagCompound)) { + return false; + } + if(a.getHasSubtypes() && (a.getItemDamage() == -1 || b.getItemDamage() == -1)) { + return true; + } + if(a.getHasSubtypes() && a.getItemDamage() != b.getItemDamage()) { + return false; + } + return true; + } + + /** + * Spawns a new cart entity using the provided item. + * + * The backing item must implement IMinecartItem + * and/or extend ItemMinecart. + * + * Generally Forge requires all cart items to extend ItemMinecart. + * + * @param owner The player name that should used as the owner + * @param cart An ItemStack containing a cart item, will not be changed by the function + * @param world The World object + * @param i x-Coord + * @param j y-Coord + * @param k z-Coord + * @return the cart placed or null if failed + * @see IMinecartItem, ItemMinecart + */ + public static EntityMinecart placeCart(String owner, ItemStack cart, World world, int i, int j, int k) { + if(cart == null) { + return null; + } + cart = cart.copy(); + if(cart.getItem() instanceof IMinecartItem) { + IMinecartItem mi = (IMinecartItem)cart.getItem(); + return mi.placeCart(owner, cart, world, i, j, k); + } else if(cart.getItem() instanceof ItemMinecart) { + try { + boolean placed = cart.getItem().onItemUse(cart, null, world, i, j, k, 0, 0, 0, 0); + if(placed) { + List carts = getMinecartsAt(world, i, j, k, 0.3f); + if(carts.size() > 0) { + setCartOwner(carts.get(0), owner); + return carts.get(0); + } + } + } catch (Exception e) { + return null; + } + } + + return null; + } + + /** + * Offers an item stack to linked carts or drops it if no one wants it. + * @param cart + * @param stack + */ + public static void offerOrDropItem(EntityMinecart cart, ItemStack stack) { + EntityMinecart link_A = getLinkageManager(cart.worldObj).getLinkedCartA(cart); + EntityMinecart link_B = getLinkageManager(cart.worldObj).getLinkedCartB(cart); + + if(stack != null && stack.stackSize > 0 && link_A instanceof IItemTransfer) { + stack = ((IItemTransfer)link_A).offerItem(cart, stack); + } + if(stack != null && stack.stackSize > 0 && link_B instanceof IItemTransfer) { + stack = ((IItemTransfer)link_B).offerItem(cart, stack); + } + + if(stack != null && stack.stackSize > 0) { + cart.entityDropItem(stack, 1); + } + } + + public static boolean isMinecartOnRailAt(World world, int i, int j, int k, float sensitivity) { + return isMinecartOnRailAt(world, i, j, k, sensitivity, null, true); + } + + public static boolean isMinecartOnRailAt(World world, int i, int j, int k, float sensitivity, Class type, boolean subclass) { + if(BlockRail.isRailBlockAt(world, i, j, k)) { + return isMinecartAt(world, i, j, k, sensitivity, type, subclass); + } + return false; + } + + public static boolean isMinecartOnAnySide(World world, int i, int j, int k, float sensitivity) { + return isMinecartOnAnySide(world, i, j, k, sensitivity, null, true); + } + + public static boolean isMinecartOnAnySide(World world, int i, int j, int k, float sensitivity, Class type, boolean subclass) { + List list = new ArrayList(); + for(int side = 0; side < 6; side++) { + list.addAll(getMinecartsOnSide(world, i, j, k, sensitivity, ForgeDirection.getOrientation(side))); + } + + if(type == null) { + return !list.isEmpty(); + } else { + for(EntityMinecart cart : list) { + if((subclass && type.isInstance(cart)) || cart.getClass() == type) { + return true; + } + } + } + return false; + } + + public static boolean isMinecartAt(World world, int i, int j, int k, float sensitivity) { + return isMinecartAt(world, i, j, k, sensitivity, null, true); + } + + public static boolean isMinecartAt(World world, int i, int j, int k, float sensitivity, Class type, boolean subclass) { + List list = getMinecartsAt(world, i, j, k, sensitivity); + + if(type == null) { + return !list.isEmpty(); + } else { + for(EntityMinecart cart : list) { + if((subclass && type.isInstance(cart)) || cart.getClass() == type) { + return true; + } + } + } + return false; + } + + public static List getMinecartsOnAllSides(World world, int i, int j, int k, float sensitivity) { + List carts = new ArrayList(); + for(int side = 0; side < 6; side++) { + carts.addAll(getMinecartsOnSide(world, i, j, k, sensitivity, ForgeDirection.getOrientation(side))); + } + + return carts; + } + + public static List getMinecartsOnAllSides(World world, int i, int j, int k, float sensitivity, Class type, boolean subclass) { + List list = new ArrayList(); + List carts = new ArrayList(); + for(int side = 0; side < 6; side++) { + list.addAll(getMinecartsOnSide(world, i, j, k, sensitivity, ForgeDirection.getOrientation(side))); + } + + for(EntityMinecart cart : list) { + if((subclass && type.isInstance(cart)) || cart.getClass() == type) { + carts.add(cart); + } + } + return carts; + } + + private static int getYOnSide(int y, ForgeDirection side) { + switch (side) { + case UP: + return y + 1; + case DOWN: + return y - 1; + default: + return y; + } + } + + private static int getXOnSide(int x, ForgeDirection side) { + switch (side) { + case EAST: + return x + 1; + case WEST: + return x - 1; + default: + return x; + } + } + + private static int getZOnSide(int z, ForgeDirection side) { + switch (side) { + case NORTH: + return z - 1; + case SOUTH: + return z + 1; + default: + return z; + } + } + + public static List getMinecartsOnSide(World world, int i, int j, int k, float sensitivity, ForgeDirection side) { + return getMinecartsAt(world, getXOnSide(i, side), getYOnSide(j, side), getZOnSide(k, side), sensitivity); + } + + public static boolean isMinecartOnSide(World world, int i, int j, int k, float sensitivity, ForgeDirection side) { + return getMinecartOnSide(world, i, j, k, sensitivity, side) != null; + } + + public static EntityMinecart getMinecartOnSide(World world, int i, int j, int k, float sensitivity, ForgeDirection side) { + for(EntityMinecart cart : getMinecartsOnSide(world, i, j, k, sensitivity, side)) { + return cart; + } + return null; + } + + public static boolean isMinecartOnSide(World world, int i, int j, int k, float sensitivity, ForgeDirection side, Class type, boolean subclass) { + return getMinecartOnSide(world, i, j, k, sensitivity, side, type, subclass) != null; + } + + public static EntityMinecart getMinecartOnSide(World world, int i, int j, int k, float sensitivity, ForgeDirection side, Class type, boolean subclass) { + for(EntityMinecart cart : getMinecartsOnSide(world, i, j, k, sensitivity, side)) { + if(type == null || (subclass && type.isInstance(cart)) || cart.getClass() == type) { + return cart; + } + } + return null; + } + + /** + * + * @param world + * @param i + * @param j + * @param k + * @param sensitivity Controls the size of the search box, ranges from (-inf, 0.49]. + * @return + */ + public static List getMinecartsAt(World world, int i, int j, int k, float sensitivity) { + sensitivity = Math.min(sensitivity, 0.49f); + List entities = world.getEntitiesWithinAABB(net.minecraft.src.EntityMinecart.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool(i + sensitivity, j + sensitivity, k + sensitivity, i + 1 - sensitivity, j + 1 - sensitivity, k + 1 - sensitivity)); + List carts = new ArrayList(); + for(Object o : entities) { + carts.add((EntityMinecart)o); + } + return carts; + } + + public static List getMinecartsIn(World world, int i1, int j1, int k1, int i2, int j2, int k2) { + List entities = world.getEntitiesWithinAABB(net.minecraft.src.EntityMinecart.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool(i1, j1, k1, i2, j2, k2)); + List carts = new ArrayList(); + for(Object o : entities) { + carts.add((EntityMinecart)o); + } + return carts; + } + + /** + * Returns the cart's "speed". It is not capped by the carts max speed, + * it instead returns the cart's "potential" speed. + * Used by collision and linkage logic. + * Do not use this to determine how fast a cart is currently moving. + * @param cart + * @return speed + */ + public static double getCartSpeedUncapped(EntityMinecart cart) { + return Math.sqrt(cart.motionX * cart.motionX + cart.motionZ * cart.motionZ); + } + + public static boolean cartVelocityIsLessThan(EntityMinecart cart, float vel) { + return Math.abs(cart.motionX) < vel && Math.abs(cart.motionZ) < vel; + } +} diff --git a/src/common/railcraft/common/api/carts/ICartRenderInterface.java b/src/common/railcraft/common/api/carts/ICartRenderInterface.java new file mode 100644 index 00000000..4fcb413f --- /dev/null +++ b/src/common/railcraft/common/api/carts/ICartRenderInterface.java @@ -0,0 +1,24 @@ +package railcraft.common.api.carts; + +import net.minecraft.src.Block; + +/** + * Used by the renderer to renders blocks in carts. + * @author CovertJaguar + */ +public interface ICartRenderInterface +{ + + /** + * Return the block that should be rendered in the cart. + * @return The Block to render + */ + public Block getBlock(); + + /** + * Return the metadata for the block + * that should be rendered in the cart. + * @return metadata + */ + public int getBlockMetadata(); +} diff --git a/src/common/railcraft/common/api/carts/IEnergyTransfer.java b/src/common/railcraft/common/api/carts/IEnergyTransfer.java new file mode 100644 index 00000000..49fee703 --- /dev/null +++ b/src/common/railcraft/common/api/carts/IEnergyTransfer.java @@ -0,0 +1,82 @@ +package railcraft.common.api.carts; + +/** + * This interface is implemented by the Energy Cart + * and is used by the Energy Loaders to charge/discharge carts. + * It is roughly equivalent to the IItemTransfer interface + * and based on ElectricItem and IElectricItem. + * + * @author CovertJaguar + * @see IItemTransfer + */ +public interface IEnergyTransfer +{ + + /** + * Injects the specified amount of EU into the device. + * + * The function returns the remainder of the EU after + * any EU used is subtracted. + * + * @param source Object initiating the transfer, should be an Entity or Tile Entity + * @param amount amount of energy to transfer in EU + * @param tier tier of the source device, has to be at least as high as the target device + * @param ignoreTransferLimit ignore the transfer limit specified by getTransferLimit() + * @param simulate don't actually change the item, just determine the return value + * @return The amount of EU not used + */ + public int injectEnergy(Object source, int amount, int tier, boolean ignoreTransferLimit, boolean simulate, boolean passAlong); + + /** + * Requests a certain amount of EU from the device. + * + * The is function will subtract EU from the device's store of power + * and return a portion up to, but not exceeding, the amount of EU requested. + * + * @param source Object initiating the transfer, should be an Entity or Tile Entity + * @param amount amount of energy to transfer in EU + * @param tier tier of the source device, has to be at least as high as the target device + * @param ignoreTransferLimit ignore the transfer limit specified by getTransferLimit() + * @param simulate don't actually change the item, just determine the return value + * @param passAlong whether neighboring carts should be asked to provide any missing power. + * @return The amount of EU transferred + */ + public int extractEnergy(Object source, int amount, int tier, boolean ignoreTransferLimit, boolean simulate, boolean passAlong); + + /** + * Return true if energy can be injected into this device. + * + * @return true if can inject energy + */ + public boolean canInjectEnergy(); + + /** + * Return true if energy can be extracted from this device. + * + * @return true if can extract energy + */ + public boolean canExtractEnergy(); + + /** + * The max capacity of the device. + * + * @return max capacity + */ + public int getCapacity(); + + /** + * Returns the current energy contained in the device. + * + * @return current energy + */ + public int getEnergy(); + + public int getTier(); + + /** + * The device's transfer rate in EU/t. + * + * @return the transfer rate + */ + public int getTransferLimit(); +} diff --git a/src/common/railcraft/common/api/carts/IItemTransfer.java b/src/common/railcraft/common/api/carts/IItemTransfer.java new file mode 100644 index 00000000..a5af647d --- /dev/null +++ b/src/common/railcraft/common/api/carts/IItemTransfer.java @@ -0,0 +1,65 @@ +package railcraft.common.api.carts; + +import net.minecraft.src.ItemStack; +import railcraft.common.api.core.items.EnumItemType; + +/** + * This interface allows items to be passed around with out needing + * to know anything about the underlying implementation of the inventories. + * + * @author CovertJaguar + */ +public interface IItemTransfer +{ + + /** + * Offers an ItemStack to the object implementing this interface. + * This function will return null if the item is accepted in full, + * otherwise it will return whatever is rejected. + * + * @param source The Object offering the item + * @param offer The ItemStack being offered + * @return Unused or unwanted portions of offer + */ + public ItemStack offerItem(Object source, ItemStack offer); + + /** + * Requests an ItemStack from the object implementing this interface. + * It is up to the object implementing this interface to determine which + * ItemStack to return, or none at all. + * + * @param source The Object submitting the request + * @return An ItemStack to fulfill the request or null if refused. + */ + public ItemStack requestItem(Object source); + + /** + * Requests an ItemStack from the object implementing this interface + * that matches the request parameter. + * It is up to the object implementing this interface to + * determine which ItemStack to return, or none at all. + * However, if the return value is not null + * it should fulfill the following condition:
+ * InventoryTools.isItemEqual(it.requestItem(this,request), request) == true + * + * @param source The Object submitting the request + * @param request The type of item requested + * @return An ItemStack to fulfill the request or null if refused. + */ + public ItemStack requestItem(Object source, ItemStack request); + + /** + * Requests an ItemStack from the object implementing this interface + * that matches the request parameter. + * It is up to the object implementing this interface to + * determine which ItemStack to return, or none at all. + * However, if the return value is not null + * it should fulfill the following condition:
+ * EnumItemType.isItemType(it.requestItem(this,request), request) == true + * + * @param source The Object submitting the request + * @param request The type of item requested + * @return An ItemStack to fulfill the request or null if refused. + */ + public ItemStack requestItem(Object source, EnumItemType request); +} diff --git a/src/common/railcraft/common/api/carts/ILinkableCart.java b/src/common/railcraft/common/api/carts/ILinkableCart.java new file mode 100644 index 00000000..d87386d9 --- /dev/null +++ b/src/common/railcraft/common/api/carts/ILinkableCart.java @@ -0,0 +1,77 @@ +package railcraft.common.api.carts; + +import net.minecraft.src.EntityMinecart; + +/** + * This interface should be implemented by any minecart that wishes + * to change the default linkage behavior. + * It is NOT required to be able to link a cart, + * it merely gives you more control over the process. + * @author CovertJaguar + */ +public interface ILinkableCart +{ + + /** + * To disable linking altogether, return false here. + * @return True if this cart is linkable. + */ + public boolean isLinkable(); + + /** + * Check called when attempting to link carts. + * @param cart The cart that we are attempting to link with. + * @return True if we can link with this cart. + */ + public boolean canLinkWithCart(EntityMinecart cart); + + /** + * Returns true if this cart has two links + * or false if it can only link with one cart. + * @return True if two links + */ + public boolean hasTwoLinks(); + + /** + * Gets the distance at which this cart can be linked. + * This is called on both carts and added together to determine + * how close two carts need to be for a successful link. + * Default = LinkageManager.LINKAGE_DISTANCE + * @param cart The cart that you are attempting to link with. + * @return The linkage distance + */ + public float getLinkageDistance(EntityMinecart cart); + + /** + * Gets the optimal distance between linked carts. + * This is called on both carts and added together to determine + * the optimal rest distance between linked carts. + * The LinkageManager will attempt to maintain this distance + * between linked carts at all times. + * Default = LinkageManager.OPTIMAL_DISTANCE + * @param cart The cart that you are linked with. + * @return The optimal rest distance + */ + public float getOptimalDistance(EntityMinecart cart); + + /** + * Return false if linked carts have no effect on the velocity of this cart. + * Use carefully, if you link two carts that can't be adjusted, + * it will behave as if they are not linked. + * @param cart The cart doing the adjusting. + * @return Whether the cart can have its velocity adjusted. + */ + public boolean canBeAdjusted(EntityMinecart cart); + + /** + * Called upon successful link creation. + * @param cart The cart we linked with. + */ + public void onLinkCreated(EntityMinecart cart); + + /** + * Called when a link is broken (usually). + * @param cart The cart we were linked with. + */ + public void onLinkBroken(EntityMinecart cart); +} diff --git a/src/common/railcraft/common/api/carts/ILinkageManager.java b/src/common/railcraft/common/api/carts/ILinkageManager.java new file mode 100644 index 00000000..e3080968 --- /dev/null +++ b/src/common/railcraft/common/api/carts/ILinkageManager.java @@ -0,0 +1,102 @@ +package railcraft.common.api.carts; + +import net.minecraft.src.EntityMinecart; + +/** + * The LinkageManager contains all the functions needed to link and interact + * with linked carts. + * + * To obtain an instance of this interface, call CartTools.getLinkageManager(). + * + * Each cart can up to two links. They are called Link A and Link B. + * Some carts will have only Link A, for example the Tunnel Bore. + * + * @author CovertJaguar + * @see CartTools, ILinkableCart + */ +public interface ILinkageManager +{ + + /** + * The default max distance at which carts can be linked, divided by 2. + */ + public static final float LINKAGE_DISTANCE = 1.25f; + /** + * The default distance at which linked carts are maintained, divided by 2. + */ + public static final float OPTIMAL_DISTANCE = 0.78f; + + /** + * Creates a link between two carts, + * but only if there is nothing preventing such a link. + * + * @param cart1 + * @param cart2 + * @return True if the link succeeded. + */ + public boolean createLink(EntityMinecart cart1, EntityMinecart cart2); + + /** + * Returns the cart linked to Link A or null if nothing is currently + * occupying Link A. + * + * @param cart The cart for which to get the link + * @return The linked cart or null + */ + public EntityMinecart getLinkedCartA(EntityMinecart cart); + + /** + * Returns the cart linked to Link B or null if nothing is currently + * occupying Link B. + * + * @param cart The cart for which to get the link + * @return The linked cart or null + */ + public EntityMinecart getLinkedCartB(EntityMinecart cart); + + /** + * Returns true if the two carts are linked to each other. + * + * @param cart1 + * @param cart2 + * @return True if linked + */ + public boolean areLinked(EntityMinecart cart1, EntityMinecart cart2); + + /** + * Breaks a link between two carts, if any link exists. + * + * @param cart1 + * @param cart2 + */ + public void breakLink(EntityMinecart cart1, EntityMinecart cart2); + + /** + * Breaks all links the cart has. + * + * @param cart + */ + public void breakLinks(EntityMinecart cart); + + /** + * Break only link A. + * + * @param cart + */ + public void breakLinkA(EntityMinecart cart); + + /** + * Break only link B. + * + * @param cart + */ + public void breakLinkB(EntityMinecart cart); + + /** + * Counts how many carts are in the train. + * + * @param cart Any cart in the train + * @return The number of carts in the train + */ + public int countCartsInTrain(EntityMinecart cart); +} diff --git a/src/common/railcraft/common/api/carts/ILiquidTransfer.java b/src/common/railcraft/common/api/carts/ILiquidTransfer.java new file mode 100644 index 00000000..8d72e734 --- /dev/null +++ b/src/common/railcraft/common/api/carts/ILiquidTransfer.java @@ -0,0 +1,53 @@ +package railcraft.common.api.carts; + +import buildcraft.api.liquids.LiquidStack; + +/** + * This interface allows carts to transfer liquid between each other + * as well as adding a couple other functions related to liquids. + * + * @author CovertJaguar + */ +public interface ILiquidTransfer +{ + + /** + * Offers liquid to this object. + * + * Is not used by the Liquid Loader to load carts, + * the traditional ILiquidContainer is used for that. + * + * @param source The Object offering the liquid, used to prevent request loops in trains + * @param quantity The quantity offered + * @param id The liquid id offered + * @return the liquid used + */ + public int offerLiquid(Object source, LiquidStack offer); + + /** + * Requests liquid from this object. + * + * Is not used by the Liquid Unloader to drain carts, + * the traditional ILiquidContainer is used for that. + * + * @param source The Object requesting the liquid, used to prevent request loops in trains + * @param quantity The quantity requested + * @param id The liquid type requested + * @return the liquid provided + */ + public int requestLiquid(Object source, LiquidStack request); + + /** + * Set by the Liquid Loader while filling, + * primarily used for rendering a visible + * change while being filled. + * @param filling + */ + public void setFilling(boolean filling); + + /** + * + * @return true if being filled + */ + public boolean isFilling(); +} diff --git a/src/common/railcraft/common/api/carts/IMinecart.java b/src/common/railcraft/common/api/carts/IMinecart.java new file mode 100644 index 00000000..7707a20e --- /dev/null +++ b/src/common/railcraft/common/api/carts/IMinecart.java @@ -0,0 +1,52 @@ +package railcraft.common.api.carts; + +import net.minecraft.src.EntityMinecart; +import net.minecraft.src.ItemStack; + +/** + * Some helper functions to make interacting with carts simpler. + * + * This interface is implemented by CartBase. + * + * @author CovertJaguar + * @see CartBase + */ +public interface IMinecart +{ + + /** + * Returns true if the Minecart matches the item provided. + * Generally just stack.isItemEqual(cart.getCartItem()), + * but some carts may need more control (the Tank Cart for example). + * + * @param stack the Filter + * @param cart the Cart + * @return true if the item matches the cart + */ + public boolean doesCartMatchFilter(ItemStack stack, EntityMinecart cart); + + /** + * Unlike EntityMinecart.getMaxSpeedRail(), + * this function is independent of the actual max speed of the cart. + * + * It should represent the max possible speed at this point in time + * before any modifiers due to linked carts, etc are applied. + * + * This is really only used for Train speed calculations. + * Which ever cart in the train returns the lowest value here will be the max speed of the entire train. + * + * @return + */ + public float getCartMaxSpeed(); + + /** + * Sets the max speed of a train. + * + * This should be used to limit the return value for EntityMinecart.getMaxSpeedRail(). + * + * @param speed + * @see CartBase + */ + public void setTrainSpeed(float speed); + +} diff --git a/src/common/railcraft/common/api/carts/TransferCartBase.java b/src/common/railcraft/common/api/carts/TransferCartBase.java new file mode 100644 index 00000000..d623308e --- /dev/null +++ b/src/common/railcraft/common/api/carts/TransferCartBase.java @@ -0,0 +1,252 @@ +package railcraft.common.api.carts; + +import net.minecraft.src.EntityMinecart; +import net.minecraft.src.IInventory; +import net.minecraft.src.ItemStack; +import net.minecraft.src.World; +import railcraft.common.api.core.items.EnumItemType; + +/** + * Abstract minecart class that implements the IItemTransfer + * interface for convenience and as example for others who wish + * to create carts that implements IItemTransfer. + * This particular implementation assumes a simple inventory + * and will attempt to pass along offers and requests to linked carts + * if it cannot fulfill them itself. + *
+ *
+ * Classes that extend this class:
+ * EntityCartChest
+ * EntityCartAnchor
+ * + * @author CovertJaguar + */ +public abstract class TransferCartBase extends CartBase implements IItemTransfer +{ + + /** + * If passThrough == true, this cart will only pass requests along, it wont attempt to fulfill them. + */ + protected boolean passThrough = false; + + public TransferCartBase(World world) + { + super(world); + } + + @Override + public ItemStack offerItem(Object source, ItemStack offer) + { + if(!passThrough && getSizeInventory() > 0) { + offer = moveItemStack(offer, this); + if(offer == null) { + return null; + } + } + + ILinkageManager lm = CartTools.getLinkageManager(worldObj); + + EntityMinecart linkedCart = lm.getLinkedCartA(this); + if(linkedCart != source && linkedCart instanceof IItemTransfer) { + offer = ((IItemTransfer)linkedCart).offerItem(this, offer); + } + + if(offer == null) { + return null; + } + + linkedCart = lm.getLinkedCartB(this); + if(linkedCart != source && linkedCart instanceof IItemTransfer) { + offer = ((IItemTransfer)linkedCart).offerItem(this, offer); + } + + return offer; + } + + @Override + public ItemStack requestItem(Object source) + { + ItemStack result = null; + if(!passThrough && getSizeInventory() > 0) { + result = removeOneItem(this); + if(result != null) { + return result; + } + } + + ILinkageManager lm = CartTools.getLinkageManager(worldObj); + + EntityMinecart linkedCart = lm.getLinkedCartA(this); + if(linkedCart != source && linkedCart instanceof IItemTransfer) { + result = ((IItemTransfer)linkedCart).requestItem(this); + } + + if(result != null) { + return result; + } + + linkedCart = lm.getLinkedCartB(this); + if(linkedCart != source && linkedCart instanceof IItemTransfer) { + result = ((IItemTransfer)linkedCart).requestItem(this); + } + + return result; + } + + @Override + public ItemStack requestItem(Object source, ItemStack request) + { + ItemStack result = null; + if(!passThrough && getSizeInventory() > 0) { + result = removeOneItem(this, request); + if(result != null) { + return result; + } + } + + ILinkageManager lm = CartTools.getLinkageManager(worldObj); + + EntityMinecart linkedCart = lm.getLinkedCartA(this); + if(linkedCart != source && linkedCart instanceof IItemTransfer) { + result = ((IItemTransfer)linkedCart).requestItem(this, request); + } + + if(result != null) { + return result; + } + + linkedCart = lm.getLinkedCartB(this); + if(linkedCart != source && linkedCart instanceof IItemTransfer) { + result = ((IItemTransfer)linkedCart).requestItem(this, request); + } + + return result; + } + + @Override + public ItemStack requestItem(Object source, EnumItemType request) + { + ItemStack result = null; + if(!passThrough && getSizeInventory() > 0) { + result = removeOneItem(this, request); + if(result != null) { + return result; + } + } + + ILinkageManager lm = CartTools.getLinkageManager(worldObj); + + EntityMinecart linkedCart = lm.getLinkedCartA(this); + if(linkedCart != source && linkedCart instanceof IItemTransfer) { + result = ((IItemTransfer)linkedCart).requestItem(this, request); + } + + if(result != null) { + return result; + } + + linkedCart = lm.getLinkedCartB(this); + if(linkedCart != source && linkedCart instanceof IItemTransfer) { + result = ((IItemTransfer)linkedCart).requestItem(this, request); + } + + return result; + } + + /** + * Removes and returns a single item from the inventory. + * @param inv The inventory + * @return An ItemStack + */ + protected final ItemStack removeOneItem(IInventory inv) + { + for(int i = 0; i < inv.getSizeInventory(); i++) { + ItemStack slot = inv.getStackInSlot(i); + if(slot != null) { + return inv.decrStackSize(i, 1); + } + } + return null; + } + + /** + * Removes and returns a single item from the inventory that matches the filter. + * @param inv The inventory + * @param filter ItemStack to match against + * @return An ItemStack + */ + protected final ItemStack removeOneItem(IInventory inv, ItemStack filter) + { + for(int i = 0; i < inv.getSizeInventory(); i++) { + ItemStack slot = inv.getStackInSlot(i); + if(slot != null && filter != null && slot.isItemEqual(filter)) { + return inv.decrStackSize(i, 1); + } + } + return null; + } + + /** + * Removes and returns a single item from the inventory that matches the filter. + * @param inv The inventory + * @param filter EnumItemType to match against + * @return An ItemStack + */ + protected final ItemStack removeOneItem(IInventory inv, EnumItemType filter) + { + for(int i = 0; i < inv.getSizeInventory(); i++) { + ItemStack slot = inv.getStackInSlot(i); + if(slot != null && filter.isItemType(slot)) { + return inv.decrStackSize(i, 1); + } + } + return null; + } + + protected final ItemStack moveItemStack(ItemStack stack, IInventory dest) + { + if(stack == null) { + return null; + } + stack = stack.copy(); + if(dest == null) { + return stack; + } + boolean movedItem = false; + do { + movedItem = false; + ItemStack destStack = null; + for(int ii = 0; ii < dest.getSizeInventory(); ii++) { + destStack = dest.getStackInSlot(ii); + if(destStack != null && destStack.isItemEqual(stack)) { + int maxStack = Math.min(destStack.getMaxStackSize(), dest.getInventoryStackLimit()); + int room = maxStack - destStack.stackSize; + if(room > 0) { + int move = Math.min(room, stack.stackSize); + destStack.stackSize += move; + stack.stackSize -= move; + if(stack.stackSize <= 0) { + return null; + } + movedItem = true; + } + } + } + if(!movedItem) { + for(int ii = 0; ii < dest.getSizeInventory(); ii++) { + destStack = dest.getStackInSlot(ii); + if(destStack == null) { + if(stack.stackSize > dest.getInventoryStackLimit()) { + dest.setInventorySlotContents(ii, stack.splitStack(dest.getInventoryStackLimit())); + } else { + dest.setInventorySlotContents(ii, stack); + return null; + } + movedItem = true; + } + } + } + } while(movedItem); + return stack; + } +} diff --git a/src/common/railcraft/common/api/carts/bore/IBoreHead.java b/src/common/railcraft/common/api/carts/bore/IBoreHead.java new file mode 100644 index 00000000..3d541039 --- /dev/null +++ b/src/common/railcraft/common/api/carts/bore/IBoreHead.java @@ -0,0 +1,37 @@ +package railcraft.common.api.carts.bore; + +/** + * This interface it used to define an item that can + * be used as a bore head for the Tunnel Bore. + * @author CovertJaguar + */ +public interface IBoreHead +{ + + /** + * Return the texture file used for this bore head. + * @return The texture file path + */ + public String getBoreTexture(); + + /** + * Return the harvest level of this bore head. + * + * This value is compared against the tool classes + * "pickaxe", "axe", and "shovel" to determine if the + * block is harvestable by the bore head. + * + * @return The harvest level + */ + public int getHarvestLevel(); + + /** + * Return the dig speed modifier of this bore head. + * + * This value controls how much faster or slow this bore head + * mines each layer compared to the default time. + * + * @return The dig speed modifier + */ + public float getDigModifier(); +} diff --git a/src/common/railcraft/common/api/carts/bore/IMineable.java b/src/common/railcraft/common/api/carts/bore/IMineable.java new file mode 100644 index 00000000..185d0b65 --- /dev/null +++ b/src/common/railcraft/common/api/carts/bore/IMineable.java @@ -0,0 +1,36 @@ +package railcraft.common.api.carts.bore; + +import net.minecraft.src.EntityMinecart; +import net.minecraft.src.ItemStack; +import net.minecraft.src.World; + +/** + * This interface can be implemented by a block class to control whether a block can be + * mined by the bore without having to force the user to edit the configuration file. + * + * If the block is found to implement this class, any setting in the configuration + * is ignored for that block. + * + * Generally, the reason blocks are not minable by default is to prevent you + * from intentionally or accidentally boring through your base. + * + * @author CovertJaguar + */ +public interface IMineable +{ + + /** + * Called when the Bore attempts to mine the block. If it returns false, + * the Bore will halt operation. + * + * @param world The World + * @param i x-Coord + * @param j y-Coord + * @param k z-Coord + * @param bore The Bore entity + * @param head The BoreHead, item implements IBoreHead. + * @return true if mineable + * @see IBoreHead + */ + public boolean canMineBlock(World world, int i, int j, int k, EntityMinecart bore, ItemStack head); +} diff --git a/src/common/railcraft/common/api/core/INetworkedObject.java b/src/common/railcraft/common/api/core/INetworkedObject.java new file mode 100644 index 00000000..c0943860 --- /dev/null +++ b/src/common/railcraft/common/api/core/INetworkedObject.java @@ -0,0 +1,16 @@ +package railcraft.common.api.core; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import net.minecraft.src.World; + +public interface INetworkedObject +{ + + public World getWorld(); + + public void writePacketData(DataOutputStream data) throws IOException; + + public void readPacketData(DataInputStream data) throws IOException; +} diff --git a/src/common/railcraft/common/api/core/IPostConnection.java b/src/common/railcraft/common/api/core/IPostConnection.java new file mode 100644 index 00000000..12a13c4e --- /dev/null +++ b/src/common/railcraft/common/api/core/IPostConnection.java @@ -0,0 +1,27 @@ +package railcraft.common.api.core; + +import net.minecraft.src.World; +import net.minecraftforge.common.ForgeDirection; + +/** + * If you want your block to connect (or not connect) to posts, + * implement this interface. + * + * The result takes priority over any other rules. + * + * @author CovertJaguar + */ +public interface IPostConnection +{ + + /** + * Return true if the block at this location should connect to a post. + * @param world The World + * @param i x-Coord + * @param j y-Coord + * @param k z-Coord + * @param side Side to connect to + * @return true if connect + */ + public boolean connectsAt(World world, int i, int j, int k, ForgeDirection side); +} diff --git a/src/common/railcraft/common/api/core/WorldCoordinate.java b/src/common/railcraft/common/api/core/WorldCoordinate.java new file mode 100644 index 00000000..3037e800 --- /dev/null +++ b/src/common/railcraft/common/api/core/WorldCoordinate.java @@ -0,0 +1,78 @@ +package railcraft.common.api.core; + +/** + * This immutable class represents a point in the Minecraft world, + * while taking into account the possibility of coordinates in different dimensions. + * @author CovertJaguar + */ +public class WorldCoordinate +{ + + /** + * The dimension + */ + public final int dimension; + /** + * x-Coord + */ + public final int x; + /** + * y-Coord + */ + public final int y; + /** + * z-Coord + */ + public final int z; + + /** + * Creates a new WorldCoordinate + * @param dimension + * @param i + * @param j + * @param k + */ + public WorldCoordinate(int dimension, int i, int j, int k) + { + this.dimension = dimension; + x = i; + y = j; + z = k; + } + + @Override + public boolean equals(Object obj) + { + if(obj == null) { + return false; + } + if(getClass() != obj.getClass()) { + return false; + } + final WorldCoordinate other = (WorldCoordinate)obj; + if(this.dimension != other.dimension) { + return false; + } + if(this.x != other.x) { + return false; + } + if(this.y != other.y) { + return false; + } + if(this.z != other.z) { + return false; + } + return true; + } + + @Override + public int hashCode() + { + int hash = 3; + hash = 13 * hash + this.dimension; + hash = 13 * hash + this.x; + hash = 13 * hash + this.y; + hash = 13 * hash + this.z; + return hash; + } +} diff --git a/src/common/railcraft/common/api/core/items/BallastRegistry.java b/src/common/railcraft/common/api/core/items/BallastRegistry.java new file mode 100644 index 00000000..dcc724f1 --- /dev/null +++ b/src/common/railcraft/common/api/core/items/BallastRegistry.java @@ -0,0 +1,93 @@ +package railcraft.common.api.core.items; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import net.minecraft.src.Block; +import net.minecraft.src.ItemBlock; +import net.minecraft.src.ItemStack; + +/** + * Register an item here to designate it as a possible + * ballast that can be used in the Bore. + * + * It is expected that ballast is affected by gravity. + * + * @author CovertJaguar + */ +public abstract class BallastRegistry +{ + + private static Set ballastRegistry = new HashSet(); + + private static class ItemWrapper + { + + public int itemID; + public int itemDamage; + public ItemStack stack; + + public ItemWrapper(ItemStack stack) + { + itemID = stack.itemID; + itemDamage = stack.getItemDamage(); + this.stack = stack; + } + + @Override + public boolean equals(Object obj) + { + if(obj == null) { + return false; + } + if(getClass() != obj.getClass()) { + return false; + } + final ItemWrapper other = (ItemWrapper)obj; + if(this.itemID != other.itemID) { + return false; + } + if(this.itemDamage != other.itemDamage) { + return false; + } + return true; + } + + @Override + public int hashCode() + { + int hash = 3; + hash = 47 * hash + this.itemID; + hash = 47 * hash + this.itemDamage; + return hash; + } + } + + static { + registerBallast(new ItemStack(Block.gravel)); + } + + public static void registerBallast(ItemStack ballast) + { + if(ballast.getItem() instanceof ItemBlock) { + ballastRegistry.add(new ItemWrapper(ballast)); + } else { + throw new RuntimeException("Attempted to register an invalid ballast, must be an ItemBlock item."); + } + } + + public static boolean isItemBallast(ItemStack ballast) + { + return ballastRegistry.contains(new ItemWrapper(ballast)); + } + + public static List getRegisteredBallasts() + { + List list = new ArrayList(); + for(ItemWrapper item : ballastRegistry) { + list.add(item.stack); + } + return list; + } +} diff --git a/src/common/railcraft/common/api/core/items/EnumItemType.java b/src/common/railcraft/common/api/core/items/EnumItemType.java new file mode 100644 index 00000000..850ff823 --- /dev/null +++ b/src/common/railcraft/common/api/core/items/EnumItemType.java @@ -0,0 +1,47 @@ +package railcraft.common.api.core.items; + +import net.minecraft.src.BlockRail; +import net.minecraft.src.Item; +import net.minecraft.src.ItemBlock; +import net.minecraft.src.ItemFood; +import net.minecraft.src.ItemStack; +import net.minecraft.src.TileEntityFurnace; +import net.minecraftforge.common.MinecartRegistry; + +/** + * This interface is used with several of the functions in IItemTransfer + * to provide a convenient means of dealing with entire classes of items without + * having to specify each item individually. + * @author CovertJaguar + */ +public enum EnumItemType +{ + + FUEL, RAIL, MINECART, BALLAST, FOOD; + + public static boolean isItemType(ItemStack stack, EnumItemType filter) + { + return filter.isItemType(stack); + } + + public boolean isItemType(ItemStack stack) + { + if(stack == null) { + return false; + } + switch (this) { + case FUEL: + return TileEntityFurnace.getItemBurnTime(stack) > 0; + case RAIL: + return stack.getItem() instanceof ITrackItem || (stack.getItem() instanceof ItemBlock && BlockRail.isRailBlock(stack.itemID)); + case MINECART: + return MinecartRegistry.getCartClassForItem(stack) != null || stack.getItem() instanceof IMinecartItem; + case BALLAST: + return BallastRegistry.isItemBallast(stack); + case FOOD: + return stack.getItem() instanceof ItemFood || stack.itemID == Item.wheat.shiftedIndex; + default: + return false; + } + } +} diff --git a/src/common/railcraft/common/api/core/items/ICrowbar.java b/src/common/railcraft/common/api/core/items/ICrowbar.java new file mode 100644 index 00000000..3a058b28 --- /dev/null +++ b/src/common/railcraft/common/api/core/items/ICrowbar.java @@ -0,0 +1,14 @@ +package railcraft.common.api.core.items; + +/** + * Any item that performs the same function as a crowbar should implement this interface. + * Making a new crowbar item is as simple as implementing this empty interface. + * Doing so will make all the blocks, tracks, and entities aware of that the item + * should be treated identically to a crowbar. + * + * @author CovertJaguar + */ +public interface ICrowbar +{ + +} diff --git a/src/common/railcraft/common/api/core/items/IMinecartItem.java b/src/common/railcraft/common/api/core/items/IMinecartItem.java new file mode 100644 index 00000000..22d513b8 --- /dev/null +++ b/src/common/railcraft/common/api/core/items/IMinecartItem.java @@ -0,0 +1,39 @@ +package railcraft.common.api.core.items; + +import net.minecraft.src.EntityMinecart; +import net.minecraft.src.ItemStack; +import net.minecraft.src.World; + +/** + * This interface should be implemented by any cart item, + * but it is generally optional. + * + * @author CovertJaguar + */ +public interface IMinecartItem +{ + + /** + * Controls whether this cart item can be placed by the Cart and Train Dispensers. + * + * Generally, you can ignore the placeCart() function if this returns false. + * + * @return true if it can be placed, false otherwise + */ + public boolean canBePlacedByNonPlayer(ItemStack cart); + + /** + * Places a cart at the specified location. + * + * Implementing this function is optional. + * + * @param owner the name of the player placing the cart or "[MyMod]" with the brackets + * @param cart An ItemStack that contains the cart + * @param world The World + * @param i x-Coord + * @param j y-Coord + * @param k z-Coord + * @return the cart placed or null if failed + */ + public EntityMinecart placeCart(String owner, ItemStack cart, World world, int i, int j, int k); +} diff --git a/src/common/railcraft/common/api/core/items/ITrackItem.java b/src/common/railcraft/common/api/core/items/ITrackItem.java new file mode 100644 index 00000000..1c4cd72f --- /dev/null +++ b/src/common/railcraft/common/api/core/items/ITrackItem.java @@ -0,0 +1,46 @@ +package railcraft.common.api.core.items; + +import net.minecraft.src.ItemStack; +import net.minecraft.src.TileEntity; +import net.minecraft.src.World; + +/** + * Should be implemented by any rail item class that wishes to have + * it's rails placed by for example the Tunnel Bore or Track Relayer. + * + * If you defined your rails with a TrackSpec, you don't need to worry about this. + * + * @author CovertJaguar + */ +public interface ITrackItem +{ + + /** + * Attempts to place a track. + * + * @param world The World object + * @param i x-Coord + * @param j y-Coord + * @param k z-Coord + * @return true if successful + */ + public boolean placeTrack(ItemStack stack, World world, int i, int j, int k); + + /** + * Return the block id of a placed track. + * + * @return the blockId + */ + public int getPlacedBlockId(); + + /** + * Return true if the given tile entity corresponds to this Track item. + * + * If the track has no tile entity, return true on null. + * + * @param stack + * @param tile + * @return + */ + public boolean isPlacedTileEntity(ItemStack stack, TileEntity tile); +} diff --git a/src/common/railcraft/common/api/core/items/ItemRegistry.java b/src/common/railcraft/common/api/core/items/ItemRegistry.java new file mode 100644 index 00000000..3760fad3 --- /dev/null +++ b/src/common/railcraft/common/api/core/items/ItemRegistry.java @@ -0,0 +1,93 @@ +package railcraft.common.api.core.items; + +import java.util.Map; +import java.util.TreeMap; +import net.minecraft.src.ItemStack; + +/** + * This class contains a registry of all currently active Railcraft items. + * Which items are registered depends on the user's settings in "railcraft.cfg", + * so the available items may vary from one installation to the next. + * + * Initialization of the registry will occur during the BaseMod.load() + * function. It is strongly recommended you wait until the BaseMod.modsLoaded() + * function to reference the registry. + * + * @author CovertJaguar + */ +public final class ItemRegistry +{ + + private static final Map registry = new TreeMap(); + + private ItemRegistry() + { + } + + /** + * This function will return an ItemStack containing the item that + * corresponds to the provided tag. + * + * Generally item tags will correspond to the tags used in "railcraft.cfg", + * but there will be some exceptions. + * + * This function can and will return null for just about every item + * if the item is disabled via the configuration files. + * You must test the return value for safety. + * + * For list of available tags see the printItemTags() function. + * + * @param tag The item tag + * @param qty The stackSize of the returned item + * @return The ItemStack or null if no item exists for that tag + */ + public static ItemStack getItem(String tag, int qty) + { + ItemStack stack = registry.get(tag); + if(stack != null) { + stack = stack.copy(); + stack.stackSize = qty; + } + return stack; + } + + /** + * Registers a new item with the Registry. + * + * This should generally only be called by Railcraft itself + * while the mod is initializing during the mod_Railcraft.load() call. + * + * @param tag The tag name + * @param item The item + */ + public static void registerItem(String tag, ItemStack item) + { + registry.put(tag, item); + } + + /** + * This function will print a list of all currently registered items + * to the console. + * + * Use this for development purposes. + */ + public static void printItemTags() + { + System.out.println(); + System.out.println("Printing all registered Railcraft items:"); + for(String tag : registry.keySet()) { + System.out.println(tag); + } + System.out.println(); + } + + /** + * Returns the entire mapping of items. + * + * @return + */ + public static Map getItems() + { + return registry; + } +} diff --git a/src/common/railcraft/common/api/crafting/IBlastFurnaceCraftingManager.java b/src/common/railcraft/common/api/crafting/IBlastFurnaceCraftingManager.java new file mode 100644 index 00000000..e92381c3 --- /dev/null +++ b/src/common/railcraft/common/api/crafting/IBlastFurnaceCraftingManager.java @@ -0,0 +1,25 @@ +package railcraft.common.api.crafting; + +import java.util.List; +import net.minecraft.src.ItemStack; + +/** + * + * @author CovertJaguar + */ +public interface IBlastFurnaceCraftingManager +{ + + void addRecipe(int inputId, int inputDamage, int cookTime, ItemStack output); + + void addRecipe(int inputId, int cookTime, ItemStack output); + + List getFuels(); + + IBlastFurnaceRecipe getRecipe(int inputId, int inputDamage); + + IBlastFurnaceRecipe getRecipe(ItemStack stack); + + List getRecipes(); + +} diff --git a/src/common/railcraft/common/api/crafting/IBlastFurnaceRecipe.java b/src/common/railcraft/common/api/crafting/IBlastFurnaceRecipe.java new file mode 100644 index 00000000..6c6a7181 --- /dev/null +++ b/src/common/railcraft/common/api/crafting/IBlastFurnaceRecipe.java @@ -0,0 +1,21 @@ +package railcraft.common.api.crafting; + +import net.minecraft.src.ItemStack; + +/** + * + * @author CovertJaguar + */ +public interface IBlastFurnaceRecipe +{ + + public int getCookTime(); + + public ItemStack getInput(); + + public ItemStack getOutput(); + + int getOutputStackSize(); + + boolean isRoomForOutput(ItemStack out); +} diff --git a/src/common/railcraft/common/api/crafting/ICokeOvenCraftingManager.java b/src/common/railcraft/common/api/crafting/ICokeOvenCraftingManager.java new file mode 100644 index 00000000..a6e5b73f --- /dev/null +++ b/src/common/railcraft/common/api/crafting/ICokeOvenCraftingManager.java @@ -0,0 +1,26 @@ +package railcraft.common.api.crafting; + +import buildcraft.api.liquids.LiquidStack; +import java.util.List; +import net.minecraft.src.ItemStack; + +/** + * + * @author CovertJaguar + */ +public interface ICokeOvenCraftingManager +{ + + void addRecipe(ItemStack input, ItemStack output, LiquidStack liquidOutput, int cookTime); + + void addRecipe(int inputId, int inputDamage, ItemStack output, LiquidStack liquidOutput, int cookTime); + + void addRecipe(int inputId, ItemStack output, LiquidStack liquidOutput, int cookTime); + + ICokeOvenRecipe getRecipe(ItemStack stack); + + ICokeOvenRecipe getRecipe(int inputId, int inputDamage); + + List getRecipes(); + +} diff --git a/src/common/railcraft/common/api/crafting/ICokeOvenRecipe.java b/src/common/railcraft/common/api/crafting/ICokeOvenRecipe.java new file mode 100644 index 00000000..f2e9e29f --- /dev/null +++ b/src/common/railcraft/common/api/crafting/ICokeOvenRecipe.java @@ -0,0 +1,20 @@ +package railcraft.common.api.crafting; + +import buildcraft.api.liquids.LiquidStack; +import net.minecraft.src.ItemStack; + +/** + * + * @author CovertJaguar + */ +public interface ICokeOvenRecipe +{ + + public int getCookTime(); + + public ItemStack getInput(); + + public LiquidStack getLiquidOutput(); + + public ItemStack getOutput(); +} diff --git a/src/common/railcraft/common/api/crafting/IRockCrusherCraftingManager.java b/src/common/railcraft/common/api/crafting/IRockCrusherCraftingManager.java new file mode 100644 index 00000000..52dd8839 --- /dev/null +++ b/src/common/railcraft/common/api/crafting/IRockCrusherCraftingManager.java @@ -0,0 +1,35 @@ +package railcraft.common.api.crafting; + +import java.util.HashMap; +import java.util.List; +import net.minecraft.src.ItemStack; + +/** + * + * @author CovertJaguar + */ +public interface IRockCrusherCraftingManager +{ + + /** + * + * @param inputId + * @param inputDamage metadata or -1 for wildcard + * @param output A map of outputs and chances. If more than 9 types of items, there will be unexpected behavior. + */ + void addRecipe(int inputId, int inputDamage, HashMap output); + + /** + * + * @param input + * @param output A map of outputs and chances. If more than 9 types of items, there will be unexpected behavior. + */ + void addRecipe(ItemStack input, HashMap output); + + IRockCrusherRecipe getRecipe(ItemStack input); + + IRockCrusherRecipe getRecipe(int inputId, int inputDamage); + + List getRecipes(); + +} diff --git a/src/common/railcraft/common/api/crafting/IRockCrusherRecipe.java b/src/common/railcraft/common/api/crafting/IRockCrusherRecipe.java new file mode 100644 index 00000000..75b2d811 --- /dev/null +++ b/src/common/railcraft/common/api/crafting/IRockCrusherRecipe.java @@ -0,0 +1,37 @@ +package railcraft.common.api.crafting; + +import java.util.List; +import java.util.Map; +import net.minecraft.src.ItemStack; + +/** + * + * @author CovertJaguar + */ +public interface IRockCrusherRecipe +{ + + public ItemStack getInput(); + + /** + * Returns a map containing each output entry and its chance of being included. + * + * @return + */ + public Map getOutputs(); + + /** + * Returns a list of all possible outputs. + * This is basically a condensed version of getOutputs().keySet(). + * + * @return + */ + public List getPossibleOuput(); + + /** + * Returns a list of outputs after it has passed through the randomizer. + * + * @return + */ + public List getRandomizedOuput(); +} diff --git a/src/common/railcraft/common/api/crafting/IRollingMachineCraftingManager.java b/src/common/railcraft/common/api/crafting/IRollingMachineCraftingManager.java new file mode 100644 index 00000000..6b9ee7f6 --- /dev/null +++ b/src/common/railcraft/common/api/crafting/IRollingMachineCraftingManager.java @@ -0,0 +1,23 @@ +package railcraft.common.api.crafting; + +import java.util.List; +import net.minecraft.src.IRecipe; +import net.minecraft.src.InventoryCrafting; +import net.minecraft.src.ItemStack; + +/** + * + * @author CovertJaguar + */ +public interface IRollingMachineCraftingManager +{ + + void addRecipe(ItemStack output, Object[] components); + + void addShapelessRecipe(ItemStack output, Object[] compenents); + + ItemStack findMatchingRecipe(InventoryCrafting inventorycrafting); + + List getRecipeList(); + +} diff --git a/src/common/railcraft/common/api/crafting/RailcraftCraftingManager.java b/src/common/railcraft/common/api/crafting/RailcraftCraftingManager.java new file mode 100644 index 00000000..27608b22 --- /dev/null +++ b/src/common/railcraft/common/api/crafting/RailcraftCraftingManager.java @@ -0,0 +1,16 @@ +package railcraft.common.api.crafting; + +/** + * These variables are defined during the pre-init phase. + * Do not attempt to access them during pre-init. + * + * @author CovertJaguar + */ +public abstract class RailcraftCraftingManager +{ + + public static ICokeOvenCraftingManager cokeOven; + public static IBlastFurnaceCraftingManager blastFurnace; + public static IRockCrusherCraftingManager rockCrusher; + public static IRollingMachineCraftingManager rollingMachine; +} diff --git a/src/common/railcraft/common/api/signals/EnumSignalAspect.java b/src/common/railcraft/common/api/signals/EnumSignalAspect.java new file mode 100644 index 00000000..8a71e40d --- /dev/null +++ b/src/common/railcraft/common/api/signals/EnumSignalAspect.java @@ -0,0 +1,155 @@ +package railcraft.common.api.signals; + +/** + * Represents a Signal state. + * @author CovertJaguar + */ +public enum EnumSignalAspect +{ + + /** + * The All Clear. + */ + GREEN(0), + /** + * Typically means pairing in progress. + */ + BLINK_YELLOW(1), + /** + * Caution, cart heading away. + */ + YELLOW(1), + /** + * Maintenance warning, the signal is malfunctioning. + */ + BLINK_RED(2), + /** + * Stop! + */ + RED(2), + /** + * Can't happen, really it can't (or shouldn't). + * Only used when rendering blink states (for the texture offset). + */ + OFF(3); + private final byte id; + private final int textureOffset; + private static byte nextId = 0; + private static boolean blinkState; + + private EnumSignalAspect(int textureOffset) + { + this.textureOffset = textureOffset; + id = getNextId(); + } + + /** + * Returns the aspect id, used mainly for saving and network communication. + * @return id + */ + public byte getId() + { + return id; + } + + /** + * Returns the texture offset for this specific aspect. + * @return offset + */ + public int getTextureOffset() + { + return textureOffset; + } + + /** + * Returns true if the aspect is one of the blink states. + * @return true if blinks + */ + public boolean isBlinkAspect() + { + if(this == BLINK_YELLOW || this == BLINK_RED) { + return true; + } + return false; + } + + /** + * Return true if the light is currently off. + * @return true if the light is currently off. + */ + public static boolean isBlinkOn() + { + return blinkState; + } + + /** + * Don't call this, its used to change blink states by Railcraft. + */ + public static void invertBlinkState() + { + blinkState = !blinkState; + } + + /** + * Takes an id and returns an Aspect. + * @param id + * @return + */ + public static EnumSignalAspect fromId(int id) + { + for(EnumSignalAspect a : EnumSignalAspect.values()) { + if(a.getId() == id) { + return a; + } + } + return RED; + } + + /** + * Tests two Aspects and determines which is more restrictive. + * The concept of "most restrictive" refers to which aspect enforces the + * most limitations of movement to a train. + * + * In Railcraft the primary use is in Signal Box logic. + * + * @param first + * @param second + * @return The most restrictive Aspect + */ + public static EnumSignalAspect mostRestrictive(EnumSignalAspect first, EnumSignalAspect second) + { + if(first == null && second != null) { + return second; + } else if(first != null && second == null) { + return first; + } else if(first == null && second == null) { + return RED; + } + if(first == OFF || second == OFF) { + return RED; + } + if(first.getId() > second.getId()) { + return first; + } + return second; + } + + private static byte getNextId() + { + byte i = nextId; + nextId++; + return i; + } + + @Override + public String toString() + { + String[] sa = name().split("_"); + String out = ""; + for(String s : sa) { + out = out + s.substring(0, 1) + s.substring(1).toLowerCase() + " "; + } + out = out.trim(); + return out; + } +} diff --git a/src/common/railcraft/common/api/signals/IBlockSignal.java b/src/common/railcraft/common/api/signals/IBlockSignal.java new file mode 100644 index 00000000..a115423c --- /dev/null +++ b/src/common/railcraft/common/api/signals/IBlockSignal.java @@ -0,0 +1,47 @@ +package railcraft.common.api.signals; + +/** + * This is not documented and needs some reworking to simplify usage. + * @author CovertJaguar + */ +public interface IBlockSignal +{ + + public void startSignalBlockPairing(); + + public void endSignalBlockPairing(); + + public boolean locateRail(); + + public boolean attemptToPair(IBlockSignal other); + + public void clearSignalBlockPairing(String reason, Object... args); + + public boolean isSignalBlockBeingPaired(); + + public boolean isSignalBlockPaired(); + + public IBlockSignal getSignalBlockPair(); + + public int getSignalBlockPairX(); + + public int getSignalBlockPairY(); + + public int getSignalBlockPairZ(); + + public int getRailX(); + + public int getRailY(); + + public int getRailZ(); + + public int getX(); + + public int getY(); + + public int getZ(); + + public int getDimension(); + + public String getDescription(); +} diff --git a/src/common/railcraft/common/api/signals/ISignalController.java b/src/common/railcraft/common/api/signals/ISignalController.java new file mode 100644 index 00000000..a3160d7a --- /dev/null +++ b/src/common/railcraft/common/api/signals/ISignalController.java @@ -0,0 +1,45 @@ +package railcraft.common.api.signals; + +import net.minecraft.src.World; + +/** + * This is not documented and needs some reworking to simplify usage. + * @author CovertJaguar + */ +public interface ISignalController +{ + + public EnumSignalAspect getSignalAspect(); + + public boolean attemptToPairWithReceiver(ISignalReceiver receiver); + + public void startReceiverPairing(); + + public void endReceiverPairing(); + + public void clearPairedReceiver(); + + public boolean isPairedWithReceiver(); + + public ISignalReceiver getReceiver(); + + public int getReceiverX(); + + public int getReceiverY(); + + public int getReceiverZ(); + + public int getX(); + + public int getY(); + + public int getZ(); + + public int getDimension(); + + public World getWorld(); + + public String getDescription(); + + public boolean isInvalid(); +} diff --git a/src/common/railcraft/common/api/signals/ISignalReceiver.java b/src/common/railcraft/common/api/signals/ISignalReceiver.java new file mode 100644 index 00000000..00de2b0c --- /dev/null +++ b/src/common/railcraft/common/api/signals/ISignalReceiver.java @@ -0,0 +1,43 @@ +package railcraft.common.api.signals; + +import net.minecraft.src.World; + +/** + * This is not documented and needs some reworking to simplify usage. + * @author CovertJaguar + */ +public interface ISignalReceiver +{ + + public boolean doesActionOnAspect(EnumSignalAspect aspect); + + public void doActionOnAspect(EnumSignalAspect aspect, boolean trigger); + + public boolean attemptToPairWithController(ISignalController controller); + + public void clearPairedController(); + + public boolean isPairedWithController(); + + public ISignalController getController(); + + public int getControllerX(); + + public int getControllerY(); + + public int getControllerZ(); + + public int getX(); + + public int getY(); + + public int getZ(); + + public int getDimension(); + + public World getWorld(); + + public boolean isInvalid(); + + public String getDescription(); +} diff --git a/src/common/railcraft/common/api/signals/SignalTools.java b/src/common/railcraft/common/api/signals/SignalTools.java new file mode 100644 index 00000000..2c2b272c --- /dev/null +++ b/src/common/railcraft/common/api/signals/SignalTools.java @@ -0,0 +1,159 @@ +package railcraft.common.api.signals; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ItemStack; +import net.minecraft.src.TileEntity; +import net.minecraft.src.World; +import railcraft.common.api.tracks.RailTools; +import railcraft.common.api.core.WorldCoordinate; + +/** + * This is not documented and needs some reworking to simplify usage. + * @author CovertJaguar + */ +public abstract class SignalTools +{ + + private static Map signalBlockPairingMap = new HashMap(); + private static Map controllerReceiverPairingMap = new HashMap(); + + public static boolean isSignalBlockSectionValid(World world, IBlockSignal first, IBlockSignal second) { + return RailTools.areDistantRailsConnectedAlongAxis(world, first.getRailX(), first.getRailY(), first.getRailZ(), second.getRailX(), second.getRailY(), second.getRailZ()); + } + + public static boolean isControllerInRangeOfReceiver(ISignalController c, ISignalReceiver r, int range) { + int distX = c.getX() - r.getX(); + int distY = c.getY() - r.getY(); + int distZ = c.getZ() - r.getZ(); + int distance = (int)Math.sqrt(distX * distX + distY * distY + distZ * distZ); + return distance <= range; + } + + public static void startSignalBlockPairing(EntityPlayer player, ItemStack device, IBlockSignal first) { + endSignalBlockPairing(player, device); + int id = new Random().nextInt(Short.MAX_VALUE); + device.setItemDamage(id); + first.startSignalBlockPairing(); + signalBlockPairingMap.put(new PairingKey(player.username, device.getItemDamage()), new WorldCoordinate(first.getDimension(), first.getX(), first.getY(), first.getZ())); + } + + public static WorldCoordinate getSignalBlockPair(EntityPlayer player, ItemStack device) { + return signalBlockPairingMap.get(new PairingKey(player.username, device.getItemDamage())); + } + + public static void endSignalBlockPairing(EntityPlayer player, ItemStack device) { + WorldCoordinate pos = signalBlockPairingMap.remove(new PairingKey(player.username, device.getItemDamage())); + if(pos != null) { + TileEntity t = player.worldObj.getBlockTileEntity(pos.x, pos.y, pos.z); + if(t instanceof IBlockSignal) { + ((IBlockSignal)t).endSignalBlockPairing(); + } + } + } + + public static void startControllerReceiverPairing(EntityPlayer player, ItemStack device, ISignalController controller) { + endControllerReceiverPairing(player, device); + int id = new Random().nextInt(Short.MAX_VALUE); + device.setItemDamage(id); + controller.startReceiverPairing(); + controllerReceiverPairingMap.put(new PairingKey(player.username, device.getItemDamage()), new WorldCoordinate(controller.getDimension(), controller.getX(), controller.getY(), controller.getZ())); + } + + public static WorldCoordinate getSavedController(EntityPlayer player, ItemStack device) { + return controllerReceiverPairingMap.get(new PairingKey(player.username, device.getItemDamage())); + } + + public static void endControllerReceiverPairing(EntityPlayer player, ItemStack device) { + WorldCoordinate pos = controllerReceiverPairingMap.remove(new PairingKey(player.username, device.getItemDamage())); + if(pos != null) { + TileEntity t = player.worldObj.getBlockTileEntity(pos.x, pos.y, pos.z); + if(t instanceof ISignalController) { + ((ISignalController)t).endReceiverPairing(); + } + } + } + + public static ISignalReceiver getReceiverFor(ISignalController con) { + World world = con.getWorld(); + if(world == null || con.getReceiverY() < 0) { + return null; + } + int i = con.getReceiverX(); + int j = con.getReceiverY(); + int k = con.getReceiverZ(); + if(!world.blockExists(i, j, k)) { + return null; + } + TileEntity pair = world.getBlockTileEntity(i, j, k); + if(pair instanceof ISignalReceiver) { + return (ISignalReceiver)pair; + } else { + con.clearPairedReceiver(); + } + return null; + } + + public static ISignalController getControllerFor(ISignalReceiver rec) { + if(rec.getControllerY() < 0) { + return null; + } + World world = rec.getWorld(); + if(world == null) { + return null; + } + int i = rec.getControllerX(); + int j = rec.getControllerY(); + int k = rec.getControllerZ(); + if(!world.blockExists(i, j, k)) { + return null; + } + TileEntity pair = world.getBlockTileEntity(i, j, k); + if(pair instanceof ISignalController) { + return (ISignalController)pair; + } else { + rec.clearPairedController(); + } + return null; + } + + private static class PairingKey + { + + protected String username; + protected int id; + + public PairingKey(String username, int id) { + this.username = username; + this.id = id; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 59 * hash + (this.username != null ? this.username.hashCode() : 0); + hash = 59 * hash + this.id; + return hash; + } + + @Override + public boolean equals(Object obj) { + if(obj == null) { + return false; + } + if(getClass() != obj.getClass()) { + return false; + } + final PairingKey other = (PairingKey)obj; + if((this.username == null) ? (other.username != null) : !this.username.equals(other.username)) { + return false; + } + if(this.id != other.id) { + return false; + } + return true; + } + } +} diff --git a/src/common/railcraft/common/api/tracks/ITrackCustomPlaced.java b/src/common/railcraft/common/api/tracks/ITrackCustomPlaced.java new file mode 100644 index 00000000..0354d1a6 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/ITrackCustomPlaced.java @@ -0,0 +1,29 @@ +package railcraft.common.api.tracks; + +import net.minecraft.src.World; + +/** + * Have your ITrackInstance implement this to override normal track placement. + * + * Used by tracks such as the Suspended Track. + * + * @author CovertJaguar + */ +public interface ITrackCustomPlaced extends ITrackInstance +{ + + /** + * Used to override normal track placement. + * + * Used by tracks such as the Suspended Track. + * + * Warning: This is called before the TileEntity is set. + * + * @param world The World + * @param i x-Coord + * @param j y-Coord + * @param k z-Coord + * @return true if the rail can placed at the specified location, false to prevent placement + */ + public boolean canPlaceRailAt(World world, int i, int j, int k); +} diff --git a/src/common/railcraft/common/api/tracks/ITrackCustomShape.java b/src/common/railcraft/common/api/tracks/ITrackCustomShape.java new file mode 100644 index 00000000..35fd7e43 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/ITrackCustomShape.java @@ -0,0 +1,24 @@ +package railcraft.common.api.tracks; + +import net.minecraft.src.AxisAlignedBB; +import net.minecraft.src.MovingObjectPosition; +import net.minecraft.src.Vec3; + +/** + * Used by rails that modify the bounding boxes. + * + * For example, the Gated Rails. + * + * Not very useful since there is no system in place to insert custom render code. + * + * @author CovertJaguar + */ +public interface ITrackCustomShape extends ITrackInstance +{ + + public AxisAlignedBB getCollisionBoundingBoxFromPool(); + + public AxisAlignedBB getSelectedBoundingBoxFromPool(); + + public MovingObjectPosition collisionRayTrace(Vec3 vec3d, Vec3 vec3d1); +} diff --git a/src/common/railcraft/common/api/tracks/ITrackEmitter.java b/src/common/railcraft/common/api/tracks/ITrackEmitter.java new file mode 100644 index 00000000..bec74732 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/ITrackEmitter.java @@ -0,0 +1,22 @@ +package railcraft.common.api.tracks; + +/** + * Tracks that can emit a redstone signal should implement + * this interface. + * + * For example a detector track. + * + * A track cannot implement both ITrackPowered and ITrackEmitter. + * + * @author CovertJaguar + */ +public interface ITrackEmitter extends ITrackInstance +{ + + /** + * Return true if the track is producing a redstone signal. + * + * @return true if powered + */ + public boolean isTrackPowering(); +} diff --git a/src/common/railcraft/common/api/tracks/ITrackInstance.java b/src/common/railcraft/common/api/tracks/ITrackInstance.java new file mode 100644 index 00000000..460959fa --- /dev/null +++ b/src/common/railcraft/common/api/tracks/ITrackInstance.java @@ -0,0 +1,123 @@ +package railcraft.common.api.tracks; + +import net.minecraft.src.Entity; +import net.minecraft.src.EntityLiving; +import net.minecraft.src.EntityMinecart; +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.TileEntity; +import railcraft.common.api.core.INetworkedObject; + +/** + * This interface defines a track. + * + * Basically all block and tile entity functions for Tracks are delegated to an + * ITrackInstance. + * + * Instead of implementing this interface directly, you should probably + * extend TrackInstanceBase. It will simplify your life. + * + * All packet manipulation is handled by Railcraft's code, + * you just need to implement the functions in INetworkedObject + * to pass data from the server to the client. + * + * @author CovertJaguar + * @see TrackInstanceBase + */ +public interface ITrackInstance extends INetworkedObject +{ + + public TrackSpec getTrackSpec(); + + /** + * Return the rail's metadata (without the power bit if the rail uses one). + * Can be used to make the cart think the rail something other than it is, + * for example when making diamond junctions or switches. + * + * Valid rail metadata is defined as follows: + * 0x0: flat track going North-South + * 0x1: flat track going West-East + * 0x2: track ascending to the East + * 0x3: track ascending to the West + * 0x4: track ascending to the North + * 0x5: track ascending to the South + * 0x6: WestNorth corner (connecting East and South) + * 0x7: EastNorth corner (connecting West and South) + * 0x8: EastSouth corner (connecting West and North) + * 0x9: WestSouth corner (connecting East and North) + * + * @param cart The cart asking for the metadata, null if it is not called by EntityMinecart. + * @return The metadata. + */ + public int getBasicRailMetadata(EntityMinecart cart); + + /** + * This function is called by any minecart that passes over this rail. + * It is called once per update tick that the minecart is on the rail. + * @param cart The cart on the rail. + */ + public void onMinecartPass(EntityMinecart cart); + + /** + * Return the block texture to be used. + * + * @return + */ + public int getTextureIndex(); + + public void writeToNBT(NBTTagCompound data); + + public void readFromNBT(NBTTagCompound data); + + /** + * Return true if this track requires update ticks. + * @return + */ + public boolean canUpdate(); + + public void updateEntity(); + + public boolean blockActivated(EntityPlayer player); + + public void onBlockPlaced(int side); + + public void onBlockPlacedBy(EntityLiving entity); + + public void onNeighborBlockChange(int id); + + /** + * Internal function that sets the Track's TileEntity so it can + * be referenced for position information, etc... + * @param tile + */ + public void setTile(TileEntity tile); + + public int getX(); + + public int getY(); + + public int getZ(); + + public float getExplosionResistance(double srcX, double srcY, double srcZ, Entity exploder); + + /** + * Return true if the rail can make corners. + * Used by placement logic. + * @return true if the rail can make corners. + */ + public boolean isFlexibleRail(); + + /** + * Returns true if the rail can make up and down slopes. + * Used by placement logic. + * @return true if the rail can make slopes. + */ + public boolean canMakeSlopes(); + + /** + * Returns the max speed of the rail. + * @param cart The cart on the rail, may be null. + * @return The max speed of the current rail. + */ + public float getRailMaxSpeed(EntityMinecart cart); +} diff --git a/src/common/railcraft/common/api/tracks/ITrackLockdown.java b/src/common/railcraft/common/api/tracks/ITrackLockdown.java new file mode 100644 index 00000000..c9c287b4 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/ITrackLockdown.java @@ -0,0 +1,18 @@ +package railcraft.common.api.tracks; + +import net.minecraft.src.EntityMinecart; + +/** + * Any rail tile entity that can completely halt + * all cart movement should implement this interface. + * (Used in collision handling) + * + * @author CovertJaguar + */ +public interface ITrackLockdown extends ITrackInstance +{ + + public boolean isCartLockedDown(EntityMinecart cart); + + public void releaseCart(); +} diff --git a/src/common/railcraft/common/api/tracks/ITrackPowered.java b/src/common/railcraft/common/api/tracks/ITrackPowered.java new file mode 100644 index 00000000..66a9c434 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/ITrackPowered.java @@ -0,0 +1,24 @@ +package railcraft.common.api.tracks; + +/** + * Implementing this interface will allow your track to be + * powered via Redstone. + * + * And so long as you inherit from TrackInstanceBase, all the code for updating + * the power state is already in place (including propagation). + * + * @author CovertJaguar + */ +public interface ITrackPowered extends ITrackInstance +{ + + public boolean isPowered(); + + public void setPowered(boolean powered); + + /** + * The distance that a redstone signal will be passed along from track to track. + * @return int + */ + public int getPowerPropagation(); +} diff --git a/src/common/railcraft/common/api/tracks/ITrackReversable.java b/src/common/railcraft/common/api/tracks/ITrackReversable.java new file mode 100644 index 00000000..c44bff8d --- /dev/null +++ b/src/common/railcraft/common/api/tracks/ITrackReversable.java @@ -0,0 +1,17 @@ +package railcraft.common.api.tracks; + +/** + * Implementing this interface will allow your track to be direction specific. + * + * And so long as you inherit from TrackInstanceBase it will automatically be + * reversable via the Crowbar. + * + * @author CovertJaguar + */ +public interface ITrackReversable extends ITrackInstance +{ + + public boolean isReversed(); + + public void setReversed(boolean reversed); +} diff --git a/src/common/railcraft/common/api/tracks/ITrackSwitch.java b/src/common/railcraft/common/api/tracks/ITrackSwitch.java new file mode 100644 index 00000000..0d30ed84 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/ITrackSwitch.java @@ -0,0 +1,21 @@ +package railcraft.common.api.tracks; + +public interface ITrackSwitch extends ITrackInstance +{ + + enum ArrowDirection + { + + NORTH, SOUTH, EAST, WEST, NORTH_SOUTH, EAST_WEST + }; + + public boolean isSwitched(); + + public void setSwitched(boolean switched); + + public boolean isMirrored(); + + public ArrowDirection getRedSignDirection(); + + public ArrowDirection getWhiteSignDirection(); +} diff --git a/src/common/railcraft/common/api/tracks/ITrackTile.java b/src/common/railcraft/common/api/tracks/ITrackTile.java new file mode 100644 index 00000000..54140bc9 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/ITrackTile.java @@ -0,0 +1,13 @@ +package railcraft.common.api.tracks; + +/** + * Don't use this, its an interface that allows other API code + * access to internal functions of the code. + * + * @author CovertJaguar + */ +public interface ITrackTile +{ + + public ITrackInstance getTrackInstance(); +} diff --git a/src/common/railcraft/common/api/tracks/RailTools.java b/src/common/railcraft/common/api/tracks/RailTools.java new file mode 100644 index 00000000..39353020 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/RailTools.java @@ -0,0 +1,175 @@ +package railcraft.common.api.tracks; + +import railcraft.common.api.core.items.ITrackItem; +import net.minecraft.src.Block; +import net.minecraft.src.BlockRail; +import net.minecraft.src.EntityMinecart; +import net.minecraft.src.ItemBlock; +import net.minecraft.src.ItemStack; +import net.minecraft.src.MathHelper; +import net.minecraft.src.TileEntity; +import net.minecraft.src.World; + +/** + * A number of utility functions related to rails. + * @author CovertJaguar + */ +public abstract class RailTools +{ + + /** + * Attempts to place a rail of the type provided. + * There is no need to verify that the ItemStack contains a valid rail + * prior to calling this function. + * + * The function takes care of that and will return false if the ItemStack + * is not a valid ITrackItem or an ItemBlock who's id + * will return true when passed to BlockRail.isRailBlock(itemID). + * + * That means this function can place any Railcraft or vanilla rail + * and has at least a decent chance of being able to place + * most third party rails. + * + * @param stack The ItemStack containing the rail + * @param world The World object + * @param i x-Coord + * @param j y-Coord + * @param k z-Coord + * @return true if successful + * @see ITrackItem + */ + public static boolean placeRailAt(ItemStack stack, World world, int i, int j, int k) + { + if(stack == null) { + return false; + } + if(stack.getItem() instanceof ITrackItem) { + return ((ITrackItem)stack.getItem()).placeTrack(stack.copy(), world, i, j, k); + } + if(stack.getItem() instanceof ItemBlock && stack.itemID < Block.blocksList.length && BlockRail.isRailBlock(stack.itemID)) { + boolean success = world.setBlockWithNotify(i, j, k, stack.itemID); + if(success) { + world.playSoundEffect((float)i + 0.5F, (float)j + 0.5F, (float)k + 0.5F, Block.rail.stepSound.getStepSound(), (Block.rail.stepSound.getVolume() + 1.0F) / 2.0F, Block.rail.stepSound.getPitch() * 0.8F); + } + return success; + } + return false; + } + + /** + * Returns true if the ItemStack contains a valid Railcraft Track item. + * + * Will return false is passed a vanilla rail. + * + * @param stack The ItemStack to test + * @return true if rail + * @see ITrackItem + */ + public static boolean isTrackItem(ItemStack stack) + { + return stack != null && stack.getItem() instanceof ITrackItem; + } + + /** + * Checks to see if a cart is being held by a ITrackLockdown. + * @param cart The cart to check + * @return True if being held + */ + public static boolean isCartLockedDown(EntityMinecart cart) + { + int x = MathHelper.floor_double(cart.posX); + int y = MathHelper.floor_double(cart.posY); + int z = MathHelper.floor_double(cart.posZ); + + if(BlockRail.isRailBlockAt(cart.worldObj, x, y - 1, z)) { + y--; + } + + TileEntity tile = cart.worldObj.getBlockTileEntity(x, y, z); + if(tile instanceof ITrackTile) { + ITrackInstance track = ((ITrackTile)tile).getTrackInstance(); + return track instanceof ITrackLockdown && ((ITrackLockdown)track).isCartLockedDown(cart); + } + return false; + } + + /** + * Verifies that two rails are connected to each other + * along a straight line with no gaps or wanderings. + * @param world The World object + * @param i1 x-Coord of Rail #1 + * @param j1 y-Coord of Rail #1 + * @param k1 z-Coord of Rail #1 + * @param i2 x-Coord of Rail #2 + * @param j2 y-Coord of Rail #2 + * @param k2 z-Coord of Rail #2 + * @return true if they are connected + */ + public static boolean areDistantRailsConnectedAlongAxis(World world, int i1, int j1, int k1, int i2, int j2, int k2) + { + if(j1 < 0 || j2 < 0) { + return false; + } + if(i1 != i2 && k1 != k2) { + return false; + } + if(i1 != i2) { + int min = 0; + int max = 0; + int jj = 0; + if(i1 < i2) { + min = i1; + max = i2; + jj = j1; + } else { + min = i2; + max = i1; + jj = j2; + } + for(int ii = min; ii <= max; ii++) { + if(world.blockExists(ii, jj, k1)) { + if(BlockRail.isRailBlockAt(world, ii, jj, k1)) { + continue; + } else if(BlockRail.isRailBlockAt(world, ii, jj - 1, k1)) { + jj--; + continue; + } else if(BlockRail.isRailBlockAt(world, ii, jj + 1, k1)) { + jj++; + continue; + } else { + return false; + } + } + } + } else if(k1 != k2) { + int min = 0; + int max = 0; + int jj = 0; + if(k1 < k2) { + min = k1; + max = k2; + jj = j1; + } else { + min = k2; + max = k1; + jj = j2; + } + for(int kk = min; kk <= max; kk++) { + if(world.blockExists(i1, jj, kk)) { + if(BlockRail.isRailBlockAt(world, i1, jj, kk)) { + continue; + } else if(BlockRail.isRailBlockAt(world, i1, jj - 1, kk)) { + jj--; + continue; + } else if(BlockRail.isRailBlockAt(world, i1, jj + 1, kk)) { + jj++; + continue; + } else { + return false; + } + } + } + } + return true; + } +} diff --git a/src/common/railcraft/common/api/tracks/TrackInstanceBase.java b/src/common/railcraft/common/api/tracks/TrackInstanceBase.java new file mode 100644 index 00000000..35d04573 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/TrackInstanceBase.java @@ -0,0 +1,385 @@ +package railcraft.common.api.tracks; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import net.minecraft.src.Block; +import net.minecraft.src.BlockRail; +import net.minecraft.src.Entity; +import net.minecraft.src.EntityLiving; +import net.minecraft.src.EntityMinecart; +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ItemStack; +import net.minecraft.src.MathHelper; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.RailLogic; +import net.minecraft.src.TileEntity; +import net.minecraft.src.World; +import net.minecraftforge.common.ForgeDirection; +import railcraft.common.api.core.items.ICrowbar; + +/** + * All ITrackInstances should extend this class. It contains a number of + * default functions and standard behavior for Tracks that should + * greatly simplify implementing new Tracks when using this API. + * + * @author CovertJaguar + * @see ITrackInstance + * @see TrackRegistry + * @see TrackSpec + */ +public abstract class TrackInstanceBase implements ITrackInstance +{ + + private Block block; + public TileEntity tileEntity; + + private Block getBlock() + { + if(block == null) { + int id = getWorld().getBlockId(getX(), getY(), getZ()); + block = Block.blocksList[id]; + } + return block; + } + + @Override + public void setTile(TileEntity tile) + { + tileEntity = tile; + } + + @Override + public int getBasicRailMetadata(EntityMinecart cart) + { + return tileEntity.getBlockMetadata(); + } + + @Override + public void onMinecartPass(EntityMinecart cart) + { + } + + @Override + public boolean blockActivated(EntityPlayer player) + { + if(this instanceof ITrackReversable) { + ItemStack current = player.getCurrentEquippedItem(); + if(current != null && current.getItem() instanceof ICrowbar) { + ITrackReversable track = (ITrackReversable)this; + track.setReversed(!track.isReversed()); + markBlockNeedsUpdate(); + if(current.isItemStackDamageable()) { + current.damageItem(1, player); + } + return true; + } + } + return false; + } + + @Override + public void onBlockPlaced(int side) + { + switchTrack(true); + testPower(); + markBlockNeedsUpdate(); + } + + @Override + public void onBlockPlacedBy(EntityLiving entityliving) + { + if(entityliving == null) { + return; + } + if(this instanceof ITrackReversable) { + int dir = MathHelper.floor_double((double)((entityliving.rotationYaw * 4F) / 360F) + 0.5D) & 3; + ((ITrackReversable)this).setReversed(dir == 0 || dir == 1); + } + markBlockNeedsUpdate(); + } + + public void markBlockNeedsUpdate() + { + getWorld().markBlockNeedsUpdate(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); + } + + protected boolean isRailValid(World world, int i, int j, int k, int meta) + { + boolean valid = true; + if(!world.isBlockSolidOnSide(i, j - 1, k, ForgeDirection.UP)) { + valid = false; + } + if(meta == 2 && !world.isBlockSolidOnSide(i + 1, j, k, ForgeDirection.UP)) { + valid = false; + } else if(meta == 3 && !world.isBlockSolidOnSide(i - 1, j, k, ForgeDirection.UP)) { + valid = false; + } else if(meta == 4 && !world.isBlockSolidOnSide(i, j, k - 1, ForgeDirection.UP)) { + valid = false; + } else if(meta == 5 && !world.isBlockSolidOnSide(i, j, k + 1, ForgeDirection.UP)) { + valid = false; + } + return valid; + } + + @Override + public void onNeighborBlockChange(int id) + { + int meta = tileEntity.getBlockMetadata(); + boolean valid = isRailValid(getWorld(), tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord, meta); + if(!valid) { + Block blockTrack = getBlock(); + blockTrack.dropBlockAsItem(getWorld(), tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord, 0, 0); + getWorld().setBlockWithNotify(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord, 0); + return; + } + + BlockRail blockTrack = (BlockRail)getBlock(); + if(id > 0 && Block.blocksList[id].canProvidePower() && isFlexibleRail() && RailLogic.getAdjacentTracks(new RailLogic(blockTrack, getWorld(), tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord)) == 3) { + switchTrack(false); + } + testPower(); + } + + protected void switchTrack(boolean flag) + { + int i = tileEntity.xCoord; + int j = tileEntity.yCoord; + int k = tileEntity.zCoord; + BlockRail blockTrack = (BlockRail)getBlock(); + (new RailLogic(blockTrack, getWorld(), i, j, k)).refreshTrackShape(getWorld().isBlockIndirectlyGettingPowered(i, j, k), flag); + } + + protected void testPower() + { + if(!(this instanceof ITrackPowered)) { + return; + } + int i = tileEntity.xCoord; + int j = tileEntity.yCoord; + int k = tileEntity.zCoord; + ITrackPowered r = (ITrackPowered)this; + int meta = tileEntity.getBlockMetadata(); + boolean powered = getWorld().isBlockIndirectlyGettingPowered(i, j, k) || getWorld().isBlockIndirectlyGettingPowered(i, j + 1, k) || testPowerPropagation(getWorld(), i, j, k, getTrackSpec(), meta, r.getPowerPropagation()); + if(powered != r.isPowered()) { + r.setPowered(powered); + Block blockTrack = getBlock(); + getWorld().notifyBlocksOfNeighborChange(i, j, k, blockTrack.blockID); + getWorld().notifyBlocksOfNeighborChange(i, j - 1, k, blockTrack.blockID); + if(meta == 2 || meta == 3 || meta == 4 || meta == 5) { + getWorld().notifyBlocksOfNeighborChange(i, j + 1, k, blockTrack.blockID); + } + markBlockNeedsUpdate(); + // System.out.println("Setting power [" + i + ", " + j + ", " + k + "]"); + } + } + + protected boolean testPowerPropagation(World world, int i, int j, int k, TrackSpec spec, int meta, int maxDist) + { + return isConnectedRailPowered(world, i, j, k, spec, meta, true, 0, maxDist) || isConnectedRailPowered(world, i, j, k, spec, meta, false, 0, maxDist); + } + + protected boolean isConnectedRailPowered(World world, int i, int j, int k, TrackSpec spec, int meta, boolean dir, int dist, int maxDist) + { + if(dist >= maxDist) { + return false; + } + boolean powered = true; + switch (meta) { + case 0: // '\0' + if(dir) { + k++; + } else { + k--; + } + break; + + case 1: // '\001' + if(dir) { + i--; + } else { + i++; + } + break; + + case 2: // '\002' + if(dir) { + i--; + } else { + i++; + j++; + powered = false; + } + meta = 1; + break; + + case 3: // '\003' + if(dir) { + i--; + j++; + powered = false; + } else { + i++; + } + meta = 1; + break; + + case 4: // '\004' + if(dir) { + k++; + } else { + k--; + j++; + powered = false; + } + meta = 0; + break; + + case 5: // '\005' + if(dir) { + k++; + j++; + powered = false; + } else { + k--; + } + meta = 0; + break; + } + if(testPowered(world, i, j, k, spec, dir, dist, maxDist, meta)) { + return true; + } + return powered && testPowered(world, i, j - 1, k, spec, dir, dist, maxDist, meta); + } + + protected boolean testPowered(World world, int i, int j, int k, TrackSpec spec, boolean dir, int dist, int maxDist, int orientation) + { + // System.out.println("Testing Power at <" + i + ", " + j + ", " + k + ">"); + int id = world.getBlockId(i, j, k); + Block blockTrack = getBlock(); + if(id == blockTrack.blockID) { + int meta = world.getBlockMetadata(i, j, k); + TileEntity tile = world.getBlockTileEntity(i, j, k); + if(tile instanceof ITrackTile) { + ITrackInstance track = ((ITrackTile)tile).getTrackInstance(); + if(!(track instanceof ITrackPowered) || track.getTrackSpec() != spec) { + return false; + } + if(orientation == 1 && (meta == 0 || meta == 4 || meta == 5)) { + return false; + } + if(orientation == 0 && (meta == 1 || meta == 2 || meta == 3)) { + return false; + } + if(((ITrackPowered)track).isPowered()) { + if(world.isBlockIndirectlyGettingPowered(i, j, k) || world.isBlockIndirectlyGettingPowered(i, j + 1, k)) { + return true; + } else { + return isConnectedRailPowered(world, i, j, k, spec, meta, dir, dist + 1, maxDist); + } + } + } + } + return false; + } + + @Override + public int getTextureIndex() + { + return getTrackSpec().getTextureIndex(); + } + + @Override + public void writeToNBT(NBTTagCompound data) + { + } + + @Override + public void readFromNBT(NBTTagCompound data) + { + } + + @Override + public boolean canUpdate() + { + return false; + } + + @Override + public void updateEntity() + { + } + + @Override + public float getExplosionResistance(double srcX, double srcY, double srcZ, Entity exploder) + { + return 3.5f; + } + + @Override + public void writePacketData(DataOutputStream data) throws IOException + { + } + + @Override + public void readPacketData(DataInputStream data) throws IOException + { + } + + @Override + public World getWorld() + { + return tileEntity.worldObj; + } + + @Override + public int getX() + { + return tileEntity.xCoord; + } + + @Override + public int getY() + { + return tileEntity.yCoord; + } + + @Override + public int getZ() + { + return tileEntity.zCoord; + } + + /** + * Return true if the rail can make corners. + * Used by placement logic. + * @return true if the rail can make corners. + */ + @Override + public boolean isFlexibleRail() + { + return false; + } + + /** + * Returns true if the rail can make up and down slopes. + * Used by placement logic. + * @return true if the rail can make slopes. + */ + @Override + public boolean canMakeSlopes() + { + return true; + } + + /** + * Returns the max speed of the rail. + * @param cart The cart on the rail, may be null. + * @return The max speed of the current rail. + */ + @Override + public float getRailMaxSpeed(EntityMinecart cart) + { + return 0.4f; + } +} diff --git a/src/common/railcraft/common/api/tracks/TrackRegistry.java b/src/common/railcraft/common/api/tracks/TrackRegistry.java new file mode 100644 index 00000000..017dd31f --- /dev/null +++ b/src/common/railcraft/common/api/tracks/TrackRegistry.java @@ -0,0 +1,62 @@ +package railcraft.common.api.tracks; + +import cpw.mods.fml.common.FMLCommonHandler; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; + +/** + * The TrackRegistry is part of a system that allows 3rd party addons to simply, + * quickly, and easily define new Tracks with unique behaviors without requiring + * that any additional block ids be used. + * + * All the tracks in RailcraftProxy are implemented using this system 100% + * (except for Gated Tracks and Switch Tracks which have some custom render code). + * + * To define a new track, you need to define a TrackSpec and create a ITrackInstance. + * + * The TrackSpec contains basic constant information about the Track, while the TrackInstace + * controls how an individual Track block interact with the world. + * + * @author CovertJaguar + * @see TrackSpec + * @see ITrackInstance + * @see TrackInstanceBase + */ +public class TrackRegistry +{ + + private static Map trackSpecs = new HashMap(); + + public static void registerTrackSpec(TrackSpec trackSpec) + { + if(trackSpecs.put(trackSpec.getTrackId(), trackSpec) != null) { + throw new RuntimeException("TrackId conflict detected, please adjust your config or contact the author of the " + trackSpec.getTrackTag()); + } + } + + /** + * Returns a cached copy of a TrackSpec object. + * + * @param trackId + * @return + */ + public static TrackSpec getTrackSpec(int trackId) + { + TrackSpec spec = trackSpecs.get((short)trackId); + if(spec == null) { + FMLCommonHandler.instance().getFMLLogger().log(Level.WARNING, "[Railcraft] Unknown Track Spec ID({0}), reverting to normal track", trackId); + spec = trackSpecs.get(-1); + } + return spec; + } + + /** + * Returns all Registered TrackSpecs. + * @return list of TrackSpecs + */ + public static Map getTrackSpecs() + { + return trackSpecs; + } +} diff --git a/src/common/railcraft/common/api/tracks/TrackSpec.java b/src/common/railcraft/common/api/tracks/TrackSpec.java new file mode 100644 index 00000000..68608a63 --- /dev/null +++ b/src/common/railcraft/common/api/tracks/TrackSpec.java @@ -0,0 +1,86 @@ +package railcraft.common.api.tracks; + +import net.minecraft.src.ItemStack; +import railcraft.common.api.core.items.ItemRegistry; + +/** + * Each type of Track has a single instance of TrackSpec + * that corresponds with it. + * + * Each Track block in the world has a ITrackInstance that + * corresponds with it. + * + * Take note of the difference (similar to block classes and tile entities classes). + * + * TrackSpecs must be registered with the TrackRegistry. + * + * Track Items can be acquired with the ItemRegistry. + * + * @see TrackRegistry + * @see ITrackInstance + * + * @author CovertJaguar + */ +public final class TrackSpec +{ + + public static int blockID = 0; + private final String tag; + private final String textureFile; + private final short trackId; + private final int textureId; + private final Class instanceClass; + + /** + * Defines a new track spec. + * + * @param trackId A unique identifier for the track type. 0-512 are reserved for Railcraft. Capped at Short.MAX_VALUE + * @param tag A unique internal string identifier (ex. "track.speed.transition") + * @param textureFile See ITextureProvider + * @param textureId The texture index used by the track's item + * @param instanceClass The ITrackInstance class that corresponds to this TrackSpec + * @see ITextureProvider + */ + public TrackSpec(short trackId, String tag, String textureFile, int textureId, Class instanceClass) { + this.trackId = trackId; + this.tag = tag; + this.textureFile = textureFile; + this.textureId = textureId; + this.instanceClass = instanceClass; + } + + public String getTrackTag() { + return tag; + } + + public short getTrackId() { + return trackId; + } + + public ItemStack getItem() { + return getItem(1); + } + + public ItemStack getItem(int qty) { + if(blockID <= 0) { + return null; + } + return new ItemStack(blockID, qty, getTrackId()); + } + + public ITrackInstance createInstanceFromSpec() { + try { + return (ITrackInstance)instanceClass.newInstance(); + } catch (Exception ex) { + throw new RuntimeException("Improper Track Instance Constructor"); + } + } + + public String getTextureFile() { + return textureFile; + } + + public int getTextureIndex() { + return textureId; + } +} diff --git a/src/common/steampower/BlockMachine.java b/src/common/steampower/BlockMachine.java index 06752f12..ca822ff1 100644 --- a/src/common/steampower/BlockMachine.java +++ b/src/common/steampower/BlockMachine.java @@ -232,7 +232,7 @@ public class BlockMachine extends universalelectricity.prefab.BlockMachine @Override public int getRenderType() { - return -1; + return ItemRenderHelperS.renderID; } } diff --git a/src/common/steampower/ItemMachine.java b/src/common/steampower/ItemMachine.java index 9371c923..c80b7cca 100644 --- a/src/common/steampower/ItemMachine.java +++ b/src/common/steampower/ItemMachine.java @@ -19,7 +19,7 @@ public class ItemMachine extends ItemBlock { par3List.add(new ItemStack(this, 1, 1)); par3List.add(new ItemStack(this, 1, 2)); - par3List.add(new ItemStack(this, 1, 15)); + } @Override public String getTextureFile() { diff --git a/src/common/steampower/turbine/BlockGenerator.java b/src/common/steampower/turbine/BlockGenerator.java index 4bcb0997..4d512832 100644 --- a/src/common/steampower/turbine/BlockGenerator.java +++ b/src/common/steampower/turbine/BlockGenerator.java @@ -2,6 +2,7 @@ package steampower.turbine; import java.util.ArrayList; +import steampower.ItemRenderHelperS; import steampower.TileEntityMachine; import net.minecraft.src.CreativeTabs; @@ -58,7 +59,7 @@ public class BlockGenerator extends universalelectricity.prefab.BlockMachine { @Override public int getRenderType() { - return -1; + return ItemRenderHelperS.renderID; } @Override public TileEntity createNewTileEntity(World world) diff --git a/src/common/steampower/turbine/TileEntityGen.java b/src/common/steampower/turbine/TileEntityGen.java index eafffc81..a0d3a24c 100644 --- a/src/common/steampower/turbine/TileEntityGen.java +++ b/src/common/steampower/turbine/TileEntityGen.java @@ -17,7 +17,7 @@ import com.google.common.io.ByteArrayDataInput; public class TileEntityGen extends TileEntityMachine implements IPacketReceiver, IMechanical,IElectricityProducer { - ForgeDirection facing; + ForgeDirection facing = ForgeDirection.DOWN; public int force = 0; public int aForce = 0; @@ -33,19 +33,17 @@ public class TileEntityGen extends TileEntityMachine implements IPacketReceiver, public void updateEntity() { - if(tCount++ >= 10) - {tCount = 0; - super.updateEntity(); - this.genAmmount = (force * 1.2)/this.getVoltage(); + + this.genAmmount = force/this.getVoltage(); int meta = worldObj.getBlockMetadata(xCoord, yCoord, zCoord); int nMeta = 0; - + int wireCount = 0; switch(meta) { case 0: nMeta = 2;break; - case 1: nMeta = 4;break; + case 1: nMeta = 5;break; case 2: nMeta = 3;break; - case 3: nMeta = 5;break; + case 3: nMeta = 4;break; } facing = ForgeDirection.getOrientation(nMeta).getOpposite(); if(genAmmount > 0) @@ -73,7 +71,7 @@ public class TileEntityGen extends TileEntityMachine implements IPacketReceiver, if (ElectricityManager.instance.getElectricityRequired( ((IConductor)tileEntity).getConnectionID()) > 0) { this.wires[i] = (IConductor)tileEntity; - ElectricityManager.instance.produceElectricity(this, this.wires[i],genAmmount, this.getVoltage()); + wireCount++; } else { @@ -84,9 +82,18 @@ public class TileEntityGen extends TileEntityMachine implements IPacketReceiver, { this.wires[i] = null; } - } + } + } + for(int side =0; side < 6; side++) + { + if(wires[side] instanceof IConductor) + { + double max = wires[side].getMaxAmps(); + ElectricityManager.instance.produceElectricity(this, wires[side],Math.min(genAmmount/wireCount,max), this.getVoltage()); + } } + super.updateEntity(); } @Override public void handlePacketData(NetworkManager network, diff --git a/src/common/steampower/turbine/TileEntitySteamPiston.java b/src/common/steampower/turbine/TileEntitySteamPiston.java index 98d7d28b..1caf8116 100644 --- a/src/common/steampower/turbine/TileEntitySteamPiston.java +++ b/src/common/steampower/turbine/TileEntitySteamPiston.java @@ -26,6 +26,7 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR { public int force = 0; public int aForce = 0; + public int bForce = 0; private int frictionLoad = 10; public int steam = 0; public int water = 0; @@ -38,9 +39,8 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR private int posCount = 0; public int tCount = 0; private ForgeDirection frontDir; - private ForgeDirection backDir; - public TileEntity bb; public TileEntity ff; + public TileEntity bb; public boolean running= false; @@ -59,14 +59,13 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR switch(meta) { case 0: nMeta = 2;break; - case 1: nMeta = 4;break; + case 1: nMeta = 5;break; case 2: nMeta = 3;break; - case 3: nMeta = 5;break; + case 3: nMeta = 4;break; } frontDir = ForgeDirection.getOrientation(nMeta); - backDir = ForgeDirection.getOrientation(nMeta).getOpposite(); - bb = worldObj.getBlockTileEntity(xCoord+backDir.offsetX, yCoord+1, zCoord+backDir.offsetZ); ff = worldObj.getBlockTileEntity(xCoord+frontDir.offsetX, yCoord+1, zCoord+frontDir.offsetZ); + bb = worldObj.getBlockTileEntity(xCoord+frontDir.getOpposite().offsetX, yCoord+1, zCoord+frontDir.getOpposite().offsetZ); if(this.runTime > 0) { this.running = true; @@ -83,11 +82,6 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR pos += 1;if(pos > 7){pos =0;} } } - if(bb instanceof TileEntitySteamPiston) - { - this.pos = ((TileEntitySteamPiston) bb).getAnimationPos() + 1; - if(this.pos > 7){pos = 0;} - } if(!worldObj.isRemote) { if(this.runTime < 1 && this.steam > 0) @@ -95,12 +89,30 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR this.steam--; this.runTime=60; } + if(bb instanceof IMechanical) + { + if(((IMechanical) bb).canOutputSide(frontDir)) + { + this.bForce = ((IMechanical) bb).getForce(); + }else + if( bb instanceof TileEntitySteamPiston) + { + if(((TileEntitySteamPiston) bb).getMeta() == this.getMeta()) + { + this.bForce = ((TileEntitySteamPiston) bb).getForce(); + } + } + else + { + this.bForce = 0; + } + } if(this.runTime > 0) { genRate=Math.min(genRate + 1, 100); this.runTime-=1; this.force = Math.min(genRate * 10,1000); - this.aForce = Math.max(force - this.frictionLoad,0); + this.aForce = Math.max(force - this.frictionLoad+bForce,0); } if(runTime == 0 && this.steam == 0) { @@ -110,9 +122,12 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR if(ff instanceof IMechanical) { - if(((IMechanical) ff).canInputSide(backDir)) + if(((IMechanical) ff).canInputSide(frontDir.getOpposite())) { ((IMechanical) ff).applyForce(this.aForce); + }else + { + } } @@ -133,7 +148,7 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR @Override public boolean canOutputSide(ForgeDirection side) { - if(frontDir == side) + if(frontDir.getOpposite() == side) { return true; } @@ -142,7 +157,7 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR @Override public boolean canInputSide(ForgeDirection side) { - if(backDir == side) + if(frontDir == side) { return true; } @@ -151,7 +166,7 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR @Override public int applyForce(int force) { - this.aForce = this.force + force- frictionLoad; + this.bForce = force; return aForce; } @@ -245,7 +260,7 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR //---------------- public Object[] getSendData() { - return new Object[]{steam,water,force,aForce,genRate,runTime}; + return new Object[]{steam,water,force,aForce,bForce,genRate,runTime}; } @Override public void handlePacketData(NetworkManager network,Packet250CustomPayload packet, EntityPlayer player,ByteArrayDataInput dataStream) { @@ -255,6 +270,7 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR this.water = dataStream.readInt(); this.force = dataStream.readInt(); this.aForce = dataStream.readInt(); + this.bForce = dataStream.readInt(); this.genRate= dataStream.readInt(); this.runTime = dataStream.readInt(); //System.out.print("Packet \n"); @@ -301,5 +317,7 @@ public class TileEntitySteamPiston extends TileEntityMachine implements IPacketR // TODO Auto-generated method stub return this.force; } - + public int getMeta() { + return worldObj.getBlockMetadata(xCoord, yCoord, zCoord); + } } diff --git a/src/minecraft/basicpipes/ItemRenderHelper.java b/src/minecraft/basicpipes/ItemRenderHelper.java new file mode 100644 index 00000000..036bb39a --- /dev/null +++ b/src/minecraft/basicpipes/ItemRenderHelper.java @@ -0,0 +1,56 @@ +package basicpipes; + +import net.minecraft.src.Block; +import net.minecraft.src.IBlockAccess; +import net.minecraft.src.RenderBlocks; + +import org.lwjgl.opengl.GL11; + +import basicpipes.conductors.TileEntityPipe; +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; +import cpw.mods.fml.client.registry.RenderingRegistry; + +public class ItemRenderHelper implements ISimpleBlockRenderingHandler { + public static ItemRenderHelper instance = new ItemRenderHelper(); + public static int renderID = RenderingRegistry.getNextAvailableRenderId(); + private ModelPump modelPump = new ModelPump(); + private ModelGearRod modelRod = new ModelGearRod(); + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + if(block.blockID == BasicPipesMain.machineID && metadata < 4) + { + GL11.glPushMatrix(); + GL11.glTranslatef((float) 0.0F, (float)1.1F, (float)0.0F); + GL11.glRotatef(180f, 0f, 0f, 1f); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, FMLClientHandler.instance().getClient().renderEngine.getTexture("/textures/pumps/Pump.png")); + modelPump.renderMain(0.0725F); + modelPump.renderC1(0.0725F); + modelPump.renderC2(0.0725F); + modelPump.renderC3(0.0725F); + GL11.glPopMatrix(); + } + if(block.blockID == BasicPipesMain.rodID) + { + GL11.glPushMatrix(); + GL11.glTranslatef((float) 0.0F, (float)1.5F, (float)0.0F); + GL11.glRotatef(180f, 0f, 0f, 1f); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, FMLClientHandler.instance().getClient().renderEngine.getTexture("/textures/GearRod.png")); + modelRod.render(0.0825F,0); + GL11.glPopMatrix(); + } + } + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + return false; + } + + public boolean shouldRender3DInInventory() { + + return true; + } + + public int getRenderId() + { + return renderID; + } +} diff --git a/src/minecraft/basicpipes/PipeClientProxy.java b/src/minecraft/basicpipes/PipeClientProxy.java index d25e7b7e..74984883 100644 --- a/src/minecraft/basicpipes/PipeClientProxy.java +++ b/src/minecraft/basicpipes/PipeClientProxy.java @@ -7,6 +7,7 @@ import basicpipes.conductors.TileEntityRod; import basicpipes.machines.TileEntityPump; import net.minecraftforge.client.MinecraftForgeClient; import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.client.registry.RenderingRegistry; import cpw.mods.fml.common.registry.GameRegistry; public class PipeClientProxy extends PipeProxy @@ -17,6 +18,7 @@ public class PipeClientProxy extends PipeProxy //Preload textures MinecraftForgeClient.preloadTexture(BasicPipesMain.textureFile+"/Items.png"); MinecraftForgeClient.preloadTexture(BasicPipesMain.textureFile+"/blocks.png"); + RenderingRegistry.registerBlockHandler(new ItemRenderHelper()); } @Override diff --git a/src/minecraft/steampower/GUISteamPiston.java b/src/minecraft/steampower/GUISteamPiston.java index f3e314df..339e94cd 100644 --- a/src/minecraft/steampower/GUISteamPiston.java +++ b/src/minecraft/steampower/GUISteamPiston.java @@ -61,7 +61,8 @@ import universalelectricity.electricity.ElectricInfo.ElectricUnit; displayText2 = "water" + "-" + tileEntity.water; displayText3 = "steam" + "-" + tileEntity.steam; - displayText4 = "Debug:Time" + "=" + tileEntity.tCount; + displayText4 = "Debug:Time" + "=" + tileEntity.tCount; + displayText5 = "Debug:bforce" + "=" + tileEntity.bForce; this.fontRenderer.drawString(displayText, (int)(105-displayText.length()*1), 45, 4210752); this.fontRenderer.drawString(displayText2, (int)(105-displayText.length()*1), 55, 4210752); diff --git a/src/minecraft/steampower/ItemRenderHelperS.java b/src/minecraft/steampower/ItemRenderHelperS.java new file mode 100644 index 00000000..11041fbf --- /dev/null +++ b/src/minecraft/steampower/ItemRenderHelperS.java @@ -0,0 +1,62 @@ +package steampower; + +import net.minecraft.src.Block; +import net.minecraft.src.IBlockAccess; +import net.minecraft.src.RenderBlocks; + +import org.lwjgl.opengl.GL11; + +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; +import cpw.mods.fml.client.registry.RenderingRegistry; +//ItemRenderHelperS.renderID +public class ItemRenderHelperS implements ISimpleBlockRenderingHandler { + public static ItemRenderHelperS instance = new ItemRenderHelperS(); + public static int renderID = RenderingRegistry.getNextAvailableRenderId(); + private ModelGenerator modelGen = new ModelGenerator(); + private ModelTank modelTank = new ModelTank(0f); + private ModelFurnace modelFurnace = new ModelFurnace(); + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + if(block.blockID == SteamPowerMain.genID) + { + GL11.glPushMatrix(); + GL11.glTranslatef((float) 0.0F, (float)1.3F, (float)0.0F); + GL11.glRotatef(180f, 0f, 0f, 1f); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, FMLClientHandler.instance().getClient().renderEngine.getTexture(SteamPowerMain.textureFile+"Generator.png")); + modelGen.RenderMain(0.0725F); + GL11.glPopMatrix(); + } + if(block.blockID == SteamPowerMain.machine.blockID && metadata == 1) + { + GL11.glPushMatrix(); + GL11.glTranslatef((float) 0.0F, (float)1F, (float)0.0F); + GL11.glRotatef(180f, 0f, 0f, 1f); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, FMLClientHandler.instance().getClient().renderEngine.getTexture(SteamPowerMain.textureFile+"tankTexture.png")); + modelTank.generalRender(0.0625F); + GL11.glPopMatrix(); + } + if(block.blockID == SteamPowerMain.machine.blockID && metadata > 1 && metadata < 6) + { + GL11.glPushMatrix(); + GL11.glTranslatef((float) 0.0F, (float)1F, (float)0.0F); + GL11.glRotatef(180f, 0f, 0f, 1f); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, FMLClientHandler.instance().getClient().renderEngine.getTexture(SteamPowerMain.textureFile+"Furnace.png")); + modelFurnace.genRender(0.0625F); + GL11.glPopMatrix(); + } + } + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + return false; + } + + public boolean shouldRender3DInInventory() { + + return true; + } + + public int getRenderId() + { + return renderID; + } +} diff --git a/src/minecraft/steampower/SteamClientProxy.java b/src/minecraft/steampower/SteamClientProxy.java index e5201e88..86acc571 100644 --- a/src/minecraft/steampower/SteamClientProxy.java +++ b/src/minecraft/steampower/SteamClientProxy.java @@ -8,6 +8,7 @@ import steampower.geared.RenderGearPiston; import steampower.turbine.TileEntityGen; import steampower.turbine.TileEntitySteamPiston; import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.client.registry.RenderingRegistry; public class SteamClientProxy extends SteamProxy{ @@ -15,6 +16,7 @@ public class SteamClientProxy extends SteamProxy{ { MinecraftForgeClient.preloadTexture(SteamPowerMain.textureFile+"blocks.png"); MinecraftForgeClient.preloadTexture(SteamPowerMain.textureFile+"Items.png"); + RenderingRegistry.registerBlockHandler(new ItemRenderHelperS()); } @Override public void init()