Bug Fixed and add new Item renders

Fixed a few bugs and improved how some thing work. Also added item
renders for some blocks so they look better in hand.
This commit is contained in:
Rseifert 2012-10-04 01:47:34 -04:00
parent 10c0eedf88
commit bf060956df
92 changed files with 6381 additions and 42 deletions

View file

@ -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;
}
}

View file

@ -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

View file

@ -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() {

View file

@ -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;
}
}

View file

@ -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<ItemStack, BaseSeed> baseseeds = new HashMap<ItemStack, BaseSeed>();
/**
* 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;
}
}

View file

@ -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<BiomeGenBase,Integer> humidityBiomeBonus = new HashMap<BiomeGenBase,Integer>();
private static final HashMap<BiomeGenBase,Integer> nutrientBiomeBonus = new HashMap<BiomeGenBase,Integer>();
/**
* 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;
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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<Block> whitelist = new HashSet<Block>();
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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<String> getNetworkedFields();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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<Map.Entry<ItemStack, ItemStack> > getCompressorRecipes() {
if (TileEntityCompressor_recipes == null) {
try {
TileEntityCompressor_recipes = (List<Map.Entry<ItemStack, ItemStack> >) 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<ItemStack, ItemStack>(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<Map.Entry<ItemStack, ItemStack> > getExtractorRecipes() {
if (TileEntityExtractor_recipes == null) {
try {
TileEntityExtractor_recipes = (List<Map.Entry<ItemStack, ItemStack> >) 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<ItemStack, ItemStack>(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<Map.Entry<ItemStack, ItemStack> > getMaceratorRecipes() {
if (TileEntityMacerator_recipes == null) {
try {
TileEntityMacerator_recipes = (List<Map.Entry<ItemStack, ItemStack> >) 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<ItemStack, ItemStack>(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<Map.Entry<ItemStack, ItemStack> > recipeList) {
assert input != null;
for (Map.Entry<ItemStack, ItemStack> 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<ItemStack> getRecyclerBlacklist() {
if (TileEntityRecycler_blacklist == null) {
try {
TileEntityRecycler_blacklist = (List<ItemStack>) 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<Map.Entry<ItemStack,Float>> getScrapboxDrops() {
try {
return (List<Map.Entry<ItemStack,Float>>) 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<Map.Entry<ItemStack, Integer> > getMatterAmplifiers() {
if (TileEntityMatter_amplifiers == null) {
try {
TileEntityMatter_amplifiers = (List<Map.Entry<ItemStack, Integer> >) 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<ItemStack,Integer>(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<Map.Entry<ItemStack, ItemStack> > TileEntityCompressor_recipes;
private static List<Map.Entry<ItemStack, ItemStack> > TileEntityExtractor_recipes;
private static List<Map.Entry<ItemStack, ItemStack> > TileEntityMacerator_recipes;
private static List<ItemStack> TileEntityRecycler_blacklist;
private static List<Map.Entry<ItemStack, Integer> > TileEntityMatter_amplifiers;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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();
}
}

View file

@ -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<? extends EntityMinecart> 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 <code>IMinecartItem</code>
* and/or extend <code>ItemMinecart</code>.
*
* 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<EntityMinecart> 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<? extends EntityMinecart> 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<? extends EntityMinecart> type, boolean subclass) {
List<EntityMinecart> list = new ArrayList<EntityMinecart>();
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<? extends EntityMinecart> type, boolean subclass) {
List<EntityMinecart> 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<EntityMinecart> getMinecartsOnAllSides(World world, int i, int j, int k, float sensitivity) {
List<EntityMinecart> carts = new ArrayList<EntityMinecart>();
for(int side = 0; side < 6; side++) {
carts.addAll(getMinecartsOnSide(world, i, j, k, sensitivity, ForgeDirection.getOrientation(side)));
}
return carts;
}
public static List<EntityMinecart> getMinecartsOnAllSides(World world, int i, int j, int k, float sensitivity, Class<? extends EntityMinecart> type, boolean subclass) {
List<EntityMinecart> list = new ArrayList<EntityMinecart>();
List<EntityMinecart> carts = new ArrayList<EntityMinecart>();
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<EntityMinecart> 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<? extends EntityMinecart> 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<? extends EntityMinecart> 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<EntityMinecart> 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<EntityMinecart> carts = new ArrayList<EntityMinecart>();
for(Object o : entities) {
carts.add((EntityMinecart)o);
}
return carts;
}
public static List<EntityMinecart> 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<EntityMinecart> carts = new ArrayList<EntityMinecart>();
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;
}
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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();
}

View file

@ -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 <railcraft.wikispaces.com>
* @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();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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:<br/>
* 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:<br/>
* 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);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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);
}

View file

@ -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 <railcraft.wikispaces.com>
* @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);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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();
}

View file

@ -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 <railcraft.wikispaces.com>
* @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);
}

View file

@ -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.
* <br/>
* <br/>
* Classes that extend this class:<br/>
* EntityCartChest<br/>
* EntityCartAnchor<br/>
*
* @author CovertJaguar <railcraft.wikispaces.com>
*/
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;
}
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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);
}

