REPLACED MASTER WITH 1.7.10

This commit is contained in:
chylex committed 2015-03-13 10:12:20 +01:00
1 parent c24cc52abf
commit 412761b056
625 files changed
+16508 -8346

No files matched your search

+2 -3
View File
@@ -19,15 +19,14 @@ apply plugin: 'forge'
version = ""
group = "chylex.hee.HardcoreEnderExpansion"
archivesBaseName = "HardcoreEnderExpansion MC-1.8 v1."
archivesBaseName = "HardcoreEnderExpansion MC-1.7.10 v1.7.1"
sourceCompatibility = 1.7
targetCompatibility = 1.7
minecraft {
version = "1.8-11.14.1.1306"
version = "1.7.10-10.13.2.1291"
runDir = "eclipse"
mappings = "snapshot_20150118"
}
processResources {
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
View File
Binary file not shown.
+22
View File
@@ -0,0 +1,22 @@
package thaumcraft.api;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
/**
*
* @author Azanor
*
* Equipped head slot items that extend this class will be able to perform most functions that
* goggles of revealing can apart from view nodes which is handled by IRevealer.
*
*/
public interface IGoggles {
/*
* If this method returns true things like block essentia contents will be shown.
*/
public boolean showIngamePopups(ItemStack itemstack, EntityLivingBase player);
}
@@ -0,0 +1,13 @@
package thaumcraft.api;
/**
* @author Azanor
* Items, armor and tools with this interface can receive the Repair enchantment.
* Repairs 1 point of durability every 10 seconds (2 for repair II)
*/
public interface IRepairable {
}
@@ -0,0 +1,17 @@
package thaumcraft.api;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
/**
* @author Azanor
* Items, armor and tools with this interface can receive the Repair enchantment.
* Repairs 1 point of durability every 10 seconds (2 for repair II)
*/
public interface IRepairableExtended extends IRepairable {
public boolean doRepair(ItemStack stack, EntityPlayer player, int enchantlevel);
}
@@ -0,0 +1,22 @@
package thaumcraft.api;
import net.minecraft.item.ItemStack;
/**
*
* @author Azanor
*
* Armor or bauble slot items that implement this interface can provide runic shielding.
* Recharging, hardening, etc. is handled internally by thaumcraft.
*
*/
public interface IRunicArmor {
/**
* returns how much charge this item can provide. This is the base shielding value - any hardening is stored and calculated internally.
*/
public int getRunicCharge(ItemStack itemstack);
}
@@ -0,0 +1,14 @@
package thaumcraft.api;
/**
*
* @author Azanor
*
* Interface used to identify scribing tool items used in research table
*
*/
public interface IScribeTools {
}
@@ -0,0 +1,20 @@
package thaumcraft.api;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import thaumcraft.api.aspects.Aspect;
/**
* @author Azanor
* ItemArmor with this interface will grant a discount to the vis cost of actions the wearer performs with casting wands.
* The amount returned is the percentage by which the cost is discounted. There is a built-int max discount of 50%, but
* individual items really shouldn't have a discount more than 5%
*/
public interface IVisDiscountGear {
int getVisDiscount(ItemStack stack, EntityPlayer player, Aspect aspect);
}
+70
View File
@@ -0,0 +1,70 @@
package thaumcraft.api;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import cpw.mods.fml.common.FMLLog;
/**
* @author Azanor
*
* This is used to gain access to the items in my mod.
* I only give some examples and it will probably still
* require a bit of work for you to get hold of everything you need.
*
*/
public class ItemApi {
public static ItemStack getItem(String itemString, int meta) {
ItemStack item = null;
try {
String itemClass = "thaumcraft.common.config.ConfigItems";
Object obj = Class.forName(itemClass).getField(itemString).get(null);
if (obj instanceof Item) {
item = new ItemStack((Item) obj,1,meta);
} else if (obj instanceof ItemStack) {
item = (ItemStack) obj;
}
} catch (Exception ex) {
FMLLog.warning("[Thaumcraft] Could not retrieve item identified by: " + itemString);
}
return item;
}
public static ItemStack getBlock(String itemString, int meta) {
ItemStack item = null;
try {
String itemClass = "thaumcraft.common.config.ConfigBlocks";
Object obj = Class.forName(itemClass).getField(itemString).get(null);
if (obj instanceof Block) {
item = new ItemStack((Block) obj,1,meta);
} else if (obj instanceof ItemStack) {
item = (ItemStack) obj;
}
} catch (Exception ex) {
FMLLog.warning("[Thaumcraft] Could not retrieve block identified by: " + itemString);
}
return item;
}
/**
*
* Some examples
*
* Casting Wands:
* itemWandCasting
*
* Resources:
* itemEssence, itemWispEssence, itemResource, itemShard, itemNugget,
* itemNuggetChicken, itemNuggetBeef, itemNuggetPork, itemTripleMeatTreat
*
* Research:
* itemResearchNotes, itemInkwell, itemThaumonomicon
*
*/
}
@@ -0,0 +1,21 @@
package thaumcraft.api;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
public class ItemRunic extends Item implements IRunicArmor {
int charge;
public ItemRunic (int charge)
{
super();
this.charge = charge;
}
@Override
public int getRunicCharge(ItemStack itemstack) {
return charge;
}
}
@@ -0,0 +1,471 @@
package thaumcraft.api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.block.Block;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.Item.ToolMaterial;
import net.minecraft.item.ItemArmor.ArmorMaterial;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.util.EnumHelper;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
import thaumcraft.api.crafting.CrucibleRecipe;
import thaumcraft.api.crafting.InfusionEnchantmentRecipe;
import thaumcraft.api.crafting.InfusionRecipe;
import thaumcraft.api.crafting.ShapedArcaneRecipe;
import thaumcraft.api.crafting.ShapelessArcaneRecipe;
import thaumcraft.api.research.IScanEventHandler;
import thaumcraft.api.research.ResearchCategories;
import thaumcraft.api.research.ResearchCategoryList;
import thaumcraft.api.research.ResearchItem;
import thaumcraft.api.research.ResearchPage;
/**
* @author Azanor
*
*
* IMPORTANT: If you are adding your own aspects to items it is a good idea to do it AFTER Thaumcraft adds its aspects, otherwise odd things may happen.
*
*/
public class ThaumcraftApi {
//Materials
public static ToolMaterial toolMatThaumium = EnumHelper.addToolMaterial("THAUMIUM", 3, 400, 7F, 2, 22);
public static ToolMaterial toolMatElemental = EnumHelper.addToolMaterial("THAUMIUM_ELEMENTAL", 3, 1500, 10F, 3, 18);
public static ArmorMaterial armorMatThaumium = EnumHelper.addArmorMaterial("THAUMIUM", 25, new int[] { 2, 6, 5, 2 }, 25);
public static ArmorMaterial armorMatSpecial = EnumHelper.addArmorMaterial("SPECIAL", 25, new int[] { 1, 3, 2, 1 }, 25);
//Enchantment references
public static int enchantFrugal;
public static int enchantPotency;
public static int enchantWandFortune;
public static int enchantHaste;
public static int enchantRepair;
//Miscellaneous
/**
* Portable Hole Block-id Blacklist.
* Simply add the block-id's of blocks you don't want the portable hole to go through.
*/
public static ArrayList<Block> portableHoleBlackList = new ArrayList<Block>();
//RESEARCH/////////////////////////////////////////
public static ArrayList<IScanEventHandler> scanEventhandlers = new ArrayList<IScanEventHandler>();
public static ArrayList<EntityTags> scanEntities = new ArrayList<EntityTags>();
public static class EntityTagsNBT {
public EntityTagsNBT(String name, Object value) {
this.name = name;
this.value = value;
}
public String name;
public Object value;
}
public static class EntityTags {
public EntityTags(String entityName, AspectList aspects, EntityTagsNBT... nbts) {
this.entityName = entityName;
this.nbts = nbts;
this.aspects = aspects;
}
public String entityName;
public EntityTagsNBT[] nbts;
public AspectList aspects;
}
/**
* not really working atm, so ignore it for now
* @param scanEventHandler
*/
public static void registerScanEventhandler(IScanEventHandler scanEventHandler) {
scanEventhandlers.add(scanEventHandler);
}
/**
* This is used to add aspects to entities which you can then scan using a thaumometer.
* Also used to calculate vis drops from mobs.
* @param entityName
* @param aspects
* @param nbt you can specify certain nbt keys and their values
* to differentiate between mobs. <br>For example the normal and wither skeleton:
* <br>ThaumcraftApi.registerEntityTag("Skeleton", (new AspectList()).add(Aspect.DEATH, 5));
* <br>ThaumcraftApi.registerEntityTag("Skeleton", (new AspectList()).add(Aspect.DEATH, 8), new NBTTagByte("SkeletonType",(byte) 1));
*/
public static void registerEntityTag(String entityName, AspectList aspects, EntityTagsNBT... nbt ) {
scanEntities.add(new EntityTags(entityName,aspects,nbt));
}
//RECIPES/////////////////////////////////////////
private static ArrayList craftingRecipes = new ArrayList();
private static HashMap<Object,ItemStack> smeltingBonus = new HashMap<Object,ItemStack>();
/**
* This method is used to determine what bonus items are generated when the infernal furnace smelts items
* @param in The input of the smelting operation. e.g. new ItemStack(Block.oreGold)
* @param out The bonus item that can be produced from the smelting operation e.g. new ItemStack(nuggetGold,0,0).
* Stacksize should be 0 unless you want to guarantee that at least 1 item is always produced.
*/
public static void addSmeltingBonus(ItemStack in, ItemStack out) {
smeltingBonus.put(
Arrays.asList(in.getItem(),in.getItemDamage()),
new ItemStack(out.getItem(),0,out.getItemDamage()));
}
/**
* This method is used to determine what bonus items are generated when the infernal furnace smelts items
* @param in The ore dictionary input of the smelting operation. e.g. "oreGold"
* @param out The bonus item that can be produced from the smelting operation e.g. new ItemStack(nuggetGold,0,0).
* Stacksize should be 0 unless you want to guarantee that at least 1 item is always produced.
*/
public static void addSmeltingBonus(String in, ItemStack out) {
smeltingBonus.put( in, new ItemStack(out.getItem(),0,out.getItemDamage()));
}
/**
* Returns the bonus item produced from a smelting operation in the infernal furnace
* @param in The input of the smelting operation. e.g. new ItemStack(oreGold)
* @return the The bonus item that can be produced
*/
@SuppressWarnings("deprecation")
public static ItemStack getSmeltingBonus(ItemStack in) {
ItemStack out = smeltingBonus.get(Arrays.asList(in.getItem(),in.getItemDamage()));
if (out == null) {
out = smeltingBonus.get(Arrays.asList(in.getItem(),OreDictionary.WILDCARD_VALUE));
}
if (out == null) {
String od = OreDictionary.getOreName( OreDictionary.getOreID(in));
out = smeltingBonus.get(od);
}
return out;
}
public static List getCraftingRecipes() {
return craftingRecipes;
}
/**
* @param research the research key required for this recipe to work. Leave blank if it will work without research
* @param result the recipe output
* @param aspects the vis cost per aspect.
* @param recipe The recipe. Format is exactly the same as vanilla recipes. Input itemstacks are NBT sensitive.
*/
public static ShapedArcaneRecipe addArcaneCraftingRecipe(String research, ItemStack result, AspectList aspects, Object ... recipe)
{
ShapedArcaneRecipe r= new ShapedArcaneRecipe(research, result, aspects, recipe);
craftingRecipes.add(r);
return r;
}
/**
* @param research the research key required for this recipe to work. Leave blank if it will work without research
* @param result the recipe output
* @param aspects the vis cost per aspect
* @param recipe The recipe. Format is exactly the same as vanilla shapeless recipes. Input itemstacks are NBT sensitive.
*/
public static ShapelessArcaneRecipe addShapelessArcaneCraftingRecipe(String research, ItemStack result, AspectList aspects, Object ... recipe)
{
ShapelessArcaneRecipe r = new ShapelessArcaneRecipe(research, result, aspects, recipe);
craftingRecipes.add(r);
return r;
}
/**
* @param research the research key required for this recipe to work. Leave blank if it will work without research
* @param result the recipe output. It can either be an itemstack or an nbt compound tag that will be added to the central item
* @param instability a number that represents the N in 1000 chance for the infusion altar to spawn an
* instability effect each second while the crafting is in progress
* @param aspects the essentia cost per aspect.
* @param aspects input the central item to be infused
* @param recipe An array of items required to craft this. Input itemstacks are NBT sensitive.
* Infusion crafting components are automatically "fuzzy" and the oredict will be checked for possible matches.
*
*/
public static InfusionRecipe addInfusionCraftingRecipe(String research, Object result, int instability, AspectList aspects, ItemStack input,ItemStack[] recipe)
{
if (!(result instanceof ItemStack || result instanceof Object[])) return null;
InfusionRecipe r= new InfusionRecipe(research, result, instability, aspects, input, recipe);
craftingRecipes.add(r);
return r;
}
/**
* @param research the research key required for this recipe to work. Leave blank if it will work without research
* @param enchantment the enchantment that will be applied to the item
* @param instability a number that represents the N in 1000 chance for the infusion altar to spawn an
* instability effect each second while the crafting is in progress
* @param aspects the essentia cost per aspect.
* @param recipe An array of items required to craft this. Input itemstacks are NBT sensitive.
* Infusion crafting components are automatically "fuzzy" and the oredict will be checked for possible matches.
*
*/
public static InfusionEnchantmentRecipe addInfusionEnchantmentRecipe(String research, Enchantment enchantment, int instability, AspectList aspects, ItemStack[] recipe)
{
InfusionEnchantmentRecipe r= new InfusionEnchantmentRecipe(research, enchantment, instability, aspects, recipe);
craftingRecipes.add(r);
return r;
}
/**
* @param stack the recipe result
* @return the recipe
*/
public static InfusionRecipe getInfusionRecipe(ItemStack res) {
for (Object r:getCraftingRecipes()) {
if (r instanceof InfusionRecipe) {
if (((InfusionRecipe)r).getRecipeOutput() instanceof ItemStack) {
if (((ItemStack) ((InfusionRecipe)r).getRecipeOutput()).isItemEqual(res))
return (InfusionRecipe)r;
}
}
}
return null;
}
/**
* @param key the research key required for this recipe to work.
* @param result the output result
* @param catalyst an itemstack of the catalyst or a string if it is an ore dictionary item
* @param cost the vis cost
* @param tags the aspects required to craft this
*/
public static CrucibleRecipe addCrucibleRecipe(String key, ItemStack result, Object catalyst, AspectList tags) {
CrucibleRecipe rc = new CrucibleRecipe(key, result, catalyst, tags);
getCraftingRecipes().add(rc);
return rc;
}
/**
* @param stack the recipe result
* @return the recipe
*/
public static CrucibleRecipe getCrucibleRecipe(ItemStack stack) {
for (Object r:getCraftingRecipes()) {
if (r instanceof CrucibleRecipe) {
if (((CrucibleRecipe)r).getRecipeOutput().isItemEqual(stack))
return (CrucibleRecipe)r;
}
}
return null;
}
/**
* Used by the thaumonomicon drilldown feature.
* @param stack the item
* @return the thaumcraft recipe key that produces that item.
*/
private static HashMap<int[],Object[]> keyCache = new HashMap<int[],Object[]>();
@SuppressWarnings("null")
public static Object[] getCraftingRecipeKey(EntityPlayer player, ItemStack stack) {
int[] key = new int[] {Item.getIdFromItem(stack.getItem()),stack.getItemDamage()};
if (keyCache.containsKey(key)) {
if (keyCache.get(key) == null) return null;
if (ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), (String)(keyCache.get(key))[0]))
return keyCache.get(key);
else
return null;
}
for (ResearchCategoryList rcl:ResearchCategories.researchCategories.values()) {
for (ResearchItem ri:rcl.research.values()) {
if (ri.getPages() == null) continue;
for (int a = 0;a<ri.getPages().length;a++) {
ResearchPage page = ri.getPages()[a];
if (page.recipeOutput != null && stack != null && page.recipeOutput.isItemEqual(stack)) {
keyCache.put(key,new Object[] {ri.key,a});
if (ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), ri.key))
return new Object[] {ri.key,a};
else
return null;
}
}
}
}
keyCache.put(key,null);
return null;
}
//ASPECTS////////////////////////////////////////
public static ConcurrentHashMap<List,AspectList> objectTags = new ConcurrentHashMap<List,AspectList>();
/**
* Checks to see if the passed item/block already has aspects associated with it.
* @param id
* @param meta
* @return
*/
public static boolean exists(Item item, int meta) {
AspectList tmp = ThaumcraftApi.objectTags.get(Arrays.asList(item,meta));
if (tmp == null) {
tmp = ThaumcraftApi.objectTags.get(Arrays.asList(item,OreDictionary.WILDCARD_VALUE));
if (meta == OreDictionary.WILDCARD_VALUE && tmp == null) {
int index = 0;
do {
tmp = ThaumcraftApi.objectTags.get(Arrays.asList(item,index));
index++;
} while (index<16 && tmp == null);
}
if (tmp == null) return false;
}
return true;
}
/**
* Used to assign apsects to the given item/block. Here is an example of the declaration for cobblestone:<p>
* <i>ThaumcraftApi.registerObjectTag(new ItemStack(Blocks.cobblestone), (new AspectList()).add(Aspect.ENTROPY, 1).add(Aspect.EARTH, 1));</i>
* @param item the item passed. Pass OreDictionary.WILDCARD_VALUE if all damage values of this item/block should have the same aspects
* @param aspects A ObjectTags object of the associated aspects
*/
public static void registerObjectTag(ItemStack item, AspectList aspects) {
if (aspects == null) aspects = new AspectList();
try {
objectTags.put(Arrays.asList(item.getItem(),item.getItemDamage()), aspects);
} catch (Exception e) {}
}
/**
* Used to assign apsects to the given item/block. Here is an example of the declaration for cobblestone:<p>
* <i>ThaumcraftApi.registerObjectTag(new ItemStack(Blocks.cobblestone), new int[]{0,1}, (new AspectList()).add(Aspect.ENTROPY, 1).add(Aspect.EARTH, 1));</i>
* @param item
* @param meta A range of meta values if you wish to lump several item meta's together as being the "same" item (i.e. stair orientations)
* @param aspects A ObjectTags object of the associated aspects
*/
public static void registerObjectTag(ItemStack item, int[] meta, AspectList aspects) {
if (aspects == null) aspects = new AspectList();
try {
objectTags.put(Arrays.asList(item.getItem(),meta), aspects);
} catch (Exception e) {}
}
/**
* Used to assign apsects to the given ore dictionary item.
* @param oreDict the ore dictionary name
* @param aspects A ObjectTags object of the associated aspects
*/
public static void registerObjectTag(String oreDict, AspectList aspects) {
if (aspects == null) aspects = new AspectList();
ArrayList<ItemStack> ores = OreDictionary.getOres(oreDict);
if (ores != null && ores.size()>0) {
for (ItemStack ore:ores) {
try {
objectTags.put(Arrays.asList(ore.getItem(), ore.getItemDamage()), aspects);
} catch (Exception e) {}
}
}
}
/**
* Used to assign aspects to the given item/block.
* Attempts to automatically generate aspect tags by checking registered recipes.
* Here is an example of the declaration for pistons:<p>
* <i>ThaumcraftApi.registerComplexObjectTag(new ItemStack(Blocks.cobblestone), (new AspectList()).add(Aspect.MECHANISM, 2).add(Aspect.MOTION, 4));</i>
* @param item, pass OreDictionary.WILDCARD_VALUE to meta if all damage values of this item/block should have the same aspects
* @param aspects A ObjectTags object of the associated aspects
*/
public static void registerComplexObjectTag(ItemStack item, AspectList aspects ) {
if (!exists(item.getItem(),item.getItemDamage())) {
AspectList tmp = ThaumcraftApiHelper.generateTags(item.getItem(), item.getItemDamage());
if (tmp != null && tmp.size()>0) {
for(Aspect tag:tmp.getAspects()) {
aspects.add(tag, tmp.getAmount(tag));
}
}
registerObjectTag(item,aspects);
} else {
AspectList tmp = ThaumcraftApiHelper.getObjectAspects(item);
for(Aspect tag:aspects.getAspects()) {
tmp.merge(tag, tmp.getAmount(tag));
}
registerObjectTag(item,tmp);
}
}
//CROPS //////////////////////////////////////////////////////////////////////////////////////////
/**
* To define mod crops you need to use FMLInterModComms in your @Mod.Init method.
* There are two 'types' of crops you can add. Standard crops and clickable crops.
*
* Standard crops work like normal vanilla crops - they grow until a certain metadata
* value is reached and you harvest them by destroying the block and collecting the blocks.
* You need to create and ItemStack that tells the golem what block id and metadata represents
* the crop when fully grown. Sending a metadata of [OreDictionary.WILDCARD_VALUE] will mean the metadata won't get
* checked.
* Example for vanilla wheat:
* FMLInterModComms.sendMessage("Thaumcraft", "harvestStandardCrop", new ItemStack(Block.crops,1,7));
*
* Clickable crops are crops that you right click to gather their bounty instead of destroying them.
* As for standard crops, you need to create and ItemStack that tells the golem what block id
* and metadata represents the crop when fully grown. The golem will trigger the blocks onBlockActivated method.
* Sending a metadata of [OreDictionary.WILDCARD_VALUE] will mean the metadata won't get checked.
* Example (this will technically do nothing since clicking wheat does nothing, but you get the idea):
* FMLInterModComms.sendMessage("Thaumcraft", "harvestClickableCrop", new ItemStack(Block.crops,1,7));
*
* Stacked crops (like reeds) are crops that you wish the bottom block should remain after harvesting.
* As for standard crops, you need to create and ItemStack that tells the golem what block id
* and metadata represents the crop when fully grown. Sending a metadata of [OreDictionary.WILDCARD_VALUE] will mean the actualy md won't get
* checked. If it has the order upgrade it will only harvest if the crop is more than one block high.
* Example:
* FMLInterModComms.sendMessage("Thaumcraft", "harvestStackedCrop", new ItemStack(Block.reed,1,7));
*/
//NATIVE CLUSTERS //////////////////////////////////////////////////////////////////////////////////
/**
* You can define certain ores that will have a chance to produce native clusters via FMLInterModComms
* in your @Mod.Init method using the "nativeCluster" string message.
* The format should be:
* "[ore item/block id],[ore item/block metadata],[cluster item/block id],[cluster item/block metadata],[chance modifier float]"
*
* NOTE: The chance modifier is a multiplier applied to the default chance for that cluster to be produced (default 27.5% for a pickaxe of the core)
*
* Example for vanilla iron ore to produce one of my own native iron clusters (assuming default id's) at double the default chance:
* FMLInterModComms.sendMessage("Thaumcraft", "nativeCluster","15,0,25016,16,2.0");
*/
//LAMP OF GROWTH BLACKLIST ///////////////////////////////////////////////////////////////////////////
/**
* You can blacklist crops that should not be effected by the Lamp of Growth via FMLInterModComms
* in your @Mod.Init method using the "lampBlacklist" itemstack message.
* Sending a metadata of [OreDictionary.WILDCARD_VALUE] will mean the metadata won't get checked.
* Example for vanilla wheat:
* FMLInterModComms.sendMessage("Thaumcraft", "lampBlacklist", new ItemStack(Block.crops,1,OreDictionary.WILDCARD_VALUE));
*/
//DIMENSION BLACKLIST ///////////////////////////////////////////////////////////////////////////
/**
* You can blacklist a dimension to not spawn certain thaumcraft features
* in your @Mod.Init method using the "dimensionBlacklist" string message in the format "[dimension]:[level]"
* The level values are as follows:
* [0] stop all tc spawning and generation
* [1] allow ore and node generation
* [2] allow mob spawning
* [3] allow ore and node gen + mob spawning
* Example:
* FMLInterModComms.sendMessage("Thaumcraft", "dimensionBlacklist", "15:1");
*/
//BIOME BLACKLIST ///////////////////////////////////////////////////////////////////////////
/**
* You can blacklist a biome to not spawn certain thaumcraft features
* in your @Mod.Init method using the "biomeBlacklist" string message in the format "[biome id]:[level]"
* The level values are as follows:
* [0] stop all tc spawning and generation
* [1] allow ore and node generation
* [2] allow mob spawning
* [3] allow ore and node gen + mob spawning
* Example:
* FMLInterModComms.sendMessage("Thaumcraft", "biomeBlacklist", "180:2");
*/
}
@@ -0,0 +1,268 @@
package thaumcraft.api;
import java.lang.reflect.Method;
import java.util.HashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
import thaumcraft.api.aspects.IEssentiaTransport;
import cpw.mods.fml.common.FMLLog;
public class ThaumcraftApiHelper {
@SuppressWarnings("null")
public static AspectList cullTags(AspectList temp) {
AspectList temp2 = new AspectList();
for (Aspect tag:temp.getAspects()) {
if (tag != null)
temp2.add(tag, temp.getAmount(tag));
}
while (temp2 != null && temp2.size()>10) {
Aspect lowest = null;
int low = Integer.MAX_VALUE;
for (Aspect tag:temp2.getAspects()) {
if (tag == null) continue;
if (temp2.getAmount(tag)<low) {
low = temp2.getAmount(tag);
lowest = tag;
}
}
temp2.aspects.remove(lowest);
}
return temp2;
}
public static boolean areItemsEqual(ItemStack s1,ItemStack s2)
{
if (s1.isItemStackDamageable() && s2.isItemStackDamageable())
{
return s1.getItem() == s2.getItem();
} else
return s1.getItem() == s2.getItem() && s1.getItemDamage() == s2.getItemDamage();
}
static Method isResearchComplete;
static Method getObjectTags;
static Method getBonusTags;
static Method generateTags;
public static boolean isResearchComplete(String username, String researchkey) {
boolean ot = false;
try {
if(isResearchComplete == null) {
Class fake = Class.forName("thaumcraft.common.lib.research.ResearchManager");
isResearchComplete = fake.getMethod("isResearchComplete", String.class, String.class);
}
ot = (Boolean) isResearchComplete.invoke(null, username, researchkey);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.research.ResearchManager method isResearchComplete");
}
return ot;
}
public static ItemStack getStackInRowAndColumn(Object instance, int row, int column) {
ItemStack ot = null;
try {
Class fake = Class.forName("thaumcraft.common.tiles.TileMagicWorkbench");
Method getStackInRowAndColumn = fake.getMethod("getStackInRowAndColumn", int.class, int.class);
ot = (ItemStack) getStackInRowAndColumn.invoke(instance, row, column);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.tiles.TileMagicWorkbench method getStackInRowAndColumn");
}
return ot;
}
public static AspectList getObjectAspects(ItemStack is) {
AspectList ot = null;
try {
if(getObjectTags == null) {
Class fake = Class.forName("thaumcraft.common.lib.crafting.ThaumcraftCraftingManager");
getObjectTags = fake.getMethod("getObjectTags", ItemStack.class);
}
ot = (AspectList) getObjectTags.invoke(null, is);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.crafting.ThaumcraftCraftingManager method getObjectTags");
}
return ot;
}
public static AspectList getBonusObjectTags(ItemStack is,AspectList ot) {
try {
if(getBonusTags == null) {
Class fake = Class.forName("thaumcraft.common.lib.crafting.ThaumcraftCraftingManager");
getBonusTags = fake.getMethod("getBonusTags", ItemStack.class, AspectList.class);
}
ot = (AspectList) getBonusTags.invoke(null, is, ot);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.crafting.ThaumcraftCraftingManager method getBonusTags");
}
return ot;
}
public static AspectList generateTags(Item item, int meta) {
try {
if(generateTags == null) {
Class fake = Class.forName("thaumcraft.common.lib.crafting.ThaumcraftCraftingManager");
generateTags = fake.getMethod("generateTags", Item.class, int.class);
}
return (AspectList) generateTags.invoke(null, item, meta);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.crafting.ThaumcraftCraftingManager method generateTags");
}
return null;
}
public static boolean containsMatch(boolean strict, ItemStack[] inputs, ItemStack... targets)
{
for (ItemStack input : inputs)
{
for (ItemStack target : targets)
{
if (itemMatches(target, input, strict))
{
return true;
}
}
}
return false;
}
public static boolean itemMatches(ItemStack target, ItemStack input, boolean strict)
{
if (input == null && target != null || input != null && target == null)
{
return false;
}
return (target.getItem() == input.getItem() && ((target.getItemDamage() == OreDictionary.WILDCARD_VALUE && !strict) || target.getItemDamage() == input.getItemDamage()));
}
public static TileEntity getConnectableTile(World world, int x, int y, int z, ForgeDirection face) {
TileEntity te = world.getTileEntity(x+face.offsetX, y+face.offsetY, z+face.offsetZ);
if (te instanceof IEssentiaTransport && ((IEssentiaTransport)te).isConnectable(face.getOpposite()))
return te;
else
return null;
}
public static TileEntity getConnectableTile(IBlockAccess world, int x, int y, int z, ForgeDirection face) {
TileEntity te = world.getTileEntity(x+face.offsetX, y+face.offsetY, z+face.offsetZ);
if (te instanceof IEssentiaTransport && ((IEssentiaTransport)te).isConnectable(face.getOpposite()))
return te;
else
return null;
}
private static HashMap<Integer, AspectList> allAspects= new HashMap<Integer, AspectList>();
private static HashMap<Integer, AspectList> allCompoundAspects= new HashMap<Integer, AspectList>();
public static AspectList getAllAspects(int amount) {
if (allAspects.get(amount) == null) {
AspectList al = new AspectList();
for (Aspect aspect:Aspect.aspects.values()) {
al.add(aspect, amount);
}
allAspects.put(amount, al);
}
return allAspects.get(amount);
}
public static AspectList getAllCompoundAspects(int amount) {
if (allCompoundAspects.get(amount) == null) {
AspectList al = new AspectList();
for (Aspect aspect:Aspect.getCompoundAspects()) {
al.add(aspect, amount);
}
allCompoundAspects.put(amount, al);
}
return allCompoundAspects.get(amount);
}
static Method consumeVisFromWand;
/**
* Use to subtract vis from a wand for most operations
* Wands store vis differently so "real" vis costs need to be multiplied by 100 before calling this method
* @param wand the wand itemstack
* @param player the player using the wand
* @param cost the cost of the operation.
* @param doit actually subtract the vis from the wand if true - if false just simulate the result
* @param crafting is this a crafting operation or not - if
* false then things like frugal and potency will apply to the costs
* @return was the vis successfully subtracted
*/
public static boolean consumeVisFromWand(ItemStack wand, EntityPlayer player,
AspectList cost, boolean doit, boolean crafting) {
boolean ot = false;
try {
if(consumeVisFromWand == null) {
Class fake = Class.forName("thaumcraft.common.items.wands.ItemWandCasting");
consumeVisFromWand = fake.getMethod("consumeAllVis",
ItemStack.class, EntityPlayer.class, AspectList.class, boolean.class, boolean.class);
}
ot = (Boolean) consumeVisFromWand.invoke(
consumeVisFromWand.getDeclaringClass().cast(wand.getItem()), wand, player, cost, doit, crafting);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.items.wands.ItemWandCasting method consumeAllVis");
}
return ot;
}
static Method consumeVisFromWandCrafting;
/**
* Subtract vis for use by a crafting mechanic. Costs are calculated slightly
* differently and things like the frugal enchant is ignored
* Must NOT be multiplied by 100 - send the actual vis cost
* @param wand the wand itemstack
* @param player the player using the wand
* @param cost the cost of the operation.
* @param doit actually subtract the vis from the wand if true - if false just simulate the result
* @return was the vis successfully subtracted
*/
public static boolean consumeVisFromWandCrafting(ItemStack wand, EntityPlayer player,
AspectList cost, boolean doit) {
boolean ot = false;
try {
if(consumeVisFromWandCrafting == null) {
Class fake = Class.forName("thaumcraft.common.items.wands.ItemWandCasting");
consumeVisFromWandCrafting = fake.getMethod("consumeAllVisCrafting",
ItemStack.class, EntityPlayer.class, AspectList.class, boolean.class);
}
ot = (Boolean) consumeVisFromWandCrafting.invoke(
consumeVisFromWandCrafting.getDeclaringClass().cast(wand.getItem()), wand, player, cost, doit);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.items.wands.ItemWandCasting method consumeAllVisCrafting");
}
return ot;
}
static Method consumeVisFromInventory;
/**
* Subtract vis from a wand the player is carrying. Works like consumeVisFromWand in that actual vis
* costs should be multiplied by 100. The costs are handled like crafting however and things like
* frugal don't effect them
* @param player the player using the wand
* @param cost the cost of the operation.
* @return was the vis successfully subtracted
*/
public static boolean consumeVisFromInventory(EntityPlayer player, AspectList cost) {
boolean ot = false;
try {
if(consumeVisFromInventory == null) {
Class fake = Class.forName("thaumcraft.common.items.wands.WandManager");
consumeVisFromInventory = fake.getMethod("consumeVisFromInventory",
EntityPlayer.class, AspectList.class);
}
ot = (Boolean) consumeVisFromInventory.invoke(null, player, cost);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.items.wands.WandManager method consumeVisFromInventory");
}
return ot;
}
}
@@ -0,0 +1,199 @@
package thaumcraft.api.aspects;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import org.apache.commons.lang3.text.WordUtils;
public class Aspect {
String tag;
Aspect[] components;
int color;
private String chatcolor;
ResourceLocation image;
int blend;
/**
* Use this constructor to register your own aspects.
* @param tag the key that will be used to reference this aspect, as well as its latin display name
* @param color color to display the tag in
* @param components the aspects this one is formed from
* @param image ResourceLocation pointing to a 32x32 icon of the aspect
* @param blend GL11 blendmode (1 or 771). Used for rendering nodes. Default is 1
*/
public Aspect(String tag, int color, Aspect[] components, ResourceLocation image, int blend) {
if (aspects.containsKey(tag)) throw new IllegalArgumentException(tag+" already registered!");
this.tag = tag;
this.components = components;
this.color = color;
this.image = image;
this.blend = blend;
aspects.put(tag, this);
}
/**
* Shortcut constructor I use for the default aspects - you shouldn't be using this.
*/
public Aspect(String tag, int color, Aspect[] components) {
this(tag,color,components,new ResourceLocation("thaumcraft","textures/aspects/"+tag.toLowerCase()+".png"),1);
}
/**
* Shortcut constructor I use for the default aspects - you shouldn't be using this.
*/
public Aspect(String tag, int color, Aspect[] components, int blend) {
this(tag,color,components,new ResourceLocation("thaumcraft","textures/aspects/"+tag.toLowerCase()+".png"),blend);
}
/**
* Shortcut constructor I use for the primal aspects -
* you shouldn't use this as making your own primal aspects will break all the things.
*/
public Aspect(String tag, int color, String chatcolor, int blend) {
this(tag,color,(Aspect[])null, blend);
this.setChatcolor(chatcolor);
}
public int getColor() {
return color;
}
public String getName() {
return WordUtils.capitalizeFully(tag);
}
public String getLocalizedDescription() {
return StatCollector.translateToLocal("tc.aspect."+tag);
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public Aspect[] getComponents() {
return components;
}
public void setComponents(Aspect[] components) {
this.components = components;
}
public ResourceLocation getImage() {
return image;
}
public static Aspect getAspect(String tag) {
return aspects.get(tag);
}
public int getBlend() {
return blend;
}
public void setBlend(int blend) {
this.blend = blend;
}
public boolean isPrimal() {
return getComponents() == null || getComponents().length != 2;
}
///////////////////////////////
public static ArrayList<Aspect> getPrimalAspects() {
ArrayList<Aspect> primals = new ArrayList<Aspect>();
Collection<Aspect> pa = aspects.values();
for (Aspect aspect:pa) {
if (aspect.isPrimal()) primals.add(aspect);
}
return primals;
}
public static ArrayList<Aspect> getCompoundAspects() {
ArrayList<Aspect> compounds = new ArrayList<Aspect>();
Collection<Aspect> pa = aspects.values();
for (Aspect aspect:pa) {
if (!aspect.isPrimal()) compounds.add(aspect);
}
return compounds;
}
public String getChatcolor() {
return chatcolor;
}
public void setChatcolor(String chatcolor) {
this.chatcolor = chatcolor;
}
///////////////////////////////
public static LinkedHashMap<String,Aspect> aspects = new LinkedHashMap<String,Aspect>();
//PRIMAL
public static final Aspect AIR = new Aspect("aer",0xffff7e,"e",1);
public static final Aspect EARTH = new Aspect("terra",0x56c000,"2",1);
public static final Aspect FIRE = new Aspect("ignis",0xff5a01,"c",1);
public static final Aspect WATER = new Aspect("aqua",0x3cd4fc,"3",1);
public static final Aspect ORDER = new Aspect("ordo",0xd5d4ec,"7",1);
public static final Aspect ENTROPY = new Aspect("perditio",0x404040,"8",771);
//SECONDARY
public static final Aspect VOID = new Aspect("vacuos",0x888888, new Aspect[] {AIR, ENTROPY},771);
public static final Aspect LIGHT = new Aspect("lux",0xfff663, new Aspect[] {AIR, FIRE});
public static final Aspect WEATHER = new Aspect("tempestas",0xFFFFFF, new Aspect[] {AIR, WATER});
public static final Aspect MOTION = new Aspect("motus",0xcdccf4, new Aspect[] {AIR, ORDER});
public static final Aspect COLD = new Aspect("gelum",0xe1ffff, new Aspect[] {FIRE, ENTROPY});
public static final Aspect CRYSTAL = new Aspect("vitreus",0x80ffff, new Aspect[] {EARTH, ORDER});
public static final Aspect LIFE = new Aspect("victus",0xde0005, new Aspect[] {WATER, EARTH});
public static final Aspect POISON = new Aspect("venenum",0x89f000, new Aspect[] {WATER, ENTROPY});
public static final Aspect ENERGY = new Aspect("potentia",0xc0ffff, new Aspect[] {ORDER, FIRE});
public static final Aspect EXCHANGE = new Aspect("permutatio",0x578357, new Aspect[] {ENTROPY, ORDER});
// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {AIR, EARTH});
// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {FIRE, EARTH});
// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {FIRE, WATER});
// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {ORDER, WATER});
// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {EARTH, ENTROPY});
//TERTIARY
public static final Aspect METAL = new Aspect("metallum",0xb5b5cd, new Aspect[] {EARTH, CRYSTAL});
public static final Aspect DEATH = new Aspect("mortuus",0x887788, new Aspect[] {LIFE, ENTROPY});
public static final Aspect FLIGHT = new Aspect("volatus",0xe7e7d7, new Aspect[] {AIR, MOTION});
public static final Aspect DARKNESS = new Aspect("tenebrae",0x222222, new Aspect[] {VOID, LIGHT});
public static final Aspect SOUL = new Aspect("spiritus",0xebebfb, new Aspect[] {LIFE, DEATH});
public static final Aspect HEAL = new Aspect("sano",0xff2f34, new Aspect[] {LIFE, ORDER});
public static final Aspect TRAVEL = new Aspect("iter",0xe0585b, new Aspect[] {MOTION, EARTH});
public static final Aspect ELDRITCH = new Aspect("alienis",0x805080, new Aspect[] {VOID, DARKNESS});
public static final Aspect MAGIC = new Aspect("praecantatio",0x9700c0, new Aspect[] {VOID, ENERGY});
public static final Aspect AURA = new Aspect("auram",0xffc0ff, new Aspect[] {MAGIC, AIR});
public static final Aspect TAINT = new Aspect("vitium",0x800080, new Aspect[] {MAGIC, ENTROPY});
public static final Aspect SLIME = new Aspect("limus",0x01f800, new Aspect[] {LIFE, WATER});
public static final Aspect PLANT = new Aspect("herba",0x01ac00, new Aspect[] {LIFE, EARTH});
public static final Aspect TREE = new Aspect("arbor",0x876531, new Aspect[] {AIR, PLANT});
public static final Aspect BEAST = new Aspect("bestia",0x9f6409, new Aspect[] {MOTION, LIFE});
public static final Aspect FLESH = new Aspect("corpus",0xee478d, new Aspect[] {DEATH, BEAST});
public static final Aspect UNDEAD = new Aspect("exanimis",0x3a4000, new Aspect[] {MOTION, DEATH});
public static final Aspect MIND = new Aspect("cognitio",0xffc2b3, new Aspect[] {EARTH, SOUL});
public static final Aspect SENSES = new Aspect("sensus",0x0fd9ff, new Aspect[] {AIR, SOUL});
public static final Aspect MAN = new Aspect("humanus",0xffd7c0, new Aspect[] {BEAST, MIND});
public static final Aspect CROP = new Aspect("messis",0xe1b371, new Aspect[] {PLANT, MAN});
public static final Aspect MINE = new Aspect("perfodio",0xdcd2d8, new Aspect[] {MAN, EARTH});
public static final Aspect TOOL = new Aspect("instrumentum",0x4040ee, new Aspect[] {MAN, ORDER});
public static final Aspect HARVEST = new Aspect("meto",0xeead82, new Aspect[] {CROP, TOOL});
public static final Aspect WEAPON = new Aspect("telum",0xc05050, new Aspect[] {TOOL, ENTROPY});
public static final Aspect ARMOR = new Aspect("tutamen",0x00c0c0, new Aspect[] {TOOL, EARTH});
public static final Aspect HUNGER = new Aspect("fames",0x9a0305, new Aspect[] {LIFE, VOID});
public static final Aspect GREED = new Aspect("lucrum",0xe6be44, new Aspect[] {MAN, HUNGER});
public static final Aspect CRAFT = new Aspect("fabrico",0x809d80, new Aspect[] {MAN, TOOL});
public static final Aspect CLOTH = new Aspect("pannus",0xeaeac2, new Aspect[] {TOOL, BEAST});
public static final Aspect MECHANISM = new Aspect("machina",0x8080a0, new Aspect[] {MOTION, TOOL});
public static final Aspect TRAP = new Aspect("vinculum",0x9a8080, new Aspect[] {MOTION, ENTROPY});
}
@@ -0,0 +1,255 @@
package thaumcraft.api.aspects;
import java.io.Serializable;
import java.util.LinkedHashMap;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import thaumcraft.api.ThaumcraftApiHelper;
public class AspectList implements Serializable {
public LinkedHashMap<Aspect,Integer> aspects = new LinkedHashMap<Aspect,Integer>();//aspects associated with this object
/**
* this creates a new aspect list with preloaded values based off the aspects of the given item.
* @param the itemstack of the given item
*/
public AspectList(ItemStack stack) {
try {
AspectList temp = ThaumcraftApiHelper.getObjectAspects(stack);
if (temp != null)
for (Aspect tag:temp.getAspects()) {
add(tag,temp.getAmount(tag));
}
} catch (Exception e) {}
}
public AspectList() {
}
public AspectList copy() {
AspectList out = new AspectList();
for (Aspect a:this.getAspects())
out.add(a, this.getAmount(a));
return out;
}
/**
* @return the amount of different aspects in this collection
*/
public int size() {
return aspects.size();
}
/**
* @return the amount of total vis in this collection
*/
public int visSize() {
int q = 0;
for (Aspect as:aspects.keySet()) {
q += this.getAmount(as);
}
return q;
}
/**
* @return an array of all the aspects in this collection
*/
public Aspect[] getAspects() {
Aspect[] q = new Aspect[1];
return aspects.keySet().toArray(q);
}
/**
* @return an array of all the aspects in this collection
*/
public Aspect[] getPrimalAspects() {
AspectList t = new AspectList();
for (Aspect as:aspects.keySet()) {
if (as.isPrimal()) {
t.add(as,1);
}
}
Aspect[] q = new Aspect[1];
return t.aspects.keySet().toArray(q);
}
/**
* @return an array of all the aspects in this collection sorted by name
*/
public Aspect[] getAspectsSorted() {
try {
Aspect[] out = aspects.keySet().toArray(new Aspect[1]);
boolean change = false;
do {
change = false;
for(int a = 0;a<out.length-1;a++) {
Aspect e1 = out[a];
Aspect e2 = out[a+1];
if (e1 != null && e2 != null && e1.getTag().compareTo(e2.getTag())>0) {
out[a] = e2;
out[a+1] = e1;
change = true;
break;
}
}
} while (change == true);
return out;
} catch (Exception e) {
return this.getAspects();
}
}
/**
* @return an array of all the aspects in this collection sorted by amount
*/
public Aspect[] getAspectsSortedAmount() {
try {
Aspect[] out = aspects.keySet().toArray(new Aspect[1]);
boolean change = false;
do {
change = false;
for(int a = 0;a<out.length-1;a++) {
int e1 = getAmount(out[a]);
int e2 = getAmount(out[a+1]);
if (e1>0 && e2>0 && e2>e1) {
Aspect ea = out[a];
Aspect eb = out[a+1];
out[a] = eb;
out[a+1] = ea;
change = true;
break;
}
}
} while (change == true);
return out;
} catch (Exception e) {
return this.getAspects();
}
}
/**
* @param key
* @return the amount associated with the given aspect in this collection
*/
public int getAmount(Aspect key) {
return aspects.get(key) == null?0:aspects.get(key);
}
/**
* Reduces the amount of an aspect in this collection by the given amount.
* @param key
* @param amount
* @return
*/
public boolean reduce(Aspect key, int amount) {
if (getAmount(key) >= amount) {
int am = getAmount(key)-amount;
aspects.put(key, am);
return true;
}
return false;
}
/**
* Reduces the amount of an aspect in this collection by the given amount.
* If reduced to 0 or less the aspect will be removed completely.
* @param key
* @param amount
* @return
*/
public AspectList remove(Aspect key, int amount) {
int am = getAmount(key)-amount;
if (am <= 0) aspects.remove(key); else
this.aspects.put(key, am);
return this;
}
/**
* Simply removes the aspect from the list
* @param key
* @param amount
* @return
*/
public AspectList remove(Aspect key) {
aspects.remove(key);
return this;
}
/**
* Adds this aspect and amount to the collection.
* If the aspect exists then its value will be increased by the given amount.
* @param aspect
* @param amount
* @return
*/
public AspectList add(Aspect aspect, int amount) {
if (this.aspects.containsKey(aspect)) {
int oldamount = this.aspects.get(aspect);
amount += oldamount;
}
this.aspects.put( aspect, amount );
return this;
}
/**
* Adds this aspect and amount to the collection.
* If the aspect exists then only the highest of the old or new amount will be used.
* @param aspect
* @param amount
* @return
*/
public AspectList merge(Aspect aspect, int amount) {
if (this.aspects.containsKey(aspect)) {
int oldamount = this.aspects.get(aspect);
if (amount<oldamount) amount = oldamount;
}
this.aspects.put( aspect, amount );
return this;
}
/**
* Reads the list of aspects from nbt
* @param nbttagcompound
* @return
*/
public void readFromNBT(NBTTagCompound nbttagcompound)
{
aspects.clear();
NBTTagList tlist = nbttagcompound.getTagList("Aspects",(byte)10);
for (int j = 0; j < tlist.tagCount(); j++) {
NBTTagCompound rs = tlist.getCompoundTagAt(j);
if (rs.hasKey("key")) {
add( Aspect.getAspect(rs.getString("key")),
rs.getInteger("amount"));
}
}
}
/**
* Writes the list of aspects to nbt
* @param nbttagcompound
* @return
*/
public void writeToNBT(NBTTagCompound nbttagcompound)
{
NBTTagList tlist = new NBTTagList();
nbttagcompound.setTag("Aspects", tlist);
for (Aspect aspect : getAspects())
if (aspect != null) {
NBTTagCompound f = new NBTTagCompound();
f.setString("key", aspect.getTag());
f.setInteger("amount", getAmount(aspect));
tlist.appendTag(f);
}
}
}
@@ -0,0 +1,57 @@
package thaumcraft.api.aspects;
import java.lang.reflect.Method;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import cpw.mods.fml.common.FMLLog;
public class AspectSourceHelper {
static Method drainEssentia;
static Method findEssentia;
/**
* This method is what is used to drain essentia from jars and other sources for things like
* infusion crafting or powering the arcane furnace. A record of possible sources are kept track of
* and refreshed as needed around the calling tile entity. This also renders the essentia trail particles.
* Only 1 essentia is drained at a time
* @param tile the tile entity that is draining the essentia
* @param aspect the aspect that you are looking for
* @param direction the direction from which you wish to drain. Forgedirection.Unknown simply seeks in all directions.
* @param range how many blocks you wish to search for essentia sources.
* @return boolean returns true if essentia was found and removed from a source.
*/
public static boolean drainEssentia(TileEntity tile, Aspect aspect, ForgeDirection direction, int range) {
try {
if(drainEssentia == null) {
Class fake = Class.forName("thaumcraft.common.lib.events.EssentiaHandler");
drainEssentia = fake.getMethod("drainEssentia", TileEntity.class, Aspect.class, ForgeDirection.class, int.class);
}
return (Boolean) drainEssentia.invoke(null, tile, aspect, direction, range);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.events.EssentiaHandler method drainEssentia");
}
return false;
}
/**
* This method returns if there is any essentia of the passed type that can be drained. It in no way checks how
* much there is, only if an essentia container nearby contains at least 1 point worth.
* @param tile the tile entity that is checking the essentia
* @param aspect the aspect that you are looking for
* @param direction the direction from which you wish to drain. Forgedirection.Unknown simply seeks in all directions.
* @param range how many blocks you wish to search for essentia sources.
* @return boolean returns true if essentia was found and removed from a source.
*/
public static boolean findEssentia(TileEntity tile, Aspect aspect, ForgeDirection direction, int range) {
try {
if(findEssentia == null) {
Class fake = Class.forName("thaumcraft.common.lib.events.EssentiaHandler");
findEssentia = fake.getMethod("findEssentia", TileEntity.class, Aspect.class, ForgeDirection.class, int.class);
}
return (Boolean) findEssentia.invoke(null, tile, aspect, direction, range);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.events.EssentiaHandler method findEssentia");
}
return false;
}
}
@@ -0,0 +1,80 @@
package thaumcraft.api.aspects;
/**
*
* @author azanor
*
* Used by blocks like the crucible and alembic to hold their aspects.
* Tiles extending this interface will have their aspects show up when viewed by goggles of revealing
*
*/
public interface IAspectContainer {
public AspectList getAspects();
public void setAspects(AspectList aspects);
/**
* This method is used to determine of a specific aspect can be added to this container.
* @param tag
* @return true or false
*/
public boolean doesContainerAccept(Aspect tag);
/**
* This method is used to add a certain amount of an aspect to the tile entity.
* @param tag
* @param amount
* @return the amount of aspect left over that could not be added.
*/
public int addToContainer(Aspect tag, int amount);
/**
* Removes a certain amount of a specific aspect from the tile entity
* @param tag
* @param amount
* @return true if that amount of aspect was available and was removed
*/
public boolean takeFromContainer(Aspect tag, int amount);
/**
* removes a bunch of different aspects and amounts from the tile entity.
* @param ot the ObjectTags object that contains the aspects and their amounts.
* @return true if all the aspects and their amounts were available and successfully removed
*
* Going away in the next major patch
*/
@Deprecated
public boolean takeFromContainer(AspectList ot);
/**
* Checks if the tile entity contains the listed amount (or more) of the aspect
* @param tag
* @param amount
* @return
*/
public boolean doesContainerContainAmount(Aspect tag,int amount);
/**
* Checks if the tile entity contains all the listed aspects and their amounts
* @param ot the ObjectTags object that contains the aspects and their amounts.
* @return
*
* Going away in the next major patch
*/
@Deprecated
public boolean doesContainerContain(AspectList ot);
/**
* Returns how much of the aspect this tile entity contains
* @param tag
* @return the amount of that aspect found
*/
public int containerContains(Aspect tag);
}
@@ -0,0 +1,16 @@
package thaumcraft.api.aspects;
/**
* @author Azanor
*
* This interface is implemented by tile entites (or possibly anything else) like jars
* so that they can act as an essentia source for blocks like the infusion altar.
*
*/
public interface IAspectSource extends IAspectContainer {
}
@@ -0,0 +1,36 @@
package thaumcraft.api.aspects;
import net.minecraft.item.ItemStack;
/**
*
* @author azanor
*
* Used by wispy essences and essentia phials to hold their aspects.
* Useful for similar item containers that store their aspect information in nbt form so TC
* automatically picks up the aspects they contain
*
*/
public interface IEssentiaContainerItem {
public AspectList getAspects(ItemStack itemstack);
public void setAspects(ItemStack itemstack, AspectList aspects);
}
//Example implementation
/*
@Override
public AspectList getAspects(ItemStack itemstack) {
if (itemstack.hasTagCompound()) {
AspectList aspects = new AspectList();
aspects.readFromNBT(itemstack.getTagCompound());
return aspects.size()>0?aspects:null;
}
return null;
}
@Override
public void setAspects(ItemStack itemstack, AspectList aspects) {
if (!itemstack.hasTagCompound()) itemstack.setTagCompound(new NBTTagCompound());
aspects.writeToNBT(itemstack.getTagCompound());
}
*/
@@ -0,0 +1,100 @@
package thaumcraft.api.aspects;
import net.minecraftforge.common.util.ForgeDirection;
/**
* @author Azanor
* This interface is used by tiles that use or transport vis.
* Only tiles that implement this interface will be able to connect to vis conduits or other thaumic devices
*/
public interface IEssentiaTransport {
/**
* Is this tile able to connect to other vis users/sources on the specified side?
* @param face
* @return
*/
public boolean isConnectable(ForgeDirection face);
/**
* Is this side used to input essentia?
* @param face
* @return
*/
boolean canInputFrom(ForgeDirection face);
/**
* Is this side used to output essentia?
* @param face
* @return
*/
boolean canOutputTo(ForgeDirection face);
/**
* Sets the amount of suction this block will apply
* @param suction
*/
public void setSuction(Aspect aspect, int amount);
/**
* Returns the type of suction this block is applying.
* @param loc
* the location from where the suction is being checked
* @return
* a return type of null indicates the suction is untyped and the first thing available will be drawn
*/
public Aspect getSuctionType(ForgeDirection face);
/**
* Returns the strength of suction this block is applying.
* @param loc
* the location from where the suction is being checked
* @return
*/
public int getSuctionAmount(ForgeDirection face);
/**
* remove the specified amount of essentia from this transport tile
* @return how much was actually taken
*/
public int takeEssentia(Aspect aspect, int amount, ForgeDirection face);
/**
* add the specified amount of essentia to this transport tile
* @return how much was actually added
*/
public int addEssentia(Aspect aspect, int amount, ForgeDirection face);
/**
* What type of essentia this contains
* @param face
* @return
*/
public Aspect getEssentiaType(ForgeDirection face);
/**
* How much essentia this block contains
* @param face
* @return
*/
public int getEssentiaAmount(ForgeDirection face);
/**
* Essentia will not be drawn from this container unless the suction exceeds this amount.
* @return the amount
*/
public int getMinimumSuction();
/**
* Return true if you want the conduit to extend a little further into the block.
* Used by jars and alembics that have smaller than normal hitboxes
* @return
*/
boolean renderExtendedTube();
}
@@ -0,0 +1,73 @@
package thaumcraft.api.crafting;
import java.util.ArrayList;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.ThaumcraftApiHelper;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
public class CrucibleRecipe {
private ItemStack recipeOutput;
public Object catalyst;
public AspectList aspects;
public String key;
public CrucibleRecipe(String researchKey, ItemStack result, Object cat, AspectList tags) {
recipeOutput = result;
this.aspects = tags;
this.key = researchKey;
this.catalyst = cat;
if (cat instanceof String) {
this.catalyst = OreDictionary.getOres((String) cat);
}
}
public boolean matches(AspectList itags, ItemStack cat) {
if (catalyst instanceof ItemStack &&
!ThaumcraftApiHelper.itemMatches((ItemStack) catalyst,cat,false)) {
return false;
} else
if (catalyst instanceof ArrayList && ((ArrayList<ItemStack>)catalyst).size()>0) {
if (!ThaumcraftApiHelper.containsMatch(true, ((ArrayList<ItemStack>)catalyst).toArray(new ItemStack[]{}), cat)) return false;
}
if (itags == null) return false;
for (Aspect tag:aspects.getAspects()) {
if (itags.getAmount(tag)<aspects.getAmount(tag)) return false;
}
return true;
}
public boolean catalystMatches(ItemStack cat) {
if (catalyst instanceof ItemStack && ThaumcraftApiHelper.itemMatches((ItemStack) catalyst,cat,false)) {
return true;
} else
if (catalyst instanceof ArrayList && ((ArrayList<ItemStack>)catalyst).size()>0) {
if (ThaumcraftApiHelper.containsMatch(true,
((ArrayList<ItemStack>)catalyst).toArray(new ItemStack[]{}), cat)) return true;
}
return false;
}
public AspectList removeMatching(AspectList itags) {
AspectList temptags = new AspectList();
temptags.aspects.putAll(itags.aspects);
for (Aspect tag:aspects.getAspects()) {
temptags.remove(tag, aspects.getAmount(tag));
// if (!temptags.remove(tag, aspects.getAmount(tag))) return null;
}
itags = temptags;
return itags;
}
public ItemStack getRecipeOutput() {
return recipeOutput;
}
}
@@ -0,0 +1,35 @@
package thaumcraft.api.crafting;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import thaumcraft.api.aspects.AspectList;
public interface IArcaneRecipe
{
/**
* Used to check if a recipe matches current crafting inventory
* @param player
*/
boolean matches(IInventory var1, World world, EntityPlayer player);
/**
* Returns an Item that is the result of this recipe
*/
ItemStack getCraftingResult(IInventory var1);
/**
* Returns the size of the recipe area
*/
int getRecipeSize();
ItemStack getRecipeOutput();
AspectList getAspects();
AspectList getAspects(IInventory var1);
String getResearch();
}
@@ -0,0 +1,19 @@
package thaumcraft.api.crafting;
import net.minecraft.world.World;
/**
*
* @author Azanor
*
* Blocks that implement this interface act as infusion crafting stabilisers like candles and skulls
*
*/
public interface IInfusionStabiliser {
/**
* returns true if the block can stabilise things
*/
public boolean canStabaliseInfusion(World world, int x, int y, int z);
}
@@ -0,0 +1,156 @@
package thaumcraft.api.crafting;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.ThaumcraftApiHelper;
import thaumcraft.api.aspects.AspectList;
public class InfusionEnchantmentRecipe
{
public AspectList aspects;
public String research;
public ItemStack[] components;
public Enchantment enchantment;
public int recipeXP;
public int instability;
public InfusionEnchantmentRecipe(String research, Enchantment input, int inst,
AspectList aspects2, ItemStack[] recipe) {
this.research = research;
this.enchantment = input;
this.aspects = aspects2;
this.components = recipe;
this.instability = inst;
this.recipeXP = Math.max(1, input.getMinEnchantability(1)/3);
}
/**
* Used to check if a recipe matches current crafting inventory
* @param player
*/
public boolean matches(ArrayList<ItemStack> input, ItemStack central, World world, EntityPlayer player) {
if (research.length()>0 && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) {
return false;
}
if (!enchantment.canApply(central) || !central.getItem().isItemTool(central)) {
return false;
}
Map map1 = EnchantmentHelper.getEnchantments(central);
Iterator iterator = map1.keySet().iterator();
while (iterator.hasNext())
{
int j1 = ((Integer)iterator.next()).intValue();
Enchantment ench = Enchantment.enchantmentsList[j1];
if (j1 == enchantment.effectId &&
EnchantmentHelper.getEnchantmentLevel(j1, central) >= ench.getMaxLevel())
return false;
if (enchantment.effectId != ench.effectId &&
(!enchantment.canApplyTogether(ench) ||
!ench.canApplyTogether(enchantment))) {
return false;
}
}
ItemStack i2 = null;
ArrayList<ItemStack> ii = new ArrayList<ItemStack>();
for (ItemStack is:input) {
ii.add(is.copy());
}
for (ItemStack comp:components) {
boolean b = false;
for (int a = 0;a<ii.size();a++) {
i2 = ii.get(a).copy();
if (comp.getItemDamage() == OreDictionary.WILDCARD_VALUE) {
i2.setItemDamage(OreDictionary.WILDCARD_VALUE);
}
if (areItemStacksEqual(i2, comp,true)) {
ii.remove(a);
b = true;
break;
}
}
if (!b) return false;
}
// System.out.println(ii.size());
return ii.size() == 0?true:false;
}
@SuppressWarnings("deprecation")
private boolean areItemStacksEqual(ItemStack stack0, ItemStack stack1, boolean fuzzy)
{
if (stack0 == null && stack1 != null) return false;
if (stack0 != null && stack1 == null) return false;
if (stack0 == null && stack1 == null) return true;
boolean t1 = false;
if (fuzzy) {
t1 = true;
int od = OreDictionary.getOreID(stack0);
if (od != -1) {
ItemStack[] ores = OreDictionary.getOres(od).toArray(new ItemStack[]{});
if (ThaumcraftApiHelper.containsMatch(false, new ItemStack[]{stack1}, ores))
return true;
}
}
else
t1 = ItemStack.areItemStackTagsEqual(stack0, stack1);
return stack0.getItem() != stack1.getItem() ? false : (stack0.getItemDamage() != stack1.getItemDamage() ? false : (stack0.stackSize > stack0.getMaxStackSize() ? false : t1));
}
public Enchantment getEnchantment() {
return enchantment;
}
public AspectList getAspects() {
return aspects;
}
public String getResearch() {
return research;
}
public int calcInstability(ItemStack recipeInput) {
int i = 0;
Map map1 = EnchantmentHelper.getEnchantments(recipeInput);
Iterator iterator = map1.keySet().iterator();
while (iterator.hasNext())
{
int j1 = ((Integer)iterator.next()).intValue();
i += EnchantmentHelper.getEnchantmentLevel(j1, recipeInput);
}
return (i/2) + instability;
}
public int calcXP(ItemStack recipeInput) {
return recipeXP * (1+EnchantmentHelper.getEnchantmentLevel(enchantment.effectId, recipeInput));
}
public float getEssentiaMod(ItemStack recipeInput) {
float mod = EnchantmentHelper.getEnchantmentLevel(enchantment.effectId, recipeInput);
Map map1 = EnchantmentHelper.getEnchantments(recipeInput);
Iterator iterator = map1.keySet().iterator();
while (iterator.hasNext())
{
int j1 = ((Integer)iterator.next()).intValue();
if (j1 != enchantment.effectId)
mod += EnchantmentHelper.getEnchantmentLevel(j1, recipeInput) * .1f;
}
return mod;
}
}
@@ -0,0 +1,128 @@
package thaumcraft.api.crafting;
import java.util.ArrayList;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.ThaumcraftApiHelper;
import thaumcraft.api.aspects.AspectList;
public class InfusionRecipe
{
protected AspectList aspects;
protected String research;
private ItemStack[] components;
private ItemStack recipeInput;
protected Object recipeOutput;
protected int instability;
public InfusionRecipe(String research, Object output, int inst,
AspectList aspects2, ItemStack input, ItemStack[] recipe) {
this.research = research;
this.recipeOutput = output;
this.recipeInput = input;
this.aspects = aspects2;
this.components = recipe;
this.instability = inst;
}
/**
* Used to check if a recipe matches current crafting inventory
* @param player
*/
public boolean matches(ArrayList<ItemStack> input, ItemStack central, World world, EntityPlayer player) {
if (getRecipeInput() == null) return false;
if (research.length()>0 && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) {
return false;
}
ItemStack i2 = central.copy();
if (getRecipeInput().getItemDamage() == OreDictionary.WILDCARD_VALUE) {
i2.setItemDamage(OreDictionary.WILDCARD_VALUE);
}
if (!areItemStacksEqual(i2, getRecipeInput(), true)) return false;
ArrayList<ItemStack> ii = new ArrayList<ItemStack>();
for (ItemStack is:input) {
ii.add(is.copy());
}
for (ItemStack comp:getComponents()) {
boolean b = false;
for (int a = 0;a<ii.size();a++) {
i2 = ii.get(a).copy();
if (comp.getItemDamage() == OreDictionary.WILDCARD_VALUE) {
i2.setItemDamage(OreDictionary.WILDCARD_VALUE);
}
if (areItemStacksEqual(i2, comp,true)) {
ii.remove(a);
b = true;
break;
}
}
if (!b) return false;
}
return ii.size() == 0?true:false;
}
@SuppressWarnings("deprecation")
protected boolean areItemStacksEqual(ItemStack stack0, ItemStack stack1, boolean fuzzy)
{
if (stack0 == null && stack1 != null) return false;
if (stack0 != null && stack1 == null) return false;
if (stack0 == null && stack1 == null) return true;
boolean t1 = false;
if (fuzzy) {
t1 = true;
int od = OreDictionary.getOreID(stack0);
if (od != -1) {
ItemStack[] ores = OreDictionary.getOres(od).toArray(new ItemStack[]{});
if (ThaumcraftApiHelper.containsMatch(false, new ItemStack[]{stack1}, ores))
return true;
}
}
else
t1 = ItemStack.areItemStackTagsEqual(stack0, stack1);
return stack0.getItem() != stack1.getItem() ? false : (stack0.getItemDamage() != stack1.getItemDamage() ? false : (stack0.stackSize > stack0.getMaxStackSize() ? false : t1));
}
public Object getRecipeOutput() {
return getRecipeOutput(this.getRecipeInput());
}
public AspectList getAspects() {
return getAspects(this.getRecipeInput());
}
public int getInstability() {
return getInstability(this.getRecipeInput());
}
public String getResearch() {
return research;
}
public ItemStack getRecipeInput() {
return recipeInput;
}
public ItemStack[] getComponents() {
return components;
}
public Object getRecipeOutput(ItemStack input) {
return recipeOutput;
}
public AspectList getAspects(ItemStack input) {
return aspects;
}
public int getInstability(ItemStack input) {
return instability;
}
}
@@ -0,0 +1,260 @@
package thaumcraft.api.crafting;
import java.util.ArrayList;
import java.util.HashMap;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.ThaumcraftApiHelper;
import thaumcraft.api.aspects.AspectList;
public class ShapedArcaneRecipe implements IArcaneRecipe
{
//Added in for future ease of change, but hard coded for now.
private static final int MAX_CRAFT_GRID_WIDTH = 3;
private static final int MAX_CRAFT_GRID_HEIGHT = 3;
public ItemStack output = null;
public Object[] input = null;
public AspectList aspects = null;
public String research;
public int width = 0;
public int height = 0;
private boolean mirrored = true;
public ShapedArcaneRecipe(String research, Block result, AspectList aspects, Object... recipe){ this(research, new ItemStack(result), aspects, recipe); }
public ShapedArcaneRecipe(String research, Item result, AspectList aspects, Object... recipe){ this(research, new ItemStack(result), aspects, recipe); }
public ShapedArcaneRecipe(String research, ItemStack result, AspectList aspects, Object... recipe)
{
output = result.copy();
this.research = research;
this.aspects = aspects;
String shape = "";
int idx = 0;
if (recipe[idx] instanceof Boolean)
{
mirrored = (Boolean)recipe[idx];
if (recipe[idx+1] instanceof Object[])
{
recipe = (Object[])recipe[idx+1];
}
else
{
idx = 1;
}
}
if (recipe[idx] instanceof String[])
{
String[] parts = ((String[])recipe[idx++]);
for (String s : parts)
{
width = s.length();
shape += s;
}
height = parts.length;
}
else
{
while (recipe[idx] instanceof String)
{
String s = (String)recipe[idx++];
shape += s;
width = s.length();
height++;
}
}
if (width * height != shape.length())
{
String ret = "Invalid shaped ore recipe: ";
for (Object tmp : recipe)
{
ret += tmp + ", ";
}
ret += output;
throw new RuntimeException(ret);
}
HashMap<Character, Object> itemMap = new HashMap<Character, Object>();
for (; idx < recipe.length; idx += 2)
{
Character chr = (Character)recipe[idx];
Object in = recipe[idx + 1];
if (in instanceof ItemStack)
{
itemMap.put(chr, ((ItemStack)in).copy());
}
else if (in instanceof Item)
{
itemMap.put(chr, new ItemStack((Item)in));
}
else if (in instanceof Block)
{
itemMap.put(chr, new ItemStack((Block)in, 1, OreDictionary.WILDCARD_VALUE));
}
else if (in instanceof String)
{
itemMap.put(chr, OreDictionary.getOres((String)in));
}
else
{
String ret = "Invalid shaped ore recipe: ";
for (Object tmp : recipe)
{
ret += tmp + ", ";
}
ret += output;
throw new RuntimeException(ret);
}
}
input = new Object[width * height];
int x = 0;
for (char chr : shape.toCharArray())
{
input[x++] = itemMap.get(chr);
}
}
@Override
public ItemStack getCraftingResult(IInventory var1){ return output.copy(); }
@Override
public int getRecipeSize(){ return input.length; }
@Override
public ItemStack getRecipeOutput(){ return output; }
@Override
public boolean matches(IInventory inv, World world, EntityPlayer player)
{
if (research.length()>0 && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) {
return false;
}
for (int x = 0; x <= MAX_CRAFT_GRID_WIDTH - width; x++)
{
for (int y = 0; y <= MAX_CRAFT_GRID_HEIGHT - height; ++y)
{
if (checkMatch(inv, x, y, false))
{
return true;
}
if (mirrored && checkMatch(inv, x, y, true))
{
return true;
}
}
}
return false;
}
private boolean checkMatch(IInventory inv, int startX, int startY, boolean mirror)
{
for (int x = 0; x < MAX_CRAFT_GRID_WIDTH; x++)
{
for (int y = 0; y < MAX_CRAFT_GRID_HEIGHT; y++)
{
int subX = x - startX;
int subY = y - startY;
Object target = null;
if (subX >= 0 && subY >= 0 && subX < width && subY < height)
{
if (mirror)
{
target = input[width - subX - 1 + subY * width];
}
else
{
target = input[subX + subY * width];
}
}
ItemStack slot = ThaumcraftApiHelper.getStackInRowAndColumn(inv, x, y);
if (target instanceof ItemStack)
{
if (!checkItemEquals((ItemStack)target, slot))
{
return false;
}
}
else if (target instanceof ArrayList)
{
boolean matched = false;
for (ItemStack item : (ArrayList<ItemStack>)target)
{
matched = matched || checkItemEquals(item, slot);
}
if (!matched)
{
return false;
}
}
else if (target == null && slot != null)
{
return false;
}
}
}
return true;
}
private boolean checkItemEquals(ItemStack target, ItemStack input)
{
if (input == null && target != null || input != null && target == null)
{
return false;
}
return (target.getItem() == input.getItem() &&
(!target.hasTagCompound() || ItemStack.areItemStackTagsEqual(target, input)) &&
(target.getItemDamage() == OreDictionary.WILDCARD_VALUE|| target.getItemDamage() == input.getItemDamage()));
}
public ShapedArcaneRecipe setMirrored(boolean mirror)
{
mirrored = mirror;
return this;
}
/**
* Returns the input for this recipe, any mod accessing this value should never
* manipulate the values in this array as it will effect the recipe itself.
* @return The recipes input vales.
*/
public Object[] getInput()
{
return this.input;
}
@Override
public AspectList getAspects() {
return aspects;
}
@Override
public AspectList getAspects(IInventory inv) {
return aspects;
}
@Override
public String getResearch() {
return research;
}
}
@@ -0,0 +1,156 @@
package thaumcraft.api.crafting;
import java.util.ArrayList;
import java.util.Iterator;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.ThaumcraftApiHelper;
import thaumcraft.api.aspects.AspectList;
public class ShapelessArcaneRecipe implements IArcaneRecipe
{
private ItemStack output = null;
private ArrayList input = new ArrayList();
public AspectList aspects = null;
public String research;
public ShapelessArcaneRecipe(String research, Block result, AspectList aspects, Object... recipe){ this(research,new ItemStack(result),aspects, recipe); }
public ShapelessArcaneRecipe(String research, Item result, AspectList aspects, Object... recipe){ this(research,new ItemStack(result),aspects, recipe); }
public ShapelessArcaneRecipe(String research, ItemStack result, AspectList aspects, Object... recipe)
{
output = result.copy();
this.research = research;
this.aspects = aspects;
for (Object in : recipe)
{
if (in instanceof ItemStack)
{
input.add(((ItemStack)in).copy());
}
else if (in instanceof Item)
{
input.add(new ItemStack((Item)in));
}
else if (in instanceof Block)
{
input.add(new ItemStack((Block)in));
}
else if (in instanceof String)
{
input.add(OreDictionary.getOres((String)in));
}
else
{
String ret = "Invalid shapeless ore recipe: ";
for (Object tmp : recipe)
{
ret += tmp + ", ";
}
ret += output;
throw new RuntimeException(ret);
}
}
}
@Override
public int getRecipeSize(){ return input.size(); }
@Override
public ItemStack getRecipeOutput(){ return output; }
@Override
public ItemStack getCraftingResult(IInventory var1){ return output.copy(); }
@Override
public boolean matches(IInventory var1, World world, EntityPlayer player)
{
if (research.length()>0 && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) {
return false;
}
ArrayList required = new ArrayList(input);
for (int x = 0; x < 9; x++)
{
ItemStack slot = var1.getStackInSlot(x);
if (slot != null)
{
boolean inRecipe = false;
Iterator req = required.iterator();
while (req.hasNext())
{
boolean match = false;
Object next = req.next();
if (next instanceof ItemStack)
{
match = checkItemEquals((ItemStack)next, slot);
}
else if (next instanceof ArrayList)
{
for (ItemStack item : (ArrayList<ItemStack>)next)
{
match = match || checkItemEquals(item, slot);
}
}
if (match)
{
inRecipe = true;
required.remove(next);
break;
}
}
if (!inRecipe)
{
return false;
}
}
}
return required.isEmpty();
}
private boolean checkItemEquals(ItemStack target, ItemStack input)
{
return (target.getItem() == input.getItem() &&
(!target.hasTagCompound() || ItemStack.areItemStackTagsEqual(target, input)) &&
(target.getItemDamage() == OreDictionary.WILDCARD_VALUE || target.getItemDamage() == input.getItemDamage()));
}
/**
* Returns the input for this recipe, any mod accessing this value should never
* manipulate the values in this array as it will effect the recipe itself.
* @return The recipes input vales.
*/
public ArrayList getInput()
{
return this.input;
}
@Override
public AspectList getAspects() {
return aspects;
}
@Override
public AspectList getAspects(IInventory inv) {
return aspects;
}
@Override
public String getResearch() {
return research;
}
}
@@ -0,0 +1,34 @@
package thaumcraft.api.damagesource;
import net.minecraft.entity.Entity;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSourceIndirect;
public class DamageSourceIndirectThaumcraftEntity extends EntityDamageSourceIndirect {
private boolean fireDamage;
private float hungerDamage;
private boolean isUnblockable;
public DamageSourceIndirectThaumcraftEntity(String par1Str,
Entity par2Entity, Entity par3Entity) {
super(par1Str, par2Entity, par3Entity);
}
@Override
public DamageSource setFireDamage()
{
this.fireDamage = true;
return this;
}
@Override
public DamageSource setDamageBypassesArmor()
{
this.isUnblockable = true;
this.hungerDamage = 0.0F;
return this;
}
}
@@ -0,0 +1,46 @@
package thaumcraft.api.damagesource;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSource;
public class DamageSourceThaumcraft extends DamageSource
{
public static DamageSource taint = new DamageSourceThaumcraft("taint").setDamageBypassesArmor().setMagicDamage();
public static DamageSource tentacle = new DamageSourceThaumcraft("tentacle");
public static DamageSource swarm = new DamageSourceThaumcraft("swarm");
protected DamageSourceThaumcraft(String par1Str) {
super(par1Str);
}
/** This kind of damage can be blocked or not. */
private boolean isUnblockable = false;
private boolean isDamageAllowedInCreativeMode = false;
private float hungerDamage = 0.3F;
/** This kind of damage is based on fire or not. */
private boolean fireDamage;
/** This kind of damage is based on a projectile or not. */
private boolean projectile;
/**
* Whether this damage source will have its damage amount scaled based on the current difficulty.
*/
private boolean difficultyScaled;
private boolean magicDamage = false;
private boolean explosion = false;
public static DamageSource causeSwarmDamage(EntityLivingBase par0EntityLiving)
{
return new EntityDamageSource("swarm", par0EntityLiving);
}
public static DamageSource causeTentacleDamage(EntityLivingBase par0EntityLiving)
{
return new EntityDamageSource("tentacle", par0EntityLiving);
}
}
@@ -0,0 +1,5 @@
package thaumcraft.api.entities;
public interface ITaintedMob {
}
@@ -0,0 +1,53 @@
package thaumcraft.api.nodes;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
import thaumcraft.api.aspects.IAspectContainer;
public interface INode extends IAspectContainer {
/**
* Unique identifier to distinguish nodes. Normal node id's are based on world id and coordinates
* @return
*/
public String getId();
public AspectList getAspectsBase();
/**
* Return the type of node
* @return
*/
public NodeType getNodeType();
/**
* Set the type of node
* @return
*/
public void setNodeType(NodeType nodeType);
/**
* Return the node modifier
* @return
*/
public void setNodeModifier(NodeModifier nodeModifier);
/**
* Set the node modifier
* @return
*/
public NodeModifier getNodeModifier();
/**
* Return the maximum capacity of each aspect the node can hold
* @return
*/
public int getNodeVisBase(Aspect aspect);
/**
* Set the maximum capacity of each aspect the node can hold
* @return
*/
public void setNodeVisBase(Aspect aspect, short nodeVisBase);
}
@@ -0,0 +1,22 @@
package thaumcraft.api.nodes;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
/**
*
* @author Azanor
*
* Equipped head slot items that extend this class will make nodes visible in world.
*
*/
public interface IRevealer {
/*
* If this method returns true the nodes will be visible.
*/
public boolean showNodes(ItemStack itemstack, EntityLivingBase player);
}
@@ -0,0 +1,6 @@
package thaumcraft.api.nodes;
public enum NodeModifier
{
BRIGHT, PALE, FADING
}
@@ -0,0 +1,6 @@
package thaumcraft.api.nodes;
public enum NodeType
{
NORMAL, UNSTABLE, DARK, TAINTED, HUNGRY, PURE
}
@@ -0,0 +1,68 @@
package thaumcraft.api.potions;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.potion.Potion;
import net.minecraft.util.ResourceLocation;
import thaumcraft.api.damagesource.DamageSourceThaumcraft;
import thaumcraft.api.entities.ITaintedMob;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class PotionFluxTaint extends Potion
{
public static PotionFluxTaint instance = null; // will be instantiated at runtime
private int statusIconIndex = -1;
public PotionFluxTaint(int par1, boolean par2, int par3)
{
super(par1,par2,par3);
setIconIndex(0, 0);
}
public static void init()
{
instance.setPotionName("potion.fluxtaint");
instance.setIconIndex(3, 1);
instance.setEffectiveness(0.25D);
}
@Override
public boolean isBadEffect() {
return true;
}
@Override
@SideOnly(Side.CLIENT)
public int getStatusIconIndex() {
Minecraft.getMinecraft().renderEngine.bindTexture(rl);
return super.getStatusIconIndex();
}
ResourceLocation rl = new ResourceLocation("thaumcraft","textures/misc/potions.png");
@Override
public void performEffect(EntityLivingBase target, int par2) {
if (target instanceof ITaintedMob) {
target.heal(1);
} else
if (!target.isEntityUndead() && !(target instanceof EntityPlayer))
{
target.attackEntityFrom(DamageSourceThaumcraft.taint, 1);
}
else
if (!target.isEntityUndead() && (target.getMaxHealth() > 1 || (target instanceof EntityPlayer)))
{
target.attackEntityFrom(DamageSourceThaumcraft.taint, 1);
}
}
@Override
public boolean isReady(int par1, int par2)
{
int k = 40 >> par2;
return k > 0 ? par1 % k == 0 : true;
}
}
@@ -0,0 +1,9 @@
package thaumcraft.api.research;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public interface IScanEventHandler {
ScanResult scanPhenomena(ItemStack stack, World world, EntityPlayer player);
}
@@ -0,0 +1,98 @@
package thaumcraft.api.research;
import java.util.Collection;
import java.util.LinkedHashMap;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import org.apache.logging.log4j.Level;
import cpw.mods.fml.common.FMLLog;
public class ResearchCategories {
//Research
public static LinkedHashMap <String, ResearchCategoryList> researchCategories = new LinkedHashMap <String,ResearchCategoryList>();
/**
* @param key
* @return the research item linked to this key
*/
public static ResearchCategoryList getResearchList(String key) {
return researchCategories.get(key);
}
/**
* @param key
* @return the name of the research category linked to this key.
* Must be stored as localization information in the LanguageRegistry.
*/
public static String getCategoryName(String key) {
return StatCollector.translateToLocal("tc.research_category."+key);
}
/**
* @param key the research key
* @return the ResearchItem object.
*/
public static ResearchItem getResearch(String key) {
Collection rc = researchCategories.values();
for (Object cat:rc) {
Collection rl = ((ResearchCategoryList)cat).research.values();
for (Object ri:rl) {
if ((((ResearchItem)ri).key).equals(key)) return (ResearchItem)ri;
}
}
return null;
}
/**
* This should only be done at the PostInit stage
* @param key the key used for this category
* @param icon the icon to be used for the research category tab
* @param background the resource location of the background image to use for this category
* @return the name of the research linked to this key
*/
public static void registerCategory(String key, ResourceLocation icon, ResourceLocation background) {
if (getResearchList(key) == null) {
ResearchCategoryList rl = new ResearchCategoryList(icon, background);
researchCategories.put(key, rl);
}
}
public static void addResearch(ResearchItem ri) {
ResearchCategoryList rl = getResearchList(ri.category);
if (rl != null && !rl.research.containsKey(ri.key)) {
if (!ri.isVirtual()) {
for (ResearchItem rr:rl.research.values()) {
if (rr.displayColumn == ri.displayColumn && rr.displayRow == ri.displayRow) {
FMLLog.log(Level.FATAL, "[Thaumcraft] Research ["+ri.getName()+"] not added as it overlaps with existing research ["+rr.getName()+"]");
return;
}
}
}
rl.research.put(ri.key, ri);
if (ri.displayColumn < rl.minDisplayColumn)
{
rl.minDisplayColumn = ri.displayColumn;
}
if (ri.displayRow < rl.minDisplayRow)
{
rl.minDisplayRow = ri.displayRow;
}
if (ri.displayColumn > rl.maxDisplayColumn)
{
rl.maxDisplayColumn = ri.displayColumn;
}
if (ri.displayRow > rl.maxDisplayRow)
{
rl.maxDisplayRow = ri.displayRow;
}
}
}
}
@@ -0,0 +1,36 @@
package thaumcraft.api.research;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.util.ResourceLocation;
public class ResearchCategoryList {
/** Is the smallest column used on the GUI. */
public int minDisplayColumn;
/** Is the smallest row used on the GUI. */
public int minDisplayRow;
/** Is the biggest column used on the GUI. */
public int maxDisplayColumn;
/** Is the biggest row used on the GUI. */
public int maxDisplayRow;
/** display variables **/
public ResourceLocation icon;
public ResourceLocation background;
public ResearchCategoryList(ResourceLocation icon, ResourceLocation background) {
this.icon = icon;
this.background = background;
}
//Research
public Map<String, ResearchItem> research = new HashMap<String,ResearchItem>();
}
@@ -0,0 +1,367 @@
package thaumcraft.api.research;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
public class ResearchItem
{
/**
* A short string used as a key for this research. Must be unique
*/
public final String key;
/**
* A short string used as a reference to the research category to which this must be added.
*/
public final String category;
/**
* The aspect tags and their values required to complete this research
*/
public final AspectList tags;
/**
* This links to any research that needs to be completed before this research can be discovered or learnt.
*/
public String[] parents = null;
/**
* Like parent above, but a line will not be displayed in the thaumonomicon linking them. Just used to prevent clutter.
*/
public String[] parentsHidden = null;
/**
* any research linked to this that will be unlocked automatically when this research is complete
*/
public String[] siblings = null;
/**
* the horizontal position of the research icon
*/
public final int displayColumn;
/**
* the vertical position of the research icon
*/
public final int displayRow;
/**
* the icon to be used for this research
*/
public final ItemStack icon_item;
/**
* the icon to be used for this research
*/
public final ResourceLocation icon_resource;
/**
* How large the research grid is. Valid values are 1 to 3.
*/
private int complexity;
/**
* Special research has a spiky border. Used for important research milestones.
*/
private boolean isSpecial;
/**
* Research that can be directly purchased with RP in normal research difficulty.
*/
private boolean isSecondary;
/**
* This indicates if the research should use a circular icon border. Usually used for "passive" research
* that doesn't have recipes and grants passive effects, or that unlock automatically.
*/
private boolean isRound;
/**
* Stub research cannot be discovered by normal means, but can be unlocked via the sibling system.
*/
private boolean isStub;
/**
* This indicated that the research is completely hidden and cannot be discovered by any
* player-controlled means. The recipes will never show up in the thaumonomicon.
* Usually used to unlock "hidden" recipes via sibling unlocking, like
* the various cap and rod combos for wands.
*/
private boolean isVirtual;
@Deprecated
private boolean isLost;
/**
* Concealed research does not display in the thaumonomicon until parent researches are discovered.
*/
private boolean isConcealed;
/**
* Hidden research can only be discovered via scanning or knowledge fragments
*/
private boolean isHidden;
/**
* These research items will automatically unlock for all players on game start
*/
private boolean isAutoUnlock;
/**
* Scanning these items will have a chance of revealing hidden knowledge in the thaumonomicon
*/
private ItemStack[] itemTriggers;
/**
* Scanning these entities will have a chance of revealing hidden knowledge in the thaumonomicon
*/
private String[] entityTriggers;
/**
* Scanning things with these aspects will have a chance of revealing hidden knowledge in the thaumonomicon
*/
private Aspect[] aspectTriggers;
private ResearchPage[] pages = null;
public ResearchItem(String key, String category)
{
this.key = key;
this.category = category;
this.tags = new AspectList();
this.icon_resource = null;
this.icon_item = null;
this.displayColumn = 0;
this.displayRow = 0;
this.setVirtual();
}
public ResearchItem(String key, String category, AspectList tags, int col, int row, int complex, ResourceLocation icon)
{
this.key = key;
this.category = category;
this.tags = tags;
this.icon_resource = icon;
this.icon_item = null;
this.displayColumn = col;
this.displayRow = row;
this.complexity = complex;
if (complexity < 1) this.complexity = 1;
if (complexity > 3) this.complexity = 3;
}
public ResearchItem(String key, String category, AspectList tags, int col, int row, int complex, ItemStack icon)
{
this.key = key;
this.category = category;
this.tags = tags;
this.icon_item = icon;
this.icon_resource = null;
this.displayColumn = col;
this.displayRow = row;
this.complexity = complex;
if (complexity < 1) this.complexity = 1;
if (complexity > 3) this.complexity = 3;
}
public ResearchItem setSpecial()
{
this.isSpecial = true;
return this;
}
public ResearchItem setStub()
{
this.isStub = true;
return this;
}
@Deprecated
public ResearchItem setLost()
{
this.isLost = true;
return this;
}
public ResearchItem setConcealed()
{
this.isConcealed = true;
return this;
}
public ResearchItem setHidden()
{
this.isHidden = true;
return this;
}
public ResearchItem setVirtual()
{
this.isVirtual = true;
return this;
}
public ResearchItem setParents(String... par)
{
this.parents = par;
return this;
}
public ResearchItem setParentsHidden(String... par)
{
this.parentsHidden = par;
return this;
}
public ResearchItem setSiblings(String... sib)
{
this.siblings = sib;
return this;
}
public ResearchItem setPages(ResearchPage... par)
{
this.pages = par;
return this;
}
public ResearchPage[] getPages() {
return pages;
}
public ResearchItem setItemTriggers(ItemStack... par)
{
this.itemTriggers = par;
return this;
}
public ResearchItem setEntityTriggers(String... par)
{
this.entityTriggers = par;
return this;
}
public ResearchItem setAspectTriggers(Aspect... par)
{
this.aspectTriggers = par;
return this;
}
public ItemStack[] getItemTriggers() {
return itemTriggers;
}
public String[] getEntityTriggers() {
return entityTriggers;
}
public Aspect[] getAspectTriggers() {
return aspectTriggers;
}
public ResearchItem registerResearchItem()
{
ResearchCategories.addResearch(this);
return this;
}
public String getName()
{
return StatCollector.translateToLocal("tc.research_name."+key);
}
public String getText()
{
return StatCollector.translateToLocal("tc.research_text."+key);
}
public boolean isSpecial()
{
return this.isSpecial;
}
public boolean isStub()
{
return this.isStub;
}
@Deprecated
public boolean isLost()
{
return this.isLost;
}
public boolean isConcealed()
{
return this.isConcealed;
}
public boolean isHidden()
{
return this.isHidden;
}
public boolean isVirtual()
{
return this.isVirtual;
}
public boolean isAutoUnlock() {
return isAutoUnlock;
}
public ResearchItem setAutoUnlock()
{
this.isAutoUnlock = true;
return this;
}
public boolean isRound() {
return isRound;
}
public ResearchItem setRound() {
this.isRound = true;
return this;
}
public boolean isSecondary() {
return isSecondary;
}
public ResearchItem setSecondary() {
this.isSecondary = true;
return this;
}
public int getComplexity() {
return complexity;
}
public ResearchItem setComplexity(int complexity) {
this.complexity = complexity;
return this;
}
/**
* @return the aspect aspects ordinal with the highest value. Used to determine scroll color and similar things
*/
public Aspect getResearchPrimaryTag() {
Aspect aspect = null;
int highest = 0;
if (tags != null)
for (Aspect tag:tags.getAspects()) {
if (tags.getAmount(tag)>highest) {
aspect = tag;
highest = tags.getAmount(tag);
};
}
return aspect;
}
}
@@ -0,0 +1,173 @@
package thaumcraft.api.research;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import thaumcraft.api.aspects.AspectList;
import thaumcraft.api.crafting.CrucibleRecipe;
import thaumcraft.api.crafting.IArcaneRecipe;
import thaumcraft.api.crafting.InfusionEnchantmentRecipe;
import thaumcraft.api.crafting.InfusionRecipe;
public class ResearchPage {
public static enum PageType
{
TEXT,
TEXT_CONCEALED,
IMAGE,
CRUCIBLE_CRAFTING,
ARCANE_CRAFTING,
ASPECTS,
NORMAL_CRAFTING,
INFUSION_CRAFTING,
COMPOUND_CRAFTING,
INFUSION_ENCHANTMENT
}
public PageType type = PageType.TEXT;
public String text = null;
public String research = null;
public ResourceLocation image = null;
public AspectList aspects = null;
public Object recipe = null;
public ItemStack recipeOutput = null;
/**
* @param text this can (but does not have to) be a reference to a localization variable, not the actual text.
*/
public ResearchPage(String text) {
this.type = PageType.TEXT;
this.text = text;
}
/**
* @param research this page will only be displayed if the player has discovered this research
* @param text this can (but does not have to) be a reference to a localization variable, not the actual text.
*/
public ResearchPage(String research, String text) {
this.type = PageType.TEXT_CONCEALED;
this.research = research;
this.text = text;
}
/**
* @param recipe a vanilla crafting recipe.
*/
public ResearchPage(IRecipe recipe) {
this.type = PageType.NORMAL_CRAFTING;
this.recipe = recipe;
this.recipeOutput = recipe.getRecipeOutput();
}
/**
* @param recipe a collection of vanilla crafting recipes.
*/
public ResearchPage(IRecipe[] recipe) {
this.type = PageType.NORMAL_CRAFTING;
this.recipe = recipe;
}
/**
* @param recipe a collection of arcane crafting recipes.
*/
public ResearchPage(IArcaneRecipe[] recipe) {
this.type = PageType.ARCANE_CRAFTING;
this.recipe = recipe;
}
/**
* @param recipe a collection of infusion crafting recipes.
*/
public ResearchPage(InfusionRecipe[] recipe) {
this.type = PageType.INFUSION_CRAFTING;
this.recipe = recipe;
}
/**
* @param recipe a compound crafting recipe.
*/
public ResearchPage(List recipe) {
this.type = PageType.COMPOUND_CRAFTING;
this.recipe = recipe;
}
/**
* @param recipe an arcane worktable crafting recipe.
*/
public ResearchPage(IArcaneRecipe recipe) {
this.type = PageType.ARCANE_CRAFTING;
this.recipe = recipe;
this.recipeOutput = recipe.getRecipeOutput();
}
/**
* @param recipe an alchemy crafting recipe.
*/
public ResearchPage(CrucibleRecipe recipe) {
this.type = PageType.CRUCIBLE_CRAFTING;
this.recipe = recipe;
this.recipeOutput = recipe.getRecipeOutput();
}
/**
* @param recipe an infusion crafting recipe.
*/
public ResearchPage(InfusionRecipe recipe) {
this.type = PageType.INFUSION_CRAFTING;
this.recipe = recipe;
if (recipe.getRecipeOutput() instanceof ItemStack) {
this.recipeOutput = (ItemStack) recipe.getRecipeOutput();
} else {
this.recipeOutput = recipe.getRecipeInput();
}
}
/**
* @param recipe an infusion crafting recipe.
*/
public ResearchPage(InfusionEnchantmentRecipe recipe) {
this.type = PageType.INFUSION_ENCHANTMENT;
this.recipe = recipe;
// if (recipe.recipeOutput instanceof ItemStack) {
// this.recipeOutput = (ItemStack) recipe.recipeOutput;
// } else {
// this.recipeOutput = recipe.recipeInput;
// }
}
/**
* @param image
* @param caption this can (but does not have to) be a reference to a localization variable, not the actual text.
*/
public ResearchPage(ResourceLocation image, String caption) {
this.type = PageType.IMAGE;
this.image = image;
this.text = caption;
}
/**
* This function should really not be called directly - used internally
*/
public ResearchPage(AspectList as) {
this.type = PageType.ASPECTS;
this.aspects = as;
}
/**
* returns a localized text of the text field (if one exists). Returns the text field itself otherwise.
* @return
*/
public String getTranslatedText() {
String ret = "";
if (text != null) {
ret = StatCollector.translateToLocal(text);
if (ret.isEmpty()) ret = text;
}
return ret;
}
}
@@ -0,0 +1,44 @@
package thaumcraft.api.research;
import net.minecraft.entity.Entity;
public class ScanResult {
public byte type = 0; //1 = blocks,2 = entities,3 = phenomena
public int id;
public int meta;
public Entity entity;
public String phenomena;
public ScanResult(byte type, int blockId, int blockMeta, Entity entity,
String phenomena) {
super();
this.type = type;
this.id = blockId;
this.meta = blockMeta;
this.entity = entity;
this.phenomena = phenomena;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ScanResult) {
ScanResult sr = (ScanResult) obj;
if (type != sr.type)
return false;
if (type == 1
&& (id != sr.id || meta != sr.meta))
return false;
if (type == 2 && entity.getEntityId() != sr.entity.getEntityId())
return false;
if (type == 3 && !phenomena.equals(sr.phenomena))
return false;
}
return true;
}
@Override
public int hashCode(){
return super.hashCode();
}
}
@@ -0,0 +1,64 @@
package thaumcraft.api.wands;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;
import thaumcraft.api.aspects.AspectList;
public interface IWandFocus {
public enum WandFocusAnimation {
WAVE, CHARGE;
}
/**
* @return The color the focus should be changed to.
*/
public int getFocusColor();
/**
* @return An icon that will be drawn as a block inside the focus "block".
*/
IIcon getFocusDepthLayerIcon();
public IIcon getOrnament();
public WandFocusAnimation getAnimation();
/**
* Gets the amount of vis used per aspect per click or tick. This cost is actually listed as
* a hundredth of a single point of vis, so a cost of 100 will equal one vis per tick/click.
* It is returned as an AspectList to allow for multiple vis types in different ratios.
*/
public AspectList getVisCost();
public boolean isVisCostPerTick();
public ItemStack onFocusRightClick(ItemStack itemstack, World world, EntityPlayer player, MovingObjectPosition movingobjectposition);
public void onUsingFocusTick(ItemStack itemstack, EntityPlayer player, int count);
public void onPlayerStoppedUsingFocus(ItemStack itemstack, World world, EntityPlayer player, int count);
/**
* Helper method to determine in what order foci should be iterated through when
* the user presses the 'change focus' keybinding.
* @return a string of characters that foci will be sorted against.
* For example AA00 will be placed before FG12
* <br>As a guide build the sort string from two alphanumeric characters followed by
* two numeric characters based on... whatever.
*/
public String getSortingHelper(ItemStack itemstack);
boolean onFocusBlockStartBreak(ItemStack itemstack, int x, int y, int z, EntityPlayer player);
public boolean acceptsEnchant(int id);
}
@@ -0,0 +1,16 @@
package thaumcraft.api.wands;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
/**
*
* @author azanor
*
* Implemented by a class that you wish to be called whenever a wand with this rod performs its
* update tick.
*
*/
public interface IWandRodOnUpdate {
void onUpdate(ItemStack itemstack, EntityPlayer player);
}
@@ -0,0 +1,12 @@
package thaumcraft.api.wands;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public interface IWandTriggerManager {
public boolean performTrigger(World world, ItemStack wand, EntityPlayer player,
int x, int y, int z, int side, int event);
}
@@ -0,0 +1,25 @@
package thaumcraft.api.wands;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
/**
*
* @author azanor
*
* Add this to a tile entity that you wish wands to interact with in some way.
*
*/
public interface IWandable {
public int onWandRightClick(World world, ItemStack wandstack, EntityPlayer player, int x, int y, int z, int side, int md);
public ItemStack onWandRightClick(World world, ItemStack wandstack, EntityPlayer player);
public void onUsingWandTick(ItemStack wandstack, EntityPlayer player, int count);
public void onWandStoppedUsing(ItemStack wandstack, World world, EntityPlayer player, int count);
}
@@ -0,0 +1,165 @@
package thaumcraft.api.wands;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumRarity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.StatCollector;
import net.minecraft.world.World;
import thaumcraft.api.ThaumcraftApi;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ItemFocusBasic extends Item implements IWandFocus {
public ItemFocusBasic ()
{
super();
maxStackSize = 1;
canRepair = false;
this.setMaxDamage(0);
}
public IIcon icon;
@SideOnly(Side.CLIENT)
@Override
public IIcon getIconFromDamage(int par1) {
return icon;
}
@Override
public boolean isItemTool(ItemStack par1ItemStack)
{
return true;
}
@Override
public boolean isDamageable() {
return true;
}
@Override
public void addInformation(ItemStack stack,EntityPlayer player, List list, boolean par4) {
AspectList al = this.getVisCost();
if (al != null && al.size()>0) {
list.add(StatCollector.translateToLocal(isVisCostPerTick()?"item.Focus.cost2":"item.Focus.cost1"));
for (Aspect aspect:al.getAspectsSorted()) {
DecimalFormat myFormatter = new DecimalFormat("#####.##");
String amount = myFormatter.format(al.getAmount(aspect)/100f);
list.add(" \u00A7"+aspect.getChatcolor()+aspect.getName()+"\u00A7r x "+ amount);
}
}
}
@Override
public int getItemEnchantability() {
return 5;
}
@Override
public EnumRarity getRarity(ItemStack itemstack)
{
return EnumRarity.rare;
}
@Override
public int getFocusColor() {
// TODO Auto-generated method stub
return 0;
}
@Override
public AspectList getVisCost() {
// TODO Auto-generated method stub
return null;
}
@Override
public ItemStack onFocusRightClick(ItemStack itemstack, World world,
EntityPlayer player, MovingObjectPosition movingobjectposition) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onUsingFocusTick(ItemStack itemstack, EntityPlayer player,
int count) {
// TODO Auto-generated method stub
}
@Override
public void onPlayerStoppedUsingFocus(ItemStack itemstack, World world,
EntityPlayer player, int count) {
// TODO Auto-generated method stub
}
/**
* Just insert two alphanumeric characters before this string in your focus item class
*/
@Override
public String getSortingHelper(ItemStack itemstack) {
Map<Integer,Integer> ench = EnchantmentHelper.getEnchantments(itemstack);
String out = "";
for (Integer lvl:ench.values()) {
out = out + lvl + "";
}
return out;
}
@Override
public boolean isVisCostPerTick() {
return false;
}
@Override
public IIcon getOrnament() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean onFocusBlockStartBreak(ItemStack itemstack, int x, int y,
int z, EntityPlayer player) {
// TODO Auto-generated method stub
return false;
}
@Override
public WandFocusAnimation getAnimation() {
return WandFocusAnimation.WAVE;
}
@Override
public IIcon getFocusDepthLayerIcon() {
// TODO Auto-generated method stub
return null;
}
/**
* @see thaumcraft.api.wands.IWandFocus#acceptsEnchant(int)
* By default fortune is off for all wands
**/
@Override
public boolean acceptsEnchant(int id) {
if (id == ThaumcraftApi.enchantFrugal||
id == ThaumcraftApi.enchantPotency) return true;
return false;
}
}
@@ -0,0 +1,48 @@
package thaumcraft.api.wands;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
/**
*
* @author Azanor
*
* This class is used to keep the material information for the various rods.
* It is also used to generate the wand recipes ingame.
*
*/
public class StaffRod extends WandRod {
boolean runes = false;
public StaffRod(String tag, int capacity, ItemStack item, int craftCost) {
super(tag+"_staff", capacity, item, craftCost);
this.texture = new ResourceLocation("thaumcraft","textures/models/wand_rod_"+tag+".png");
}
public StaffRod(String tag, int capacity, ItemStack item, int craftCost,
IWandRodOnUpdate onUpdate, ResourceLocation texture) {
super(tag+"_staff", capacity, item, craftCost, onUpdate, texture);
}
public StaffRod(String tag, int capacity, ItemStack item, int craftCost,
IWandRodOnUpdate onUpdate) {
super(tag+"_staff", capacity, item, craftCost, onUpdate);
this.texture = new ResourceLocation("thaumcraft","textures/models/wand_rod_"+tag+".png");
}
public StaffRod(String tag, int capacity, ItemStack item, int craftCost,
ResourceLocation texture) {
super(tag+"_staff", capacity, item, craftCost, texture);
}
public boolean hasRunes() {
return runes;
}
public void setRunes(boolean hasRunes) {
this.runes = hasRunes;
}
}
@@ -0,0 +1,121 @@
package thaumcraft.api.wands;
import java.util.LinkedHashMap;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import thaumcraft.api.aspects.Aspect;
/**
* This class is used to keep the material information for the various caps.
* It is also used to generate the wand recipes ingame.
* @author Azanor
*
*/
public class WandCap {
private String tag;
/**
* Cost to craft this wand. Combined with the rod cost.
*/
private int craftCost;
/**
* the amount by which all aspect costs are multiplied
*/
float baseCostModifier;
/**
* specifies a list of primal aspects that use the special discount figure instead of the normal discount.
*/
List<Aspect> specialCostModifierAspects;
/**
* the amount by which the specified aspect costs are multiplied
*/
float specialCostModifier;
/**
* The texture that will be used for the ingame wand cap
*/
ResourceLocation texture;
/**
* the actual item that makes up this cap and will be used to generate the wand recipes
*/
ItemStack item;
public static LinkedHashMap<String,WandCap> caps = new LinkedHashMap<String,WandCap>();
public WandCap (String tag, float discount, ItemStack item, int craftCost) {
this.setTag(tag);
this.baseCostModifier = discount;
this.specialCostModifierAspects = null;
texture = new ResourceLocation("thaumcraft","textures/models/wand_cap_"+getTag()+".png");
this.item = item;
this.setCraftCost(craftCost);
caps.put(tag, this);
}
public WandCap (String tag, float discount, List<Aspect> specialAspects, float discountSpecial, ItemStack item, int craftCost) {
this.setTag(tag);
this.baseCostModifier = discount;
this.specialCostModifierAspects = specialAspects;
this.specialCostModifier = discountSpecial;
texture = new ResourceLocation("thaumcraft","textures/models/wand_cap_"+getTag()+".png");
this.item = item;
this.setCraftCost(craftCost);
caps.put(tag, this);
}
public float getBaseCostModifier() {
return baseCostModifier;
}
public List<Aspect> getSpecialCostModifierAspects() {
return specialCostModifierAspects;
}
public float getSpecialCostModifier() {
return specialCostModifier;
}
public ResourceLocation getTexture() {
return texture;
}
public void setTexture(ResourceLocation texture) {
this.texture = texture;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public ItemStack getItem() {
return item;
}
public void setItem(ItemStack item) {
this.item = item;
}
public int getCraftCost() {
return craftCost;
}
public void setCraftCost(int craftCost) {
this.craftCost = craftCost;
}
// Some examples:
// WandCap WAND_CAP_IRON = new WandCap("iron", 1.1f, Arrays.asList(Aspect.ORDER),1, new ItemStack(ConfigItems.itemWandCap,1,0),1);
// WandCap WAND_CAP_GOLD = new WandCap("gold", 1f, new ItemStack(ConfigItems.itemWandCap,1,1),3);
}
@@ -0,0 +1,150 @@
package thaumcraft.api.wands;
import java.util.LinkedHashMap;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
/**
*
* @author Azanor
*
* This class is used to keep the material information for the various rods.
* It is also used to generate the wand recipes ingame.
*
*/
public class WandRod {
private String tag;
/**
* Cost to craft this wand. Combined with the rod cost.
*/
private int craftCost;
/**
* The amount of vis that can be stored - this number is actually multiplied
* by 100 for use by the wands internals
*/
int capacity;
/**
* The texture that will be used for the ingame wand rod
*/
protected ResourceLocation texture;
/**
* the actual item that makes up this rod and will be used to generate the wand recipes
*/
ItemStack item;
/**
* A class that will be called whenever the wand onUpdate tick is run
*/
IWandRodOnUpdate onUpdate;
/**
* Does the rod glow in the dark?
*/
boolean glow;
public static LinkedHashMap<String,WandRod> rods = new LinkedHashMap<String,WandRod>();
public WandRod (String tag, int capacity, ItemStack item, int craftCost, ResourceLocation texture) {
this.setTag(tag);
this.capacity = capacity;
this.texture = texture;
this.item = item;
this.setCraftCost(craftCost);
rods.put(tag, this);
}
public WandRod (String tag, int capacity, ItemStack item, int craftCost, IWandRodOnUpdate onUpdate, ResourceLocation texture) {
this.setTag(tag);
this.capacity = capacity;
this.texture = texture;
this.item = item;
this.setCraftCost(craftCost);
rods.put(tag, this);
this.onUpdate = onUpdate;
}
public WandRod (String tag, int capacity, ItemStack item, int craftCost) {
this.setTag(tag);
this.capacity = capacity;
this.texture = new ResourceLocation("thaumcraft","textures/models/wand_rod_"+getTag()+".png");
this.item = item;
this.setCraftCost(craftCost);
rods.put(tag, this);
}
public WandRod (String tag, int capacity, ItemStack item, int craftCost, IWandRodOnUpdate onUpdate) {
this.setTag(tag);
this.capacity = capacity;
this.texture = new ResourceLocation("thaumcraft","textures/models/wand_rod_"+getTag()+".png");
this.item = item;
this.setCraftCost(craftCost);
rods.put(tag, this);
this.onUpdate = onUpdate;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public ResourceLocation getTexture() {
return texture;
}
public void setTexture(ResourceLocation texture) {
this.texture = texture;
}
public ItemStack getItem() {
return item;
}
public void setItem(ItemStack item) {
this.item = item;
}
public int getCraftCost() {
return craftCost;
}
public void setCraftCost(int craftCost) {
this.craftCost = craftCost;
}
public IWandRodOnUpdate getOnUpdate() {
return onUpdate;
}
public void setOnUpdate(IWandRodOnUpdate onUpdate) {
this.onUpdate = onUpdate;
}
public boolean isGlowing() {
return glow;
}
public void setGlowing(boolean hasGlow) {
this.glow = hasGlow;
}
// Some examples:
// WandRod WAND_ROD_WOOD = new WandRod("wood",25,new ItemStack(Item.stick),1);
// WandRod WAND_ROD_BLAZE = new WandRod("blaze",100,new ItemStack(Item.blazeRod),7,new WandRodBlazeOnUpdate());
}
@@ -0,0 +1,71 @@
package thaumcraft.api.wands;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
/**
* This class serves a similar function to IWandable in that it allows wands to interact
* with object in the world. In this case it is most useful for adding interaction with non-mod
* blocks where you can't control what happens in their code.
* Example where it is used is in crafting the thaumonomicon from a bookshelf and the
* crucible from a cauldron
*
* @author azanor
*
*/
public class WandTriggerRegistry {
/**
* Registers an action to perform when a casting wand right clicks on a specific block.
* A manager class needs to be created that implements IWandTriggerManager.
* @param manager
* @param event a logical number that you can use to differentiate different events or actions
* @param block
* @param meta send -1 as a wildcard value for all possible meta values
*/
public static void registerWandBlockTrigger(IWandTriggerManager manager, int event, Block block, int meta) {
triggers.put(Arrays.asList(block,meta),
Arrays.asList(manager,event));
}
private static HashMap<List,List> triggers = new HashMap<List,List>();
public static boolean hasTrigger(Block block, int meta) {
if (triggers.containsKey(Arrays.asList(block,meta)) ||
triggers.containsKey(Arrays.asList(block,-1))) return true;
return false;
}
/**
* This is called by the onItemUseFirst function in wands.
* Parameters and return value functions like you would expect for that function.
* @param world
* @param wand
* @param player
* @param x
* @param y
* @param z
* @param side
* @param block
* @param meta
* @return
*/
public static boolean performTrigger(World world, ItemStack wand, EntityPlayer player,
int x, int y, int z, int side, Block block, int meta) {
List l = triggers.get(Arrays.asList(block,meta));
if (l == null) l = triggers.get(Arrays.asList(block,-1));
if (l == null) return false;
IWandTriggerManager manager = (IWandTriggerManager) l.get(0);
int event = (Integer) l.get(1);
return manager.performTrigger(world, wand, player, x, y, z, side, event);
}
}
@@ -5,20 +5,8 @@ import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.IFuelHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.EntityRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.oredict.OreDictionary;
import chylex.hee.api.HeeIMC;
import chylex.hee.block.BlockDragonEggCustom;
import chylex.hee.block.BlockEnderGoo;
import chylex.hee.block.BlockList;
@@ -33,6 +21,7 @@ import chylex.hee.entity.boss.EntityBossDragon;
import chylex.hee.entity.boss.EntityBossEnderDemon;
import chylex.hee.entity.boss.EntityMiniBossEnderEye;
import chylex.hee.entity.boss.EntityMiniBossFireFiend;
import chylex.hee.entity.boss.dragon.managers.DragonChunkManager;
import chylex.hee.entity.item.EntityItemAltar;
import chylex.hee.entity.item.EntityItemDragonEgg;
import chylex.hee.entity.item.EntityItemEndPowder;
@@ -75,12 +64,12 @@ import chylex.hee.gui.core.GuiHandler;
import chylex.hee.item.ItemList;
import chylex.hee.mechanics.MiscEvents;
import chylex.hee.mechanics.RecipeList;
import chylex.hee.mechanics.causatum.CausatumEvents;
import chylex.hee.mechanics.charms.handler.CharmPouchHandler;
import chylex.hee.mechanics.compendium.KnowledgeRegistrations;
import chylex.hee.mechanics.compendium.events.CompendiumEvents;
import chylex.hee.mechanics.curse.CurseEvents;
import chylex.hee.mechanics.energy.EnergyEvents;
import chylex.hee.mechanics.infestation.InfestationEvents;
import chylex.hee.mechanics.misc.PlayerDataHandler;
import chylex.hee.mechanics.misc.PlayerTransportBeacons;
import chylex.hee.mechanics.misc.TempleEvents;
@@ -120,6 +109,22 @@ import chylex.hee.tileentity.TileEntityTransportBeacon;
import chylex.hee.tileentity.TileEntityVoidChest;
import chylex.hee.world.DimensionOverride;
import chylex.hee.world.loot.WorldLoot;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.IFuelHandler;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLInterModComms.IMCEvent;
import cpw.mods.fml.common.event.FMLInterModComms.IMCMessage;
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
@Mod(modid = "HardcoreEnderExpansion", name = "Hardcore Ender Expansion", version = "", useMetadata = true, guiFactory = "chylex.hee.gui.core.ModGuiFactory")
public class HardcoreEnderExpansion{
@@ -135,7 +140,7 @@ public class HardcoreEnderExpansion{
@SidedProxy(clientSide = "chylex.hee.proxy.NotificationClientProxy", serverSide = "chylex.hee.proxy.NotificationCommonProxy")
public static NotificationCommonProxy notifications;
public static final int buildId = 18_91_15_0;
public static final int buildId = 22_92_15_0;
public static String modVersion;
public static String configPath;
@@ -208,11 +213,11 @@ public class HardcoreEnderExpansion{
Stopwatch.time("PreInitEvent - entities");
EntityList.stringToClassMapping.remove("Enderman");
EntityList.idToClassMapping.remove(Integer.valueOf(58));
EntityList.IDtoClassMapping.remove(Integer.valueOf(58));
EntityList.addMapping(EntityMobEnderman.class, "Enderman", 58);
EntityList.stringToClassMapping.remove("EnderCrystal");
EntityList.idToClassMapping.remove(Integer.valueOf(200));
EntityList.IDtoClassMapping.remove(Integer.valueOf(200));
EntityList.addMapping(EntityBlockEnderCrystal.class, "EnderCrystal", 200);
EntityRegistry.registerModEntity(EntityBossDragon.class, "Dragon", 8, this, 320, 1, true);
@@ -313,13 +318,15 @@ public class HardcoreEnderExpansion{
VoidChestEvents.register();
EnergyEvents.register();
TempleEvents.register();
InfestationEvents.register();
CurseEvents.register();
CausatumEvents.register();
PlayerTransportBeacons.register();
DragonChunkManager.register();
Stopwatch.finish("PreInitEvent - events");
proxy.registerSidedEvents();
proxy.registerRenderers();
notifications.register();
Stopwatch.finish("PreInitEvent");
@@ -328,14 +335,11 @@ public class HardcoreEnderExpansion{
@EventHandler
public void onInit(FMLInitializationEvent e){
Stopwatch.time("InitEvent");
proxy.registerRenderers();
PacketPipeline.initializePipeline();
NetworkRegistry.INSTANCE.registerGuiHandler(this,GuiHandler.instance);
RecipeList.addRecipes();
WorldLoot.registerWorldLoot();
KnowledgeRegistrations.initialize();
Stopwatch.finish("InitEvent");
}
@@ -344,6 +348,8 @@ public class HardcoreEnderExpansion{
public void onPostInit(FMLPostInitializationEvent e){
Stopwatch.time("PostInitEvent");
HeeIMC.runPostInit();
KnowledgeRegistrations.initialize();
OrbAcquirableItems.initialize();
OrbSpawnableMobs.initialize();
ModIntegrationManager.integrateMods();
@@ -351,6 +357,21 @@ public class HardcoreEnderExpansion{
Stopwatch.finish("PostInitEvent");
}
@EventHandler
public void onLoadComplete(FMLLoadCompleteEvent e){
Stopwatch.time("LoadCompleteEvent");
try{
DimensionOverride.verifyIntegrity();
HeeIMC.runLoadComplete();
}
catch(Throwable t){
FMLCommonHandler.instance().raiseException(t,"Critical error handling post-load data.",true);
}
Stopwatch.finish("LoadCompleteEvent");
}
@EventHandler
public void onServerStarting(FMLServerStartingEvent e){
@@ -358,4 +379,9 @@ public class HardcoreEnderExpansion{
e.registerServerCommand(new HeeBaconCommand());
e.registerServerCommand(new HeeDebugCommand());
}
@EventHandler
public void onIMC(IMCEvent e){
for(IMCMessage message:e.getMessages())HeeIMC.acceptIMC(message);
}
}
@@ -1,9 +1,10 @@
package chylex.hee.api;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.LoaderState;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.LoaderState;
@Deprecated
public class AbstractAPI{
protected AbstractAPI(){}
public AbstractAPI(){}
protected final void validate(){
if (!Loader.instance().isInState(LoaderState.POSTINITIALIZATION))throw new IllegalStateException("Do not use HEE API outside post initialization!");
@@ -1,17 +1,22 @@
package chylex.hee.api;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier;
import net.minecraft.item.Item;
import chylex.hee.mechanics.misc.StardustDecomposition;
import chylex.hee.system.util.ItemPattern;
/**
* API for Stardust and Decomposition Table (uncrafting).
*/
@Deprecated
public final class DecompositionAPI extends AbstractAPI{
DecompositionAPI(){}
public DecompositionAPI(){}
/**
* Blacklists an item and all of its damage values in the Decomposition Table.
* @param item Item to be banned. To ban a block, use {@link net.minecraft.item.Item#getItemFromBlock(net.minecraft.block.Block) getItemFromBlock(Block)} to convert it.
*/
@Deprecated
public static void blacklistItem(Item item){
blacklistItem(item,-1);
}
@@ -21,16 +26,17 @@ public final class DecompositionAPI extends AbstractAPI{
* @param item Item to be banned. To ban a block, use {@link net.minecraft.item.Item#getItemFromBlock(net.minecraft.block.Block) getItemFromBlock(Block)} to convert it.
* @param blacklistedDamageValues Array of damage values to blacklist.
*/
@Deprecated
public static void blacklistItem(Item item, int...blacklistedDamageValues){
short[] damages = new short[blacklistedDamageValues.length];
for(int a = 0; a < blacklistedDamageValues.length; a++)damages[a] = (short)blacklistedDamageValues[a];
StardustDecomposition.addToBlacklist(item,damages);
UniqueIdentifier id = GameRegistry.findUniqueIdentifierFor(item);
StardustDecomposition.addToBlacklist(new ItemPattern().setItemName(id.modId,id.name).setDamageValues(blacklistedDamageValues));
}
/**
* Blacklists items by parsing a string, which follows the same syntax rules as decompositionBlackList in configuration - {@code http://hee.chylex.com/config}.
* @param data String to parse.
*/
@Deprecated
public static void blacklistItemFromString(String data){
StardustDecomposition.addFromString(data);
}
+5 -1
View File
@@ -8,8 +8,9 @@ import chylex.hee.mechanics.essence.handler.dragon.AltarItemRecipe;
/**
* API for Essences and Essence Altars.
*/
@Deprecated
public final class EssenceAPI extends AbstractAPI{
EssenceAPI(){}
public EssenceAPI(){}
/**
* Adds an item exchange recipe to the Dragon Essence Altar.
@@ -17,6 +18,7 @@ public final class EssenceAPI extends AbstractAPI{
* @param result Final ItemStack that is created after the exchange.
* @param cost Amount of Dragon Essence used, the final number may be lower if sockets are used.
*/
@Deprecated
public void addDragonItemRecipe(ItemStack source, ItemStack result, int cost){
validate();
DragonEssenceHandler.recipes.add(new AltarItemRecipe(source,result,cost));
@@ -26,6 +28,7 @@ public final class EssenceAPI extends AbstractAPI{
* Adds an item exchange recipe to the Dragon Essence Altar.
* @param recipe Custom instance of AltarItemRecipe to use.
*/
@Deprecated
public void addDragonItemRecipe(AltarItemRecipe recipe){
validate();
DragonEssenceHandler.recipes.add(recipe);
@@ -36,6 +39,7 @@ public final class EssenceAPI extends AbstractAPI{
* @param essenceType Type of essence.
* @return New ItemStack, or null if provided invalid value.
*/
@Deprecated
public ItemStack createEssenceItemStack(EssenceType essenceType){
validate();
if (essenceType == null || essenceType == EssenceType.INVALID)return null;
+10 -6
View File
@@ -1,34 +1,38 @@
package chylex.hee.api;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.LoaderState;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.LoaderState;
/**
* Main API class that contains and provides specific API instances.
* DO NOT USE, WILL BE REMOVED IN FAVOR OF http://hee-api.chylex.com/
*/
@Deprecated
public final class HeeAPI{
private static final EssenceAPI essenceAPI = new EssenceAPI();
private static final WorldAPI worldAPI = new WorldAPI();
private static final DecompositionAPI decompositionAPI = new DecompositionAPI();
/**
* @return API instance for Essences and Essence Altars.
* DO NOT USE, WILL BE REMOVED IN FAVOR OF http://hee-api.chylex.com/
*/
@Deprecated
public static EssenceAPI essence(){
validate();
return essenceAPI;
}
/**
* @return API instance for loot and new biomes in the End.
* DO NOT USE, WILL BE REMOVED IN FAVOR OF http://hee-api.chylex.com/
*/
@Deprecated
public static WorldAPI world(){
validate();
return worldAPI;
}
/**
* @return API instance for Stardust and Decomposition Table.
* DO NOT USE, WILL BE REMOVED IN FAVOR OF http://hee-api.chylex.com/
*/
@Deprecated
public static DecompositionAPI decomposition(){
validate();
return decompositionAPI;
+121
View File
@@ -0,0 +1,121 @@
package chylex.hee.api;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import chylex.hee.api.message.MessageRegistry;
import chylex.hee.api.message.utils.MessageLogger;
import chylex.hee.api.message.utils.RunEvent;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.LoaderState;
import cpw.mods.fml.common.event.FMLInterModComms.IMCMessage;
public class HeeIMC{
private static final Pattern patternKey = Pattern.compile("[^A-Za-z:]");
private static final Pattern patternFixJson = Pattern.compile("(?:\"(\\w+)?\":)");
private static final List<HeeMessage> cachedMessages = new ArrayList<>();
/**
* Runs IMC messages in the cache. Only handles messages that need to be ran in PostInit. Called internally from HEE.
*/
public static void runPostInit(){
if (!Loader.instance().isInState(LoaderState.POSTINITIALIZATION))throw new IllegalStateException("Invalid loader state, tried running PostInit IMC messages outside PostInit.");
MessageLogger.logState("Running PostInit IMC messages.");
runMessagesForEvent(RunEvent.POSTINIT);
}
/**
* Runs IMC messages in the cache. Called internally from HEE.
*/
public static void runLoadComplete(){
if (!Loader.instance().isInState(LoaderState.AVAILABLE))throw new IllegalStateException("Invalid loader state, tried running LoadComplete IMC messages outside LoadComplete.");
MessageLogger.logState("Running LoadComplete IMC messages.");
runMessagesForEvent(RunEvent.LOADCOMPLETE);
}
/**
* Runs IMC messages in the cache unsafely. Has to be called in LoadComplete or later.
*/
public static void runUnsafe(){
if (!Loader.instance().hasReachedState(LoaderState.AVAILABLE))throw new IllegalStateException("Invalid loader state, tried manually running IMC messages before LoadComplete.");
MessageLogger.logState("Running IMC messages unsafely from mod $0.",Loader.instance().activeModContainer().getModId()); // TODO try if this works
runMessagesForEvent(null);
}
/* === MESSAGE RUNNING === */
private static void runMessagesForEvent(RunEvent event){
for(Iterator<HeeMessage> iter = cachedMessages.iterator(); iter.hasNext();){
HeeMessage msg = iter.next();
if (MessageRegistry.canRunInEvent(msg.key,event)){
iter.remove();
MessageLogger.logRun("$0 || $1 $2",msg.modid,msg.key,msg.data);
MessageRegistry.runMessage(msg.key,msg.nbt);
}
}
}
/* === MESSAGE ACCEPTING === */
public static void acceptString(String sender, String fullNotation){
int colon = fullNotation.indexOf(' ');
if (colon == -1)MessageLogger.logError("Received incorrect IMC String message from $0. Cannot identify message key and contents. || $1",sender,fullNotation);
else acceptString(sender,fullNotation.substring(0,colon),fullNotation.substring(colon+1));
}
public static void acceptString(String sender, String key, String message){
NBTTagCompound nbt = jsonToNBT(sender,key,message);
if (nbt != null && checkKey(sender,key))cachedMessages.add(new HeeMessage(sender,key,message,nbt));
}
public static void acceptIMC(IMCMessage message){
NBTTagCompound nbt = null;
String data = "";
if (message.isNBTMessage()){
nbt = message.getNBTValue();
data = "NBT: "+nbt.toString();
}
else if (message.isStringMessage()){
if ((nbt = jsonToNBT(message.getSender(),message.key,message.getStringValue())) == null)return;
data = message.getStringValue();
}
else{
MessageLogger.logError("Received incorrect IMC message format from $0. Expected String or NBTTagCompound, got $1.",message.getSender(),message.getMessageType().getSimpleName());
return;
}
if (checkKey(message.getSender(),message.key))cachedMessages.add(new HeeMessage(message.getSender(),message.key,data,nbt));
}
/* === INTERNALS === */
private static boolean checkKey(String sender, String key){
if (patternKey.matcher(key).find()){
MessageLogger.logError("Received incorrect IMC message format from $0. Message key contains invalid characters, only letters and colons allowed. || $1",sender,key);
return false;
}
else return true;
}
private static NBTTagCompound jsonToNBT(String sender, String key, String value){
NBTTagCompound nbt = null;
try{
nbt = (NBTTagCompound)JsonToNBT.func_150315_a(patternFixJson.matcher(value).replaceAll("$1:"));
nbt.getId(); // throw NPE if null
}catch(NBTException | ClassCastException | NullPointerException e){
MessageLogger.logError("Received incorrect IMC String message from $0. Parse error: $1. || $2 $3",sender,e.getMessage(),key,value);
}
return nbt;
}
}
@@ -0,0 +1,16 @@
package chylex.hee.api;
import net.minecraft.nbt.NBTTagCompound;
public class HeeMessage{
public final String modid;
public final String key;
public final String data;
public final NBTTagCompound nbt;
HeeMessage(String modid, String key, String data, NBTTagCompound nbt){
this.modid = modid;
this.key = key;
this.data = data;
this.nbt = nbt;
}
}
+6 -1
View File
@@ -12,8 +12,9 @@ import chylex.hee.world.util.SpawnEntry;
/**
* API for manipulating with new biomes and loot.
*/
@Deprecated
public final class WorldAPI extends AbstractAPI{
WorldAPI(){}
public WorldAPI(){}
/**
* Adds a mob spawning entry to specified biome. List of existing entries is in javadoc of each {@link Biome}.
@@ -22,6 +23,7 @@ public final class WorldAPI extends AbstractAPI{
* @param maxAmount Maximum amount of mobs of this type that can exist on the island at one point in time.
* @param weight Weight of the spawn entry.
*/
@Deprecated
public static void addMobToBiome(Biome biome, Class<? extends EntityLiving> mobClass, int maxAmount, int weight){
SpawnEntry entry = new SpawnEntry(mobClass,maxAmount,weight);
@@ -41,6 +43,7 @@ public final class WorldAPI extends AbstractAPI{
* @param loot Type of loot to use.
* @return Instance of {@link chylex.hee.api.wrappers.LootList LootList}, or null if {@code loot} parameter is null.
*/
@Deprecated
public LootList getLootList(LootType loot){
switch(loot){
case DungeonTowerRegular: return new LootList(ComponentTower.lootTower);
@@ -53,6 +56,7 @@ public final class WorldAPI extends AbstractAPI{
/**
* List of biomes that generate in the End.
*/
@Deprecated
public static enum Biome{
/**
* <strong>{@code Mob type, max amount, weight}</strong><br>
@@ -85,6 +89,7 @@ public final class WorldAPI extends AbstractAPI{
/**
* List of structures which generate loot inside them.
*/
@Deprecated
public static enum LootType{
/**
* Loot spawned inside chests, dispensers and similar containers in Dungeon Tower.
@@ -1,6 +0,0 @@
package chylex.hee.api.interfaces;
/**
* Ender Goo will not give bad effects to entities that implement this interface.
*/
public interface IIgnoreEnderGoo{}
@@ -0,0 +1,5 @@
package chylex.hee.api.message;
public abstract class MessageHandler{
public abstract void call(MessageRunner runner);
}
@@ -0,0 +1,31 @@
package chylex.hee.api.message;
import net.minecraft.nbt.NBTTagCompound;
import chylex.hee.api.message.element.base.Precondition;
import chylex.hee.api.message.element.base.PreconditionComposite;
import chylex.hee.api.message.utils.MessageLogger;
public final class MessagePattern{
private final PreconditionComposite<?> conditions = PreconditionComposite.noValue();
private final MessageHandler handler;
MessagePattern(MessageHandler handler){
this.handler = handler;
}
public MessagePattern addProp(String name, Precondition condition){
conditions.addCondition(name,condition);
return this;
}
boolean tryRun(NBTTagCompound root){
if (!conditions.checkType(root)){
MessageLogger.logError("Unexpected message format, expected NBTTagCompound, got $0 || $1",root.getClass().getSimpleName(),root);
return false;
}
if (!conditions.checkValue(root))return false;
handler.call(new MessageRunner(conditions,root));
return true;
}
}
@@ -0,0 +1,45 @@
package chylex.hee.api.message;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.nbt.NBTTagCompound;
import chylex.hee.api.message.handlers.ImcHandler;
import chylex.hee.api.message.utils.MessageLogger;
import chylex.hee.api.message.utils.RunEvent;
import com.google.common.collect.ImmutableMap;
public final class MessageRegistry{
private static Map<String,MessagePattern> registry;
private static Map<String,RunEvent> events;
public static MessagePattern register(String key, MessageHandler handler, RunEvent event){
MessagePattern pattern = new MessagePattern(handler);
if (registry.put(key,pattern) != null)throw new IllegalArgumentException("Cannot register duplicate IMC message key: "+key);
events.put(key,event);
return pattern;
}
public static boolean runMessage(String key, NBTTagCompound root){
MessagePattern pattern = registry.get(key);
if (pattern == null){
MessageLogger.logError("Message key not found: $0",key);
return false;
}
return pattern.tryRun(root);
}
public static boolean canRunInEvent(String key, RunEvent event){
return events.get(key) == event || event == null;
}
static{
registry = new HashMap<>();
events = new HashMap<>();
ImcHandler.loadHandlers();
registry = ImmutableMap.copyOf(registry);
events = ImmutableMap.copyOf(events);
}
private MessageRegistry(){}
}
@@ -0,0 +1,39 @@
package chylex.hee.api.message;
import net.minecraft.nbt.NBTTagCompound;
import chylex.hee.api.message.element.base.Precondition;
import chylex.hee.api.message.element.base.PreconditionComposite;
public final class MessageRunner{
private final PreconditionComposite<?> pattern;
private final NBTTagCompound root;
public MessageRunner(PreconditionComposite<?> pattern, NBTTagCompound root){
this.pattern = pattern;
this.root = root;
}
public final <R> R getValue(String property){
Precondition<R> condition = pattern.getCondition(property);
return condition.getValue(root.getTag(property));
}
public final String getString(String property){
return pattern.<String>getCondition(property).getValue(root.getTag(property));
}
public final int getInt(String property){
return pattern.<Integer>getCondition(property).getValue(root.getTag(property)).intValue();
}
public final double getDouble(String property){
return pattern.<Double>getCondition(property).getValue(root.getTag(property)).doubleValue();
}
public final int[] getIntArray(String property){
return pattern.<int[]>getCondition(property).getValue(root.getTag(property));
}
public final boolean getBool(String property){
return pattern.<Boolean>getCondition(property).getValue(root.getTag(property)).booleanValue();
}
}
@@ -0,0 +1,28 @@
package chylex.hee.api.message.element;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTBase.NBTPrimitive;
import net.minecraftforge.common.util.Constants.NBT;
import chylex.hee.api.message.element.base.Precondition;
public class BoolValue extends Precondition<Boolean>{
public static final BoolValue any(){
return new BoolValue();
}
private BoolValue(){}
@Override
public boolean checkType(NBTBase tag){
return tag != null && tag.getId() == NBT.TAG_BYTE;
}
@Override
public boolean checkValue(NBTBase tag){
return true;
}
@Override
public Boolean getValue(NBTBase tag){
return Boolean.valueOf(((NBTPrimitive)tag).func_150290_f() == 1);
}
}
@@ -0,0 +1,42 @@
package chylex.hee.api.message.element;
import chylex.hee.api.message.element.base.Precondition;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTBase.NBTPrimitive;
import net.minecraftforge.common.util.Constants.NBT;
public class DecimalValue extends Precondition<Double>{
public static final DecimalValue any(){
return new DecimalValue(Double.MIN_VALUE,Double.MAX_VALUE);
}
public static final DecimalValue positiveOrZero(){
return new DecimalValue(0,Double.MAX_VALUE);
}
public static final DecimalValue negativeOrZero(){
return new DecimalValue(Double.MIN_VALUE,0);
}
private double minValue, maxValue;
private DecimalValue(double minValue, double maxValue){
this.minValue = minValue;
this.maxValue = maxValue;
}
@Override
public boolean checkType(NBTBase tag){
return tag != null && (tag.getId() == NBT.TAG_INT || tag.getId() == NBT.TAG_BYTE || tag.getId() == NBT.TAG_SHORT || tag.getId() == NBT.TAG_LONG || tag.getId() == NBT.TAG_DOUBLE || tag.getId() == NBT.TAG_FLOAT);
}
@Override
public boolean checkValue(NBTBase tag){
double value = ((NBTPrimitive)tag).func_150286_g();
return value >= minValue && value <= maxValue;
}
@Override
public Double getValue(NBTBase tag){
return ((NBTPrimitive)tag).func_150286_g();
}
}
@@ -0,0 +1,62 @@
package chylex.hee.api.message.element;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagInt;
import net.minecraft.nbt.NBTTagIntArray;
import net.minecraftforge.common.util.Constants.NBT;
import chylex.hee.api.message.element.base.Precondition;
public abstract class IntArrayValue extends Precondition<int[]>{
public static final IntArrayValue any(){
return new IntArrayValueAny();
}
public static final IntArrayValue condition(Precondition<Integer> condition){
return new IntArrayValueCondition(condition,IntValue.any());
}
public static final IntArrayValue condition(Precondition<Integer> condition, Precondition<Integer> elementCount){
return new IntArrayValueCondition(condition,elementCount);
}
IntArrayValue(){}
@Override
public final boolean checkType(NBTBase tag){
return tag != null && tag.getId() == NBT.TAG_INT_ARRAY;
}
@Override
public final int[] getValue(NBTBase tag){
return ((NBTTagIntArray)tag).func_150302_c();
}
private static class IntArrayValueAny extends IntArrayValue{
IntArrayValueAny(){}
@Override
public boolean checkValue(NBTBase tag){
return true;
}
}
private static class IntArrayValueCondition extends IntArrayValue{
private final Precondition<Integer> condition;
private final Precondition<Integer> elementCount;
IntArrayValueCondition(Precondition<Integer> condition, Precondition<Integer> elementCount){
this.condition = condition;
this.elementCount = elementCount;
}
@Override
public boolean checkValue(NBTBase tag){
if (!elementCount.checkValue(new NBTTagInt(getValue(tag).length)))return false;
for(int value:getValue(tag)){
if (!condition.checkValue(new NBTTagInt(value)))return false;
}
return true;
}
}
}
@@ -0,0 +1,54 @@
package chylex.hee.api.message.element;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTBase.NBTPrimitive;
import net.minecraftforge.common.util.Constants.NBT;
import chylex.hee.api.message.element.base.Precondition;
public class IntValue extends Precondition<Integer>{
public static final IntValue any(){
return new IntValue(Integer.MIN_VALUE,Integer.MAX_VALUE);
}
public static final IntValue positive(){
return new IntValue(1,Integer.MAX_VALUE);
}
public static final IntValue negative(){
return new IntValue(Integer.MIN_VALUE,-1);
}
public static final IntValue positiveOrZero(){
return new IntValue(0,Integer.MAX_VALUE);
}
public static final IntValue negativeOrZero(){
return new IntValue(Integer.MIN_VALUE,0);
}
public static final IntValue range(int minValue, int maxValue){
return new IntValue(minValue,maxValue);
}
private int minValue, maxValue;
private IntValue(int minValue, int maxValue){
this.minValue = minValue;
this.maxValue = maxValue;
}
@Override
public boolean checkType(NBTBase tag){
return tag != null && (tag.getId() == NBT.TAG_INT || tag.getId() == NBT.TAG_BYTE || tag.getId() == NBT.TAG_SHORT || tag.getId() == NBT.TAG_LONG);
}
@Override
public boolean checkValue(NBTBase tag){
int value = ((NBTPrimitive)tag).func_150287_d();
return value >= minValue && value <= maxValue;
}
@Override
public Integer getValue(NBTBase tag){
return ((NBTPrimitive)tag).func_150287_d();
}
}
@@ -0,0 +1,26 @@
package chylex.hee.api.message.element;
import net.minecraft.item.Item;
import chylex.hee.api.message.MessageRunner;
import chylex.hee.api.message.element.base.Optional;
import chylex.hee.api.message.element.base.PreconditionComposite;
import chylex.hee.system.util.ItemDamagePair;
public class ItemDamagePairValue extends PreconditionComposite<ItemDamagePair>{
public static final ItemDamagePairValue any(){
return new ItemDamagePairValue();
}
private ItemDamagePairValue(){
addCondition("id",ItemStackValue.itemString);
addCondition("damage",Optional.of(IntValue.any(),-1));
}
@Override
public ItemDamagePair getValue(MessageRunner runner){
Item item = ItemStackValue.getItemFromString("id");
if (item == null)throw new IllegalStateException("Failed constructing an ItemDamagePair from IMC, item is null.");
int damage = runner.getInt("damage");
return new ItemDamagePair(item,damage < 0 ? -1 : damage);
}
}
@@ -0,0 +1,26 @@
package chylex.hee.api.message.element;
import net.minecraft.nbt.NBTTagCompound;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.Pair;
import chylex.hee.api.message.MessageRunner;
import chylex.hee.api.message.element.base.Optional;
import chylex.hee.api.message.element.base.PreconditionComposite;
import chylex.hee.system.util.ItemPattern;
public class ItemPatternValue extends PreconditionComposite<ItemPattern>{
public static final ItemPatternValue any(){
return new ItemPatternValue();
}
private ItemPatternValue(){
addCondition("id",StringValue.any());
addCondition("damage",Optional.of(IntArrayValue.condition(IntValue.range(0,Short.MAX_VALUE)),ArrayUtils.EMPTY_INT_ARRAY));
addCondition("tag",Optional.of(NbtValue.any(),new NBTTagCompound()));
}
@Override
public ItemPattern getValue(MessageRunner runner){
Pair<String,String> name = ItemStackValue.parseItemName(runner.getString("id"));
return new ItemPattern().setItemName(name.getLeft(),name.getRight()).setDamageValues(runner.getIntArray("damage")).setNBT(runner.<NBTTagCompound>getValue("tag"));
}
}
@@ -0,0 +1,70 @@
package chylex.hee.api.message.element;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import org.apache.commons.lang3.tuple.Pair;
import chylex.hee.api.message.MessageRunner;
import chylex.hee.api.message.element.base.Optional;
import chylex.hee.api.message.element.base.PreconditionComposite;
import com.google.common.base.Function;
import cpw.mods.fml.common.registry.GameRegistry;
public class ItemStackValue extends PreconditionComposite<ItemStack>{
public static final ItemStackValue any(){
return new ItemStackValue();
}
public static final StringValue itemString = StringValue.function(new Function<String,Boolean>(){
@Override
public Boolean apply(String input){
return Boolean.valueOf(getItemFromString(input) != null);
}
});
public static final Pair<String,String> parseItemName(String fullName){
String modid = "minecraft", name = "";
int colon = fullName.indexOf(':');
if (colon == -1)name = fullName;
else{
modid = fullName.substring(0,colon);
name = fullName.substring(colon+1);
if (modid.equals("~hee"))modid = "HardcoreEnderExpansion";
}
return Pair.of(modid,name);
}
public static final Item getItemFromString(String input){
Block block = null;
Item item = null;
Pair<String,String> name = parseItemName(input);
if ((item = GameRegistry.findItem(name.getLeft(),name.getRight())) != null)return item;
else if ((block = GameRegistry.findBlock(name.getLeft(),name.getRight())) != null)return Item.getItemFromBlock(block);
else return null;
}
private ItemStackValue(){
addCondition("id",itemString);
addCondition("damage",Optional.of(IntValue.range(0,Short.MAX_VALUE),0));
addCondition("count",Optional.of(IntValue.range(1,64),1));
addCondition("tag",Optional.of(NbtValue.any(),new NBTTagCompound()));
}
@Override
public ItemStack getValue(MessageRunner runner){
ItemStack is = new ItemStack(getItemFromString(runner.getString("id")));
if (is.getItem() == null)throw new IllegalStateException("Failed constructing an ItemStack from IMC, item is null.");
is.setItemDamage(runner.getInt("damage"));
is.stackSize = runner.getInt("count");
NBTTagCompound tag = runner.<NBTTagCompound>getValue("tag");
if (!tag.hasNoTags())is.stackTagCompound = tag;
return is;
}
}
@@ -0,0 +1,47 @@
package chylex.hee.api.message.element;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.common.util.Constants.NBT;
import chylex.hee.api.message.element.base.Precondition;
public class ListValue<T> extends Precondition<List<T>>{
public static final ListValue<String> strings(Precondition<String> condition){
return new ListValue<String>(NBT.TAG_STRING,condition);
}
public static final ListValue<NBTTagCompound> tags(Precondition<NBTTagCompound> condition){
return new ListValue<NBTTagCompound>(NBT.TAG_COMPOUND,condition);
}
private final byte tagType;
private final Precondition<T> condition;
ListValue(int arrayType, Precondition<T> condition){
this.tagType = (byte)arrayType;
this.condition = condition;
}
@Override
public boolean checkType(NBTBase tag){
return tag != null && tag.getId() == NBT.TAG_LIST && ((NBTTagList)tag).func_150303_d() == tagType;
}
@Override
public boolean checkValue(NBTBase tag){
for(NBTBase element:(List<NBTBase>)((NBTTagList)tag).tagList){
if (!condition.checkType(element) || !condition.checkValue(element))return false;
}
return true;
}
@Override
public List<T> getValue(NBTBase tag){
List<T> elements = new ArrayList<>();
for(NBTBase element:(List<NBTBase>)((NBTTagList)tag).tagList)elements.add(condition.getValue(tag));
return elements;
}
}
@@ -0,0 +1,28 @@
package chylex.hee.api.message.element;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.util.Constants.NBT;
import chylex.hee.api.message.element.base.Precondition;
public class NbtValue extends Precondition<NBTTagCompound>{
public static final NbtValue any(){
return new NbtValue();
}
private NbtValue(){}
@Override
public boolean checkType(NBTBase tag){
return tag != null && tag.getId() == NBT.TAG_COMPOUND;
}
@Override
public boolean checkValue(NBTBase tag){
return true;
}
@Override
public NBTTagCompound getValue(NBTBase tag){
return (NBTTagCompound)tag;
}
}
@@ -0,0 +1,69 @@
package chylex.hee.api.message.element;
import java.util.Arrays;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagString;
import net.minecraftforge.common.util.Constants.NBT;
import org.apache.commons.lang3.ArrayUtils;
import chylex.hee.api.message.element.base.Precondition;
import com.google.common.base.Function;
public abstract class StringValue extends Precondition<String>{
public static StringValue any(){
return new StringValueAny();
}
public static StringValue one(String...validValues){
return new StringValueArray(validValues);
}
public static StringValue function(Function<String,Boolean> checkFunction){
return new StringValueFunction(checkFunction);
}
private StringValue(){}
@Override
public final boolean checkType(NBTBase tag){
return tag != null && tag.getId() == NBT.TAG_STRING;
}
@Override
public final String getValue(NBTBase tag){
return ((NBTTagString)tag).func_150285_a_();
}
private static class StringValueAny extends StringValue{
StringValueAny(){}
@Override
public boolean checkValue(NBTBase tag){
return true;
}
}
private static class StringValueArray extends StringValue{
private final String[] values;
private StringValueArray(String[] values){
this.values = Arrays.copyOf(values,values.length);
}
@Override
public boolean checkValue(NBTBase tag){
return ArrayUtils.contains(values,getValue(tag));
}
}
private static class StringValueFunction extends StringValue{
private final Function<String,Boolean> checkFunction;
private StringValueFunction(Function<String,Boolean> checkFunction){
this.checkFunction = checkFunction;
}
@Override
public boolean checkValue(NBTBase tag){
return checkFunction.apply(getValue(tag)).booleanValue();
}
}
}
@@ -0,0 +1,37 @@
package chylex.hee.api.message.element;
import chylex.hee.api.message.MessageRunner;
import chylex.hee.api.message.element.base.Optional;
import chylex.hee.api.message.element.base.PreconditionComposite;
import chylex.hee.world.loot.LootItemStack;
public class WeightedLootValue extends PreconditionComposite<LootItemStack>{
public static final WeightedLootValue any(){
return new WeightedLootValue();
}
private WeightedLootValue(){
addCondition("id",ItemStackValue.itemString);
addCondition("damage",Optional.of(IntArrayValue.condition(IntValue.range(0,Short.MAX_VALUE),IntValue.range(1,2)),new int[]{ 0 }));
addCondition("count",Optional.of(IntArrayValue.condition(IntValue.range(1,64),IntValue.range(1,2)),new int[]{ 1 }));
addCondition("weight",IntValue.positive());
}
@Override
public LootItemStack getValue(MessageRunner runner){
LootItemStack item = new LootItemStack(ItemStackValue.getItemFromString(runner.getString("id")));
if (item.getItem() == null)throw new IllegalStateException("Failed constructing a LootItemStack (WeightedItem) from IMC, item is null.");
int[] damage = runner.getIntArray("damage");
if (damage.length == 2)item.setDamage(damage[0],damage[1]);
else item.setDamage(damage[0]);
int[] count = runner.getIntArray("damage");
if (count.length == 2)item.setAmount(count[0],count[1]);
else item.setAmount(count[0]);
item.setWeight(runner.getInt("weight"));
return item;
}
}
@@ -0,0 +1,31 @@
package chylex.hee.api.message.element.base;
import net.minecraft.nbt.NBTBase;
public class Optional<T> extends Precondition<T>{
public static final <T> Optional<T> of(Precondition<T> precondition, T defaultValue){
return new Optional<T>(precondition,defaultValue);
}
private final Precondition<T> precondition;
private final T defaultValue;
private Optional(Precondition<T> precondition, T defaultValue){
this.precondition = precondition;
this.defaultValue = defaultValue;
}
@Override
public boolean checkType(NBTBase tag){
return tag == null || precondition.checkType(tag);
}
@Override
public boolean checkValue(NBTBase tag){
return tag == null || precondition.checkValue(tag);
}
@Override
public T getValue(NBTBase tag){
return tag == null ? defaultValue : precondition.getValue(tag);
}
}
@@ -0,0 +1,16 @@
package chylex.hee.api.message.element.base;
import net.minecraft.nbt.NBTBase;
public abstract class Precondition<T>{
/**
* Checks whether a tag is valid. The tag can be null if it doesn't exist!
*/
public abstract boolean checkType(NBTBase tag);
/**
* Checks the contents of a tag. This only runs if checkType returns true.
*/
public abstract boolean checkValue(NBTBase tag);
public abstract T getValue(NBTBase tag);
}
@@ -0,0 +1,62 @@
package chylex.hee.api.message.element.base;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.util.Constants.NBT;
import chylex.hee.api.message.MessageRunner;
import chylex.hee.api.message.utils.MessageLogger;
public abstract class PreconditionComposite<T> extends Precondition<T>{
public static final PreconditionComposite<Object> noValue(){
return new PreconditionComposite<Object>(){
@Override
public Object getValue(MessageRunner runner){
return null;
}
};
}
private final Map<String,Precondition> conditions = new HashMap<>();
public final void addCondition(String property, Precondition condition){
conditions.put(property,condition);
}
public final <R> Precondition<R> getCondition(String property){
return conditions.get(property);
}
@Override
public final boolean checkType(NBTBase tag){
return tag != null && tag.getId() == NBT.TAG_COMPOUND;
}
@Override
public final boolean checkValue(NBTBase tag){
NBTTagCompound compound = (NBTTagCompound)tag;
for(Entry<String,Precondition> entry:conditions.entrySet()){
NBTBase compTag = compound.getTag(entry.getKey());
if (!entry.getValue().checkType(compTag)){
MessageLogger.logError("Incorrect type of tag $0. || $1",entry.getKey(),compTag == null ? "<null>" : (compTag.toString()+"/"+compTag.getId()));
return false;
}
else if (!entry.getValue().checkValue(compTag)){
MessageLogger.logError("Incorrect value for tag $0. || $1",entry.getKey(),compTag == null ? "<null>" : compTag.toString());
return false;
}
}
return true;
}
@Override
public final T getValue(NBTBase tag){
return getValue(new MessageRunner(this,(NBTTagCompound)tag));
}
public abstract T getValue(MessageRunner runner);
}
@@ -0,0 +1,71 @@
package chylex.hee.api.message.handlers;
import java.util.Iterator;
import net.minecraft.item.ItemStack;
import chylex.hee.api.message.MessageHandler;
import chylex.hee.api.message.MessageRunner;
import chylex.hee.api.message.element.IntValue;
import chylex.hee.api.message.element.ItemPatternValue;
import chylex.hee.api.message.element.ItemStackValue;
import chylex.hee.api.message.element.StringValue;
import chylex.hee.api.message.utils.MessageLogger;
import chylex.hee.api.message.utils.RunEvent;
import chylex.hee.mechanics.essence.handler.DragonEssenceHandler;
import chylex.hee.mechanics.essence.handler.dragon.AltarItemRecipe;
import chylex.hee.system.util.ItemPattern;
public final class ImcEssenceHandlers extends ImcHandler{
private static final MessageHandler dragonEssenceAdd = new MessageHandler(){
@Override
public void call(MessageRunner runner){
ItemStack input = runner.<ItemStack>getValue("input");
for(AltarItemRecipe recipe:DragonEssenceHandler.recipes){
if (ItemStack.areItemStacksEqual(recipe.input,input) && ItemStack.areItemStackTagsEqual(recipe.input,input)){
MessageLogger.logFail("Duplicate input item, ignoring.");
return;
}
}
DragonEssenceHandler.recipes.add(new AltarItemRecipe(input,runner.<ItemStack>getValue("output"),runner.getInt("cost")));
MessageLogger.logOk("Added 1 recipe.");
}
};
private static final MessageHandler dragonEssenceRemove = new MessageHandler(){
@Override
public void call(MessageRunner runner){
boolean input = runner.getString("type").equals("input");
ItemPattern pattern = runner.<ItemPattern>getValue("search");
int limit = runner.getInt("limit");
int size = DragonEssenceHandler.recipes.size();
for(Iterator<AltarItemRecipe> iter = DragonEssenceHandler.recipes.iterator(); iter.hasNext();){
AltarItemRecipe recipe = iter.next();
if (pattern.matches(input ? recipe.input : recipe.output)){
iter.remove();
if (limit > 0 && --limit == 0)break;
}
}
size = size-DragonEssenceHandler.recipes.size();
if (size == 0)MessageLogger.logWarn("Did not find any items to remove.");
else MessageLogger.logOk("Removed $0 item(s).",size);
}
};
@Override
public void register(){
register("HEE:DragonEssence:AddRecipe",dragonEssenceAdd,RunEvent.POSTINIT)
.addProp("input",ItemStackValue.any())
.addProp("output",ItemStackValue.any())
.addProp("cost",IntValue.positive());
register("HEE:DragonEssence:RemoveRecipe",dragonEssenceRemove,RunEvent.POSTINIT)
.addProp("type",StringValue.one("input","output"))
.addProp("search",ItemPatternValue.any())
.addProp("limit",IntValue.positiveOrZero());
}
}
@@ -0,0 +1,24 @@
package chylex.hee.api.message.handlers;
import chylex.hee.api.message.MessageHandler;
import chylex.hee.api.message.MessagePattern;
import chylex.hee.api.message.MessageRegistry;
import chylex.hee.api.message.utils.RunEvent;
public abstract class ImcHandler{
public static final void loadHandlers(){
ImcHandler[] handlers = new ImcHandler[]{
new ImcEssenceHandlers(),
new ImcMobHandlers(),
new ImcTableHandlers(),
new ImcWorldHandlers()
};
for(ImcHandler handler:handlers)handler.register();
}
protected final MessagePattern register(String key, MessageHandler handler, RunEvent event){
return MessageRegistry.register(key,handler,event);
}
public abstract void register();
}
@@ -0,0 +1,48 @@
package chylex.hee.api.message.handlers;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLivingBase;
import chylex.hee.api.message.MessageHandler;
import chylex.hee.api.message.MessageRunner;
import chylex.hee.api.message.element.DecimalValue;
import chylex.hee.api.message.element.StringValue;
import chylex.hee.api.message.utils.MessageLogger;
import chylex.hee.api.message.utils.RunEvent;
import chylex.hee.entity.GlobalMobData;
import chylex.hee.mechanics.energy.EnergyValues;
import com.google.common.base.Function;
public final class ImcMobHandlers extends ImcHandler{
private static final StringValue livingMobString = StringValue.function(new Function<String,Boolean>(){
@Override
public Boolean apply(String input){
Class<?> cls = (Class<?>)EntityList.stringToClassMapping.get(input);
return Boolean.valueOf(cls != null && EntityLivingBase.class.isAssignableFrom(cls));
}
});
private static final MessageHandler enderGooTolerantAdd = new MessageHandler(){
@Override
public void call(MessageRunner runner){
if (GlobalMobData.setEnderGooTolerant(runner.getString("id")))MessageLogger.logOk("Added 1 mob to the list.");
else MessageLogger.logFail("The mob was already in the list.");
}
};
private static final MessageHandler energySet = new MessageHandler(){
@Override
public void call(MessageRunner runner){
if (EnergyValues.setMobEnergy((Class<? extends EntityLivingBase>)EntityList.stringToClassMapping.get(runner.getString("id")),(float)runner.getDouble("units")))MessageLogger.logOk("Added 1 mob to the list.");
else MessageLogger.logFail("The mob was already in the list.");
}
};
@Override
public void register(){
register("HEE:Mobs:SetGooImmune",enderGooTolerantAdd,RunEvent.LOADCOMPLETE)
.addProp("id",livingMobString);
register("HEE:Mobs:SetEnergy",energySet,RunEvent.LOADCOMPLETE)
.addProp("id",livingMobString)
.addProp("units",DecimalValue.positiveOrZero());
}
}
@@ -0,0 +1,53 @@
package chylex.hee.api.message.handlers;
import chylex.hee.api.message.MessageHandler;
import chylex.hee.api.message.MessageRunner;
import chylex.hee.api.message.element.DecimalValue;
import chylex.hee.api.message.element.IntValue;
import chylex.hee.api.message.element.ItemDamagePairValue;
import chylex.hee.api.message.element.ItemPatternValue;
import chylex.hee.api.message.utils.MessageLogger;
import chylex.hee.api.message.utils.RunEvent;
import chylex.hee.mechanics.energy.EnergyValues;
import chylex.hee.mechanics.misc.StardustDecomposition;
import chylex.hee.system.util.ItemDamagePair;
import chylex.hee.system.util.ItemPattern;
import chylex.hee.tileentity.TileEntityExperienceTable;
public final class ImcTableHandlers extends ImcHandler{
private static final MessageHandler decompositionBlacklist = new MessageHandler(){
@Override
public void call(MessageRunner runner){
StardustDecomposition.addToBlacklist(runner.<ItemPattern>getValue("pattern"));
}
};
private static final MessageHandler energySet = new MessageHandler(){
@Override
public void call(MessageRunner runner){
if (EnergyValues.setItemEnergy(runner.<ItemDamagePair>getValue("item"),(float)runner.getDouble("units")))MessageLogger.logOk("Added 1 item to the list.");
else MessageLogger.logFail("The item was already in the list.");
}
};
private static final MessageHandler expTableAdd = new MessageHandler(){
@Override
public void call(MessageRunner runner){
if (TileEntityExperienceTable.addDirectConversion(runner.<ItemDamagePair>getValue("item"),(byte)runner.getInt("bottles")))MessageLogger.logOk("Added 1 item to the list.");
else MessageLogger.logFail("The item was already in the list.");
}
};
@Override
public void register(){
register("HEE:DecompositionTable:Blacklist",decompositionBlacklist,RunEvent.LOADCOMPLETE)
.addProp("pattern",ItemPatternValue.any());
register("HEE:ExtractionTable:SetEnergy",energySet,RunEvent.LOADCOMPLETE)
.addProp("item",ItemDamagePairValue.any())
.addProp("units",DecimalValue.positiveOrZero());
register("HEE:ExperienceTable:AddItem",expTableAdd,RunEvent.LOADCOMPLETE)
.addProp("item",ItemDamagePairValue.any())
.addProp("bottles",IntValue.range(1,64));
}
}
@@ -0,0 +1,69 @@
package chylex.hee.api.message.handlers;
import java.util.HashMap;
import java.util.Map;
import chylex.hee.api.message.MessageHandler;
import chylex.hee.api.message.MessageRunner;
import chylex.hee.api.message.element.StringValue;
import chylex.hee.api.message.element.WeightedLootValue;
import chylex.hee.api.message.utils.MessageLogger;
import chylex.hee.api.message.utils.RunEvent;
import chylex.hee.entity.block.EntityBlockHomelandCache;
import chylex.hee.world.loot.LootItemStack;
import chylex.hee.world.loot.WeightedLootList;
import chylex.hee.world.structure.island.biome.feature.forest.ravageddungeon.RavagedDungeonLoot;
import chylex.hee.world.structure.island.biome.feature.island.StructureHiddenCellar;
import chylex.hee.world.structure.island.biome.feature.island.laboratory.LaboratoryContent;
import chylex.hee.world.structure.tower.ComponentTower;
import com.google.common.base.Function;
public final class ImcWorldHandlers extends ImcHandler{
private static final Map<String,WeightedLootList> lootNames = new HashMap<>();
static{
lootNames.put("DungeonTowerChest",ComponentTower.lootTower);
lootNames.put("DungeonTowerFurnaceFuel",ComponentTower.lootFuel);
lootNames.put("RavagedDungeonGeneral",RavagedDungeonLoot.lootGeneral);
lootNames.put("RavagedDungeonUncommon",RavagedDungeonLoot.lootUncommon);
lootNames.put("RavagedDungeonRare",RavagedDungeonLoot.lootRare);
lootNames.put("RavagedDungeonFinalRoom",RavagedDungeonLoot.lootEnd);
lootNames.put("HiddenCellarNormalHomeland",StructureHiddenCellar.normalChestVariation[0]);
lootNames.put("HiddenCellarRareHomeland",StructureHiddenCellar.rareChestVariation[0]);
lootNames.put("HiddenCellarNormalLaboratory",StructureHiddenCellar.normalChestVariation[1]);
lootNames.put("HiddenCellarRareLaboratory",StructureHiddenCellar.rareChestVariation[1]);
lootNames.put("HomelandCache",EntityBlockHomelandCache.loot);
lootNames.put("LaboratorySmallChest",LaboratoryContent.smallChestLoot);
lootNames.put("LaboratoryLargeChest",LaboratoryContent.largeChestLoot);
}
private static final StringValue lootName = StringValue.function(new Function<String,Boolean>(){
@Override
public Boolean apply(String input){
return Boolean.valueOf(lootNames.containsKey(input));
}
});
private static final MessageHandler lootAdd = new MessageHandler(){
@Override
public void call(MessageRunner runner){
WeightedLootList list = lootNames.get(runner.getString("list"));
LootItemStack toAdd = runner.<LootItemStack>getValue("item");
for(LootItemStack item:list){
if (item.getItem() == toAdd.getItem()){
MessageLogger.logFail("The item was already in the list.");
return;
}
}
list.add(toAdd);
MessageLogger.logOk("Added 1 item to the list.");
}
};
@Override
public void register(){
register("HEE:World:LootAdd",lootAdd,RunEvent.LOADCOMPLETE)
.addProp("list",lootName)
.addProp("item",WeightedLootValue.any());
}
}
@@ -0,0 +1,37 @@
package chylex.hee.api.message.utils;
import chylex.hee.system.logging.Log;
public final class MessageLogger{
private static final String prefixState = "[HEE-IMC] [STATE] ";
private static final String prefixRun = "[HEE-IMC] [RUN] ";
private static final String prefixError = "[HEE-IMC] [ERROR] ";
private static final String prefixOk = "[HEE-IMC] [OK] ";
private static final String prefixWarn = "[HEE-IMC] [WARN] ";
private static final String prefixFail = "[HEE-IMC] [FAIL] ";
public static void logState(String message, Object...data){
Log.info(prefixState+message,data);
}
public static void logRun(String message, Object...data){
Log.info(prefixRun+message,data);
}
public static void logError(String message, Object...data){
Log.error(prefixError+message,data);
}
public static void logOk(String message, Object...data){
Log.info(prefixOk+message,data);
}
public static void logWarn(String message, Object...data){
Log.info(prefixWarn+message,data);
}
public static void logFail(String message, Object...data){
Log.info(prefixFail+message,data);
}
private MessageLogger(){}
}
@@ -0,0 +1,8 @@
package chylex.hee.api.message.utils;
/**
* Using null will make the message run only when manually calling unsafe run.
*/
public enum RunEvent{
POSTINIT, LOADCOMPLETE
}
@@ -8,6 +8,7 @@ import chylex.hee.world.loot.WeightedLootList;
/**
* A wrapper class for simplified access to weighted loot list.
*/
@Deprecated
public class LootList{
private final WeightedLootList wrappedCollection;
@@ -19,6 +20,7 @@ public class LootList{
* Adds new loot to the list.
* @param lootItemStack Instance of {@link chylex.hee.world.loot.LootItemStack LootItemStack} that holds basic generation properties.
*/
@Deprecated
public void addLoot(LootItemStack lootItemStack){
wrappedCollection.add(lootItemStack);
}
@@ -27,6 +29,7 @@ public class LootList{
* Adds a post processor to the list, using anonymous class is suggested.
* @param postProcessor Handler that will modify item right before it's placed into the container.
*/
@Deprecated
public void addPostProcessor(IItemPostProcessor postProcessor){
wrappedCollection.addItemPostProcessor(postProcessor);
}
@@ -36,6 +39,7 @@ public class LootList{
* @param item Item to remove.
* @return True if any item was removed.
*/
@Deprecated
public boolean removeItem(Item item){
for(Iterator<LootItemStack> iter = wrappedCollection.iterator(); iter.hasNext();){
if (iter.next().getItem() == item){
Loaded 100 of 625 files, more files were not shown because too many files have changed in this diff. Show more