View file

@ -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;
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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;
}
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public abstract class BallastRegistry
{
private static Set<ItemWrapper> ballastRegistry = new HashSet<ItemWrapper>();
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<ItemStack> getRegisteredBallasts()
{
List<ItemStack> list = new ArrayList<ItemStack>();
for(ItemWrapper item : ballastRegistry) {
list.add(item.stack);
}
return list;
}
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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;
}
}
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public interface ICrowbar
{
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public final class ItemRegistry
{
private static final Map<String, ItemStack> registry = new TreeMap<String, ItemStack>();
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<String, ItemStack> getItems()
{
return registry;
}
}

View file

@ -0,0 +1,25 @@
package railcraft.common.api.crafting;
import java.util.List;
import net.minecraft.src.ItemStack;
/**
*
* @author CovertJaguar <railcraft.wikispaces.com>
*/
public interface IBlastFurnaceCraftingManager
{
void addRecipe(int inputId, int inputDamage, int cookTime, ItemStack output);
void addRecipe(int inputId, int cookTime, ItemStack output);
List<ItemStack> getFuels();
IBlastFurnaceRecipe getRecipe(int inputId, int inputDamage);
IBlastFurnaceRecipe getRecipe(ItemStack stack);
List<IBlastFurnaceRecipe> getRecipes();
}

View file

@ -0,0 +1,21 @@
package railcraft.common.api.crafting;
import net.minecraft.src.ItemStack;
/**
*
* @author CovertJaguar <railcraft.wikispaces.com>
*/
public interface IBlastFurnaceRecipe
{
public int getCookTime();
public ItemStack getInput();
public ItemStack getOutput();
int getOutputStackSize();
boolean isRoomForOutput(ItemStack out);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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<ICokeOvenRecipe> getRecipes();
}

View file

@ -0,0 +1,20 @@
package railcraft.common.api.crafting;
import buildcraft.api.liquids.LiquidStack;
import net.minecraft.src.ItemStack;
/**
*
* @author CovertJaguar <railcraft.wikispaces.com>
*/
public interface ICokeOvenRecipe
{
public int getCookTime();
public ItemStack getInput();
public LiquidStack getLiquidOutput();
public ItemStack getOutput();
}

View file

@ -0,0 +1,35 @@
package railcraft.common.api.crafting;
import java.util.HashMap;
import java.util.List;
import net.minecraft.src.ItemStack;
/**
*
* @author CovertJaguar <railcraft.wikispaces.com>
*/
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<ItemStack, Float> 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<ItemStack, Float> output);
IRockCrusherRecipe getRecipe(ItemStack input);
IRockCrusherRecipe getRecipe(int inputId, int inputDamage);
List<IRockCrusherRecipe> getRecipes();
}

View file

@ -0,0 +1,37 @@
package railcraft.common.api.crafting;
import java.util.List;
import java.util.Map;
import net.minecraft.src.ItemStack;
/**
*
* @author CovertJaguar <railcraft.wikispaces.com>
*/
public interface IRockCrusherRecipe
{
public ItemStack getInput();
/**
* Returns a map containing each output entry and its chance of being included.
*
* @return
*/
public Map<ItemStack, Float> getOutputs();
/**
* Returns a list of all possible outputs.
* This is basically a condensed version of getOutputs().keySet().
*
* @return
*/
public List<ItemStack> getPossibleOuput();
/**
* Returns a list of outputs after it has passed through the randomizer.
*
* @return
*/
public List<ItemStack> getRandomizedOuput();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public interface IRollingMachineCraftingManager
{
void addRecipe(ItemStack output, Object[] components);
void addShapelessRecipe(ItemStack output, Object[] compenents);
ItemStack findMatchingRecipe(InventoryCrafting inventorycrafting);
List<IRecipe> getRecipeList();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public abstract class RailcraftCraftingManager
{
public static ICokeOvenCraftingManager cokeOven;
public static IBlastFurnaceCraftingManager blastFurnace;
public static IRockCrusherCraftingManager rockCrusher;
public static IRollingMachineCraftingManager rollingMachine;
}

View file

@ -0,0 +1,155 @@
package railcraft.common.api.signals;
/**
* Represents a Signal state.
* @author CovertJaguar <railcraft.wikispaces.com>
*/
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;
}
}

View file

@ -0,0 +1,47 @@
package railcraft.common.api.signals;
/**
* This is not documented and needs some reworking to simplify usage.
* @author CovertJaguar <railcraft.wikispaces.com>
*/
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();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public abstract class SignalTools
{
private static Map<PairingKey, WorldCoordinate> signalBlockPairingMap = new HashMap<PairingKey, WorldCoordinate>();
private static Map<PairingKey, WorldCoordinate> controllerReceiverPairingMap = new HashMap<PairingKey, WorldCoordinate>();
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;
}
}
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public interface ITrackCustomShape extends ITrackInstance
{
public AxisAlignedBB getCollisionBoundingBoxFromPool();
public AxisAlignedBB getSelectedBoundingBoxFromPool();
public MovingObjectPosition collisionRayTrace(Vec3 vec3d, Vec3 vec3d1);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public interface ITrackEmitter extends ITrackInstance
{
/**
* Return true if the track is producing a redstone signal.
*
* @return true if powered
*/
public boolean isTrackPowering();
}

View file

@ -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);
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public interface ITrackLockdown extends ITrackInstance
{
public boolean isCartLockedDown(EntityMinecart cart);
public void releaseCart();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public interface ITrackReversable extends ITrackInstance
{
public boolean isReversed();
public void setReversed(boolean reversed);
}

View file

@ -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();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
public interface ITrackTile
{
public ITrackInstance getTrackInstance();
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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;
}
}

View file

@ -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 <railcraft.wikispaces.com>
* @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;
}
}

View file

@ -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 <railcraft.wikispaces.com>
* @see TrackSpec
* @see ITrackInstance
* @see TrackInstanceBase
*/
public class TrackRegistry
{
private static Map<Short, TrackSpec> trackSpecs = new HashMap<Short, TrackSpec>();
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<Short, TrackSpec> getTrackSpecs()
{
return trackSpecs;
}
}

View file

@ -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 <railcraft.wikispaces.com>
*/
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<? extends ITrackInstance> 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<? extends ITrackInstance> 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;
}
}

View file

@ -232,7 +232,7 @@ public class BlockMachine extends universalelectricity.prefab.BlockMachine
@Override
public int getRenderType()
{
return -1;
return ItemRenderHelperS.renderID;
}
}

View file

@ -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() {

View file

@ -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)

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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()