WOOOOOOORDS

This commit is contained in:
Jeremy Diamond committed 2014-09-11 04:28:05 -07:00
1 parent 9ad63adf61
commit d53c041078
66 files changed
+6603 -28

No files matched your search

+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,536 @@
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 toolMatVoid = EnumHelper.addToolMaterial("VOID", 4, 150, 8F, 3, 10);
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);
public static ArmorMaterial armorMatThaumiumFortress = EnumHelper.addArmorMaterial("FORTRESS", 40, new int[] { 3, 7, 6, 3 }, 25);
public static ArmorMaterial armorMatVoid = EnumHelper.addArmorMaterial("VOID", 10, new int[] { 3, 7, 6, 3 }, 10);
public static ArmorMaterial armorMatVoidFortress = EnumHelper.addArmorMaterial("VOIDFORTRESS", 18, new int[] { 4, 8, 7, 4 }, 10);
//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
*/
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;
}
/**
* @param hash the unique recipe code
* @return the recipe
*/
public static CrucibleRecipe getCrucibleRecipeFromHash(int hash) {
for (Object r:getCraftingRecipes()) {
if (r instanceof CrucibleRecipe) {
if (((CrucibleRecipe)r).hash==hash)
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[]>();
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.recipe!=null && page.recipe instanceof CrucibleRecipe[]) {
CrucibleRecipe[] crs = (CrucibleRecipe[]) page.recipe;
for (CrucibleRecipe cr:crs) {
if (cr.getRecipeOutput().isItemEqual(stack)) {
keyCache.put(key,new Object[] {ri.key,a});
if (ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), ri.key))
return new Object[] {ri.key,a};
}
}
} else
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>
* IMPORTANT - this should only be used if you are not happy with the default aspects the object would be assigned.
* @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);
}
}
//WARP ///////////////////////////////////////////////////////////////////////////////////////
private static HashMap<Object,Integer> warpMap = new HashMap<Object,Integer>();
/**
* This method is used to determine how much warp is gained if the item is crafted
* @param craftresult The item crafted
* @param amount how much warp is gained
*/
public static void addWarpToItem(ItemStack craftresult, int amount) {
warpMap.put(Arrays.asList(craftresult.getItem(),craftresult.getItemDamage()),amount);
}
/**
* This method is used to determine how much warp is gained if the sent item is crafted
* @param in The item crafted
* @param amount how much warp is gained
*/
public static void addWarpToResearch(String research, int amount) {
warpMap.put(research, amount);
}
/**
* Returns how much warp is gained from the item or research passed in
* @param in itemstack or string
* @return how much warp it will give
*/
public static int getWarp(Object in) {
if (in==null) return 0;
if (in instanceof ItemStack && warpMap.containsKey(Arrays.asList(((ItemStack)in).getItem(),((ItemStack)in).getItemDamage()))) {
return warpMap.get(Arrays.asList(((ItemStack)in).getItem(),((ItemStack)in).getItemDamage()));
} else
if (in instanceof String && warpMap.containsKey((String)in)) {
return warpMap.get((String)in);
}
return 0;
}
//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,293 @@
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 {
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;
}
static Method addWarpToPlayer;
/**
* This adds permanents or temporary warp to a player. It will automatically be synced clientside
* @param player the player using the wand
* @param amount how much warp to add
* @param amount how much warp to add. Negative amounts are only valid for temporary warp
* @param temporary add temporary warp instead of permanent
* @param amount how much warp to add
*/
public static void addWarpToPlayer(EntityPlayer player, int amount, boolean temporary) {
boolean ot = false;
try {
if(addWarpToPlayer == null) {
Class fake = Class.forName("thaumcraft.common.Thaumcraft");
addWarpToPlayer = fake.getMethod("addWarpToPlayer",
EntityPlayer.class, int.class, boolean.class);
}
addWarpToPlayer.invoke(null, player, amount, temporary);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.Thaumcraft method addWarpToPlayer");
}
}
}
@@ -0,0 +1,63 @@
package thaumcraft.api;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
/**
*
* @author azanor
*
* Custom tile entity class I use for most of my tile entities. Setup in such a way that only
* the nbt data within readCustomNBT / writeCustomNBT will be sent to the client when the tile
* updates. Apart from all the normal TE data that gets sent that is.
*
*/
public class TileThaumcraft extends TileEntity {
//NBT stuff
@Override
public void readFromNBT(NBTTagCompound nbttagcompound)
{
super.readFromNBT(nbttagcompound);
readCustomNBT(nbttagcompound);
}
public void readCustomNBT(NBTTagCompound nbttagcompound)
{
//TODO
}
@Override
public void writeToNBT(NBTTagCompound nbttagcompound)
{
super.writeToNBT(nbttagcompound);
writeCustomNBT(nbttagcompound);
}
public void writeCustomNBT(NBTTagCompound nbttagcompound)
{
//TODO
}
//Client Packet stuff
@Override
public Packet getDescriptionPacket() {
NBTTagCompound nbttagcompound = new NBTTagCompound();
this.writeCustomNBT(nbttagcompound);
return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, -999, nbttagcompound);
}
@Override
public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) {
super.onDataPacket(net, pkt);
this.readCustomNBT(pkt.func_148857_g());
}
}
@@ -0,0 +1,117 @@
package thaumcraft.api;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
public class WorldCoordinates implements Comparable
{
public int x;
/** the y coordinate */
public int y;
/** the z coordinate */
public int z;
public int dim;
public WorldCoordinates() {}
public WorldCoordinates(int par1, int par2, int par3, int d)
{
this.x = par1;
this.y = par2;
this.z = par3;
this.dim = d;
}
public WorldCoordinates(TileEntity tile)
{
this.x = tile.xCoord;
this.y = tile.yCoord;
this.z = tile.zCoord;
this.dim = tile.getWorldObj().provider.dimensionId;
}
public WorldCoordinates(WorldCoordinates par1ChunkCoordinates)
{
this.x = par1ChunkCoordinates.x;
this.y = par1ChunkCoordinates.y;
this.z = par1ChunkCoordinates.z;
this.dim = par1ChunkCoordinates.dim;
}
public boolean equals(Object par1Obj)
{
if (!(par1Obj instanceof WorldCoordinates))
{
return false;
}
else
{
WorldCoordinates coordinates = (WorldCoordinates)par1Obj;
return this.x == coordinates.x && this.y == coordinates.y && this.z == coordinates.z && this.dim == coordinates.dim ;
}
}
public int hashCode()
{
return this.x + this.y << 8 + this.z << 16 + this.dim << 24;
}
/**
* Compare the coordinate with another coordinate
*/
public int compareWorldCoordinate(WorldCoordinates par1)
{
return this.dim == par1.dim ? (
this.y == par1.y ? (this.z == par1.z ? this.x - par1.x : this.z - par1.z) : this.y - par1.y) : -1;
}
public void set(int par1, int par2, int par3, int d)
{
this.x = par1;
this.y = par2;
this.z = par3;
this.dim = d;
}
/**
* Returns the squared distance between this coordinates and the coordinates given as argument.
*/
public float getDistanceSquared(int par1, int par2, int par3)
{
float f = (float)(this.x - par1);
float f1 = (float)(this.y - par2);
float f2 = (float)(this.z - par3);
return f * f + f1 * f1 + f2 * f2;
}
/**
* Return the squared distance between this coordinates and the ChunkCoordinates given as argument.
*/
public float getDistanceSquaredToWorldCoordinates(WorldCoordinates par1ChunkCoordinates)
{
return this.getDistanceSquared(par1ChunkCoordinates.x, par1ChunkCoordinates.y, par1ChunkCoordinates.z);
}
public int compareTo(Object par1Obj)
{
return this.compareWorldCoordinate((WorldCoordinates)par1Obj);
}
public void readNBT(NBTTagCompound nbt) {
this.x = nbt.getInteger("w_x");
this.y = nbt.getInteger("w_y");
this.z = nbt.getInteger("w_z");
this.dim = nbt.getInteger("w_d");
}
public void writeNBT(NBTTagCompound nbt) {
nbt.setInteger("w_x",x);
nbt.setInteger("w_y",y);
nbt.setInteger("w_z",z);
nbt.setInteger("w_d",dim);
}
}
@@ -0,0 +1,201 @@
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,256 @@
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 = (NBTTagCompound) 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,58 @@
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,37 @@
package thaumcraft.api.aspects;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
/**
*
* @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,103 @@
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 int hash;
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);
}
String hc = researchKey + result.toString();
for (Aspect tag:tags.getAspects()) {
hc += tag.getTag()+tags.getAmount(tag);
}
hc += cat.hashCode();
hash = hc.hashCode();
}
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) {
ItemStack[] ores = ((ArrayList<ItemStack>)catalyst).toArray(new ItemStack[]{});
if (!ThaumcraftApiHelper.containsMatch(false, new ItemStack[]{cat},ores)) 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) {
ItemStack[] ores = ((ArrayList<ItemStack>)catalyst).toArray(new ItemStack[]{});
if (ThaumcraftApiHelper.containsMatch(false, new ItemStack[]{cat},ores)) 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;
}
// @Override
// public int hashCode() {
// String hash = "";
// if (catalyst instanceof ItemStack) {
// hash += ((ItemStack)catalyst).toString();
// } else if (catalyst instanceof ArrayList && ((ArrayList<ItemStack>)catalyst).size()>0) {
// for (ItemStack s:(ArrayList<ItemStack>)catalyst) {
// hash += s.toString();
// }
// } else {
// hash += catalyst.hashCode();
// }
// hash += getRecipeOutput().toString();
// for (Aspect a:aspects.getAspectsSorted()) {
// hash += a.getTag() + aspects.getAmount(a);
// }
// return hash.hashCode();
// }
}
@@ -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;
}
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;
}
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,261 @@
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,157 @@
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,32 @@
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);
}
public DamageSource setFireDamage()
{
this.fireDamage = true;
return this;
}
public DamageSource setDamageBypassesArmor()
{
this.isUnblockable = true;
this.hungerDamage = 0.0F;
return this;
}
}
@@ -0,0 +1,47 @@
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");
public static DamageSource dissolve = new DamageSourceThaumcraft("dissolve").setDamageBypassesArmor();
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,4 @@
@API(owner = "Thaumcraft", apiVersion = "4.2.0.0", provides = "Thaumcraft|API")
package thaumcraft.api;
import cpw.mods.fml.common.API;
@@ -0,0 +1,67 @@
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();
}
static final 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);
}
}
public boolean isReady(int par1, int par2)
{
int k = 40 >> par2;
return k > 0 ? par1 % k == 0 : true;
}
}
@@ -0,0 +1,48 @@
package thaumcraft.api.potions;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.potion.Potion;
import net.minecraft.util.ResourceLocation;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class PotionVisExhaust extends Potion
{
public static PotionVisExhaust instance = null; // will be instantiated at runtime
private int statusIconIndex = -1;
public PotionVisExhaust(int par1, boolean par2, int par3)
{
super(par1,par2,par3);
setIconIndex(0, 0);
}
public static void init()
{
instance.setPotionName("potion.visexhaust");
instance.setIconIndex(5, 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();
}
static final ResourceLocation rl = new ResourceLocation("thaumcraft","textures/misc/potions.png");
@Override
public void performEffect(EntityLivingBase target, int par2) {
}
}
@@ -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,101 @@
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,37 @@
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,193 @@
package thaumcraft.api.research;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
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,
SMELTING
}
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 arcane crafting recipes.
*/
public ResearchPage(CrucibleRecipe[] recipe) {
this.type = PageType.CRUCIBLE_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 a furnace smelting crafting recipe.
*/
public ResearchPage(ItemStack input) {
this.type = PageType.SMELTING;
this.recipe = input;
this.recipeOutput = FurnaceRecipes.smelting().getSmeltingResult(input);
}
/**
* @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,39 @@
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;
}
}
@@ -0,0 +1,188 @@
package thaumcraft.api.visnet;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import thaumcraft.api.TileThaumcraft;
import thaumcraft.api.WorldCoordinates;
import thaumcraft.api.aspects.Aspect;
/**
* @author Azanor
*
* The tile entity used by nodes in the vis energy network. A node is either a source (like an aura node),
* a transport relay or vis receiver (like the infernal furnace).
*
*/
public abstract class TileVisNode extends TileThaumcraft {
WeakReference<TileVisNode> parent = null;
ArrayList<WeakReference<TileVisNode>> children = new ArrayList<WeakReference<TileVisNode>>();
/**
* @return the WorldCoordinates location of where this node is located
*/
public WorldCoordinates getLocation() {
return new WorldCoordinates(this);
}
/**
* @return the number of blocks away this node will check for parent nodes to connect to.
*/
public abstract int getRange();
/**
* @return true if this is the source or root node of the vis network.
*/
public abstract boolean isSource();
/**
* This method should never be called directly. Use VisNetHandler.drainVis() instead
* @param aspect what aspect to drain
* @param vis how much to drain
* @return how much was actually drained
*/
public int consumeVis(Aspect aspect, int vis) {
if (VisNetHandler.isNodeValid(getParent())) {
int out = getParent().get().consumeVis(aspect, vis);
if (out>0) {
triggerConsumeEffect(aspect);
}
return out;
}
return 0;
}
public void removeThisNode() {
for (WeakReference<TileVisNode> n:getChildren()) {
if (n!=null && n.get()!=null) {
n.get().removeThisNode();
}
}
children = new ArrayList<WeakReference<TileVisNode>>();
if (VisNetHandler.isNodeValid(this.getParent())) {
this.getParent().get().nodeRefresh=true;
}
this.setParent(null);
this.parentChanged();
if (this.isSource()) {
HashMap<WorldCoordinates, WeakReference<TileVisNode>> sourcelist = VisNetHandler.sources.get(worldObj.provider.dimensionId);
if (sourcelist==null) {
sourcelist = new HashMap<WorldCoordinates, WeakReference<TileVisNode>>();
}
sourcelist.remove(getLocation());
VisNetHandler.sources.put( worldObj.provider.dimensionId, sourcelist );
}
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
@Override
public void invalidate() {
removeThisNode();
super.invalidate();
}
public void triggerConsumeEffect(Aspect aspect) { }
/**
* @return
*/
public WeakReference<TileVisNode> getParent() {
return parent;
}
/**
* @return
*/
public WeakReference<TileVisNode> getRootSource() {
return VisNetHandler.isNodeValid(getParent()) ?
getParent().get().getRootSource() : this.isSource() ?
new WeakReference(this) : null;
}
/**
* @param parent
*/
public void setParent(WeakReference<TileVisNode> parent) {
this.parent = parent;
}
/**
* @return
*/
public ArrayList<WeakReference<TileVisNode>> getChildren() {
return children;
}
@Override
public boolean canUpdate() {
return true;
}
protected int nodeCounter = 0;
private boolean nodeRegged = false;
public boolean nodeRefresh = false;
@Override
public void updateEntity() {
if (!worldObj.isRemote && ((nodeCounter++) % 40==0 || nodeRefresh)) {
//check for changes
if (!nodeRefresh && children.size()>0) {
for (WeakReference<TileVisNode> n:children) {
if (n==null || n.get()==null) {
nodeRefresh=true;
break;
}
}
}
//refresh linked nodes
if (nodeRefresh) {
for (WeakReference<TileVisNode> n:children) {
if (n.get()!=null) {
n.get().nodeRefresh=true;
}
}
children.clear();
parent=null;
}
//redo stuff
if (isSource() && !nodeRegged) {
VisNetHandler.addSource(getWorldObj(), this);
nodeRegged = true;
} else
if (!isSource() && !VisNetHandler.isNodeValid(getParent())) {
setParent(VisNetHandler.addNode(getWorldObj(), this));
nodeRefresh=true;
}
if (nodeRefresh) {
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
parentChanged();
}
nodeRefresh=false;
}
}
public void parentChanged() { }
/**
* @return the type of shard this is attuned to:
* none -1, air 0, fire 1, water 2, earth 3, order 4, entropy 5
* Should return -1 for most implementations
*/
public byte getAttunement() {
return -1;
}
}
@@ -0,0 +1,284 @@
package thaumcraft.api.visnet;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import net.minecraft.world.World;
import thaumcraft.api.WorldCoordinates;
import thaumcraft.api.aspects.Aspect;
import cpw.mods.fml.common.FMLLog;
public class VisNetHandler {
// / NODE DRAINING
/**
* This method drains vis from a relay or source near the passed in
* location. The amount received can be less than the amount requested so
* take that into account.
*
* @param world
* @param x the x position of the draining block or entity
* @param y the y position of the draining block or entity
* @param z the z position of the draining block or entity
* @param aspect what aspect to drain
* @param amount how much to drain
* @return how much was actually drained
*/
public static int drainVis(World world, int x, int y, int z, Aspect aspect, int amount) {
int drainedAmount = 0;
WorldCoordinates drainer = new WorldCoordinates(x, y, z,
world.provider.dimensionId);
if (!nearbyNodes.containsKey(drainer)) {
calculateNearbyNodes(world, x, y, z);
}
ArrayList<WeakReference<TileVisNode>> nodes = nearbyNodes.get(drainer);
if (nodes!=null && nodes.size()>0)
for (WeakReference<TileVisNode> noderef : nodes) {
TileVisNode node = noderef.get();
if (node == null) continue;
int a = node.consumeVis(aspect, amount);
drainedAmount += a;
amount -= a;
if (a>0) {
int color = Aspect.getPrimalAspects().indexOf(aspect);
generateVisEffect(world.provider.dimensionId, x, y, z, node.xCoord, node.yCoord, node.zCoord, color);
}
if (amount <= 0) {
break;
}
}
return drainedAmount;
}
static Method generateVisEffect;
public static void generateVisEffect(int dim, int x, int y, int z, int x2, int y2, int z2, int color) {
try {
if(generateVisEffect == null) {
Class fake = Class.forName("thaumcraft.common.lib.Utils");
generateVisEffect = fake.getMethod("generateVisEffect", int.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class);
}
generateVisEffect.invoke(null, dim, x,y,z,x2,y2,z2,color);
} catch(Exception ex) {
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.Utils method generateVisEffect");
}
}
public static HashMap<Integer, HashMap<WorldCoordinates, WeakReference<TileVisNode>>> sources = new HashMap<Integer, HashMap<WorldCoordinates, WeakReference<TileVisNode>>>();
public static void addSource(World world, TileVisNode vs) {
HashMap<WorldCoordinates, WeakReference<TileVisNode>> sourcelist = sources
.get(world.provider.dimensionId);
if (sourcelist == null) {
sourcelist = new HashMap<WorldCoordinates, WeakReference<TileVisNode>>();
}
sourcelist.put(vs.getLocation(), new WeakReference(vs));
sources.put(world.provider.dimensionId, sourcelist);
nearbyNodes.clear();
}
public static boolean isNodeValid(WeakReference<TileVisNode> node) {
if (node == null || node.get() == null || node.get().isInvalid())
return false;
return true;
}
public static WeakReference<TileVisNode> addNode(World world, TileVisNode vn) {
WeakReference ref = new WeakReference(vn);
HashMap<WorldCoordinates, WeakReference<TileVisNode>> sourcelist = sources
.get(world.provider.dimensionId);
if (sourcelist == null) {
sourcelist = new HashMap<WorldCoordinates, WeakReference<TileVisNode>>();
return null;
}
ArrayList<Object[]> nearby = new ArrayList<Object[]>();
for (WeakReference<TileVisNode> root : sourcelist.values()) {
if (!isNodeValid(root))
continue;
TileVisNode source = root.get();
float r = inRange(world, vn.getLocation(), source.getLocation(),
vn.getRange());
if (r > 0) {
nearby.add(new Object[] { source, r - vn.getRange() * 2 });
}
nearby = findClosestNodes(vn, source, nearby);
}
float dist = Float.MAX_VALUE;
TileVisNode closest = null;
if (nearby.size() > 0) {
for (Object[] o : nearby) {
if ((Float) o[1] < dist) {// && canNodeBeSeen(vn,(TileVisNode)
// o[0])) {
dist = (Float) o[1];
closest = (TileVisNode) o[0];
}
}
}
if (closest != null) {
closest.getChildren().add(ref);
nearbyNodes.clear();
return new WeakReference(closest);
}
return null;
}
public static ArrayList<Object[]> findClosestNodes(TileVisNode target,
TileVisNode root, ArrayList<Object[]> in) {
TileVisNode closestChild = null;
for (WeakReference<TileVisNode> child : root.getChildren()) {
TileVisNode n = child.get();
if (n != null
&& !n.equals(target)
&& !n.equals(root)
&& (target.getAttunement() == -1 || n.getAttunement() == -1 || n
.getAttunement() == target.getAttunement())) {
float r2 = inRange(n.getWorldObj(), n.getLocation(),
target.getLocation(), target.getRange());
if (r2 > 0) {
in.add(new Object[] { n, r2 });
}
in = findClosestNodes(target, n, in);
}
}
return in;
}
private static float inRange(World world, WorldCoordinates cc1,
WorldCoordinates cc2, int range) {
float distance = cc1.getDistanceSquaredToWorldCoordinates(cc2);
return distance > range * range ? -1 : distance;
}
private static HashMap<WorldCoordinates, ArrayList<WeakReference<TileVisNode>>> nearbyNodes = new HashMap<WorldCoordinates, ArrayList<WeakReference<TileVisNode>>>();
private static void calculateNearbyNodes(World world, int x, int y, int z) {
HashMap<WorldCoordinates, WeakReference<TileVisNode>> sourcelist = sources
.get(world.provider.dimensionId);
if (sourcelist == null) {
sourcelist = new HashMap<WorldCoordinates, WeakReference<TileVisNode>>();
return;
}
ArrayList<WeakReference<TileVisNode>> cn = new ArrayList<WeakReference<TileVisNode>>();
WorldCoordinates drainer = new WorldCoordinates(x, y, z,
world.provider.dimensionId);
ArrayList<Object[]> nearby = new ArrayList<Object[]>();
for (WeakReference<TileVisNode> root : sourcelist.values()) {
if (!isNodeValid(root))
continue;
TileVisNode source = root.get();
TileVisNode closest = null;
float range = Float.MAX_VALUE;
float r = inRange(world, drainer, source.getLocation(),
source.getRange());
if (r > 0) {
range = r;
closest = source;
}
ArrayList<WeakReference<TileVisNode>> children = new ArrayList<WeakReference<TileVisNode>>();
children = getAllChildren(source,children);
for (WeakReference<TileVisNode> child : children) {
TileVisNode n = child.get();
if (n != null && !n.equals(root)) {
float r2 = inRange(n.getWorldObj(), n.getLocation(),
drainer, n.getRange());
if (r2 > 0 && r2 < range) {
range = r2;
closest = n;
}
}
}
if (closest != null) {
cn.add(new WeakReference(closest));
}
}
nearbyNodes.put(drainer, cn);
}
private static ArrayList<WeakReference<TileVisNode>> getAllChildren(TileVisNode source, ArrayList<WeakReference<TileVisNode>> list) {
for (WeakReference<TileVisNode> child : source.getChildren()) {
TileVisNode n = child.get();
if (n != null) {
list.add(child);
list = getAllChildren(n,list);
}
}
return list;
}
// public static boolean canNodeBeSeen(TileVisNode source,TileVisNode
// target)
// {
// double d = Math.sqrt(source.getDistanceFrom(target.xCoord, target.yCoord,
// target.zCoord));
// double xd = (source.xCoord-target.xCoord) / d;
// double yd = (source.yCoord-target.yCoord) / d;
// double zd = (source.zCoord-target.zCoord) / d;
// return source.getWorldObj().rayTraceBlocks(
// Vec3.createVectorHelper(source.xCoord-xd+.5+.5, source.yCoord-yd,
// source.zCoord-zd),
// Vec3.createVectorHelper(target.xCoord+.5, target.yCoord+.5,
// target.zCoord+.5)) == null;
// }
// public static HashMap<WorldCoordinates,WeakReference<TileVisNode>>
// noderef = new HashMap<WorldCoordinates,WeakReference<TileVisNode>>();
//
// public static TileVisNode getClosestNodeWithinRadius(World world, int x,
// int y, int z, int radius) {
// TileVisNode out = null;
// WorldCoordinates wc = null;
// float cd = Float.MAX_VALUE;
// for (int sx = x - radius; sx <= x + radius; sx++) {
// for (int sy = y - radius; sy <= y + radius; sy++) {
// for (int sz = z - radius; sz <= z + radius; sz++) {
// wc = new WorldCoordinates(sx,sy,sz,world.provider.dimensionId);
// if (noderef.containsKey(wc)) {
// float d = wc.getDistanceSquared(x, y, z);
// if (d<radius*radius && noderef.get(wc).get()!=null &&
// !noderef.get(wc).get().isReceiver() &&
// isNodeValid(noderef.get(wc).get().getParent())
// ) {
// out = noderef.get(wc).get();
// cd = d;
// }
// }
// }
// }
// }
// return out;
// }
}
@@ -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,15 @@
package thaumcraft.api.wands;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public interface IWandTriggerManager {
/**
* This class will be called by wands with the proper parameters. It is up to you to decide what to do with them.
*/
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,166 @@
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,129 @@
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;
}
/**
* The research a player needs to have finished to be able to craft a wand with this cap.
*/
public String getResearch() {
return "CAP_"+getTag();
}
// 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,158 @@
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;
}
/**
* The research a player needs to have finished to be able to craft a wand with this rod.
*/
public String getResearch() {
return "ROD_"+getTag();
}
// 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,126 @@
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 {
private static HashMap<String,HashMap<List,List>> triggers = new HashMap<String,HashMap<List,List>>();
private static final String DEFAULT = "default";
/**
* 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
* @param modid a unique identifier. It is best to register your own triggers using your mod id to avoid conflicts with mods that register triggers for the same block
*/
public static void registerWandBlockTrigger(IWandTriggerManager manager, int event, Block block, int meta, String modid) {
if (!triggers.containsKey(modid)) {
triggers.put(modid, new HashMap<List,List>());
}
HashMap<List,List> temp = triggers.get(modid);
temp.put(Arrays.asList(block,meta),Arrays.asList(manager,event));
triggers.put(modid, temp);
}
/**
* for legacy support
*/
public static void registerWandBlockTrigger(IWandTriggerManager manager, int event, Block block, int meta) {
registerWandBlockTrigger(manager, event, block, meta, DEFAULT);
}
/**
* Checks all trigger registries if one exists for the given block and meta
* @param block
* @param meta
* @return
*/
public static boolean hasTrigger(Block block, int meta) {
for (String modid:triggers.keySet()) {
HashMap<List,List> temp = triggers.get(modid);
if (temp.containsKey(Arrays.asList(block,meta)) ||
temp.containsKey(Arrays.asList(block,-1))) return true;
}
return false;
}
/**
* modid sensitive version
*/
public static boolean hasTrigger(Block block, int meta, String modid) {
if (!triggers.containsKey(modid)) return false;
HashMap<List,List> temp = triggers.get(modid);
if (temp.containsKey(Arrays.asList(block,meta)) ||
temp.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) {
for (String modid:triggers.keySet()) {
HashMap<List,List> temp = triggers.get(modid);
List l = temp.get(Arrays.asList(block,meta));
if (l==null) l = temp.get(Arrays.asList(block,-1));
if (l==null) continue;
IWandTriggerManager manager = (IWandTriggerManager) l.get(0);
int event = (Integer) l.get(1);
boolean result = manager.performTrigger(world, wand, player, x, y, z, side, event);
if (result) return true;
}
return false;
}
/**
* modid sensitive version
*/
public static boolean performTrigger(World world, ItemStack wand, EntityPlayer player,
int x, int y, int z, int side, Block block, int meta, String modid) {
if (!triggers.containsKey(modid)) return false;
HashMap<List,List> temp = triggers.get(modid);
List l = temp.get(Arrays.asList(block,meta));
if (l==null) l = temp.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);
}
}
+122
View File
@@ -0,0 +1,122 @@
package truetyper;
/**
* TrueTyper: Open Source TTF implementation for Minecraft.
* Copyright (C) 2013 - Mr_okushama
* Modified by Kihira
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Matrix4f;
import java.nio.FloatBuffer;
import java.util.regex.Pattern;
public class FontHelper {
private static final String formatEscape = "\u00A7";
private static final Pattern formattingCodePattern = Pattern.compile("(?i)" + String.valueOf('\u00a7') + "[0-9A-FK-OR]");
public static void drawString(String s, float x, float y, TrueTypeFont font, float scaleX, float scaleY, float... rgba){
drawString(s,x,y,font,scaleX,scaleY,0,rgba);
}
public static void drawCenteredString(String s, float x, float y, TrueTypeFont font, float scaleX, float scaleY, float ... rgba) {
drawString(s, x - (font.getWidth(s.replaceAll(formattingCodePattern.toString(), "")) / (4F / scaleX)), y, font, scaleX, scaleY, rgba);
}
public static void drawString(String s, float x, float y, TrueTypeFont font, float scaleX, float scaleY, float rotationZ, float... rgba){
Minecraft mc = Minecraft.getMinecraft();
ScaledResolution sr = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
if(mc.gameSettings.hideGUI){
return;
}
float amt = 2F / sr.getScaleFactor();
if(sr.getScaleFactor() == 1){
amt = 2;
}
FloatBuffer matrixData = BufferUtils.createFloatBuffer(16);
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, matrixData);
FontHelper.set2DMode(matrixData);
GL11.glPushMatrix();
y = mc.displayHeight-(y*sr.getScaleFactor())-(((font.getLineHeight()/amt)));
float tx = (x*sr.getScaleFactor())+(font.getWidth(s)/2);
float tranx = tx+2;
float trany = y+(font.getLineHeight()/2);
GL11.glTranslatef(tranx,trany,0);
GL11.glRotatef(rotationZ, 0f, 0f, 1f);
GL11.glTranslatef(-tranx,-trany,0);
GL11.glEnable(GL11.GL_BLEND);
if(s.contains(formatEscape)){
String[] pars = s.split(formatEscape);
float totalOffset = 0;
for(int i = 0; i < pars.length; i++){
String par = pars[i];
float[] c = rgba;
if(i > 0){
c = Formatter.getFormatted(par.charAt(0));
par = par.substring(1, par.length());
}
font.drawString((x*sr.getScaleFactor()+totalOffset), y, par, scaleX/amt, scaleY/amt, c);
totalOffset += font.getWidth(par);
}
}else{
font.drawString((x*sr.getScaleFactor()), y, s, scaleX/amt, scaleY/amt, rgba);
}
GL11.glPopMatrix();
GL11.glDisable(GL11.GL_BLEND);
FontHelper.set3DMode();
}
private static void set2DMode(FloatBuffer matrixData) {
Minecraft mc = Minecraft.getMinecraft();
ScaledResolution sr = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
mc.entityRenderer.setupOverlayRendering();
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPushMatrix();
//GL11.glLoadMatrix(matrixData);
GL11.glLoadIdentity();
GL11.glOrtho(0, mc.displayWidth, 0, mc.displayHeight, -1, 1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPushMatrix();
GL11.glLoadIdentity();
Matrix4f matrix = new Matrix4f();
matrix.load(matrixData);
GL11.glTranslatef(matrix.m30*sr.getScaleFactor(),-matrix.m31*sr.getScaleFactor(), 0f);
}
private static void set3DMode() {
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPopMatrix();
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPopMatrix();
Minecraft mc = Minecraft.getMinecraft();
mc.entityRenderer.setupOverlayRendering();
}
}
+63
View File
@@ -0,0 +1,63 @@
package truetyper;
/**
* TrueTyper: Open Source TTF implementation for Minecraft.
* Copyright (C) 2013 - Mr_okushama
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import net.minecraft.client.Minecraft;
import net.minecraft.util.ResourceLocation;
import java.awt.*;
public class FontLoader{
public static TrueTypeFont loadSystemFont(String name, float defSize, boolean antialias){
return loadSystemFont(name, defSize, antialias, Font.TRUETYPE_FONT);
}
public static TrueTypeFont loadSystemFont(String name, float defSize, boolean antialias, int type){
Font font;
TrueTypeFont out = null;
try {
font = new Font(name, type, (int)defSize);
font = font.deriveFont(defSize);
out = new TrueTypeFont(font, antialias);
} catch (Exception e) {
e.printStackTrace();
}
return out;
}
public static TrueTypeFont createFont(ResourceLocation res, float defSize, boolean antialias){
return createFont(res, defSize, antialias, Font.TRUETYPE_FONT);
}
public static TrueTypeFont createFont(ResourceLocation res, float defSize, boolean antialias, int type){
Font font;
TrueTypeFont out = null;
try {
font = Font.createFont(type, Minecraft.getMinecraft().getResourceManager().getResource(res).getInputStream());
font = font.deriveFont(defSize);
out = new TrueTypeFont(font, antialias);
} catch (Exception e) {
e.printStackTrace();
}
return out;
}
}
+86
View File
@@ -0,0 +1,86 @@
package truetyper;
/**
* TrueTyper: Open Source TTF implementation for Minecraft.
* Copyright (C) 2013 - Mr_okushama
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class Formatter {
public static float[] getFormatted(char c){
int[] outrgba = null;
float[] outfloat;
switch(c){
case '0':
outrgba = new int[]{0,0,0,0,255};
break;
case '1':
outrgba = new int[]{0,0,170,255};
break;
case '2':
outrgba = new int[]{0,170,0,255};
break;
case '3':
outrgba = new int[]{0,170,170,255};
break;
case '4':
outrgba = new int[]{170,0,0,255};
break;
case '5':
outrgba = new int[]{170,0,170,255};
break;
case '6':
outrgba = new int[]{255,170,0,255};
break;
case '7':
outrgba = new int[]{170,170,170,255};
break;
case '8':
outrgba = new int[]{85,85,85,255};
break;
case '9':
outrgba = new int[]{85,85,255,255};
break;
case 'a':
outrgba = new int[]{85,255,85,255};
break;
case 'b':
outrgba = new int[]{85,255,255,255};
break;
case 'c':
outrgba = new int[]{255,85,85,255};
break;
case 'd':
outrgba = new int[]{85,255,255,255};
break;
case 'e':
outrgba = new int[]{255,255,85,255};
break;
case 'f':
outrgba = new int[]{255,255,255,255};
break;
default:
outrgba = new int[]{255,255,255,255};
break;
}
outfloat = new float[outrgba.length];
for(int i = 0; i < outrgba.length ; i++){
outfloat[i] = outrgba[i] > 0 ? outrgba[i]/255 : 0;
}
return outfloat;
}
}
+674
View File
@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+51
View File
@@ -0,0 +1,51 @@
An open TrueType Font renderer for Minecraft
USAGE GUIDE!
Create a TrueTypeFont object variable using either a resource location to a .ttf or
name of a system font, choose base size and whether or not you want anti aliasing like so:
testFont = FontLoader.createFont(new ResourceLocation("modid", "testfont.ttf"), 24f, false);
testFont2 = FontLoader.loadSystemFont("Arial", 16f, false);
Once the font has been created, to render to screen, simply use the static call:
FontHelper.drawString(String name, float x, float y, TrueTypeFont font, float scaleX, float scaleY, float... rgba)
eg,
FontHelper.drawString(windowTitle, posX, posY, testFont, 1f, 1f);
Thanks to ProfMobius for tweaking the matrix ( http://www.twitter.com/ProfMobius )
----
CHANGELOG:
10/11/2013 - Added support for minecraft's colour code formatting ( § / \u00A7) - I personally use net.minecraft.util.EnumChatFormatting in my strings
----
TrueTyper in part, is modified from Slick2d, full details on their licensing can be found here:
http://slick.ninjacave.com/license/
----
TrueTyper: Open Source TTF implementation for Minecraft.
Copyright (C) 2013 - Mr_okushama ( http://www.twitter.com/Mr_okushama )
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
+496
View File
@@ -0,0 +1,496 @@
package truetyper;
import net.minecraft.client.renderer.Tessellator;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Map;
/**
* TrueTyper: Open Source TTF implementation for Minecraft.
* Modified from Slick2D - under BSD Licensing - http://slick.ninjacave.com/license/
*
* Copyright (c) 2013 - Slick2D
*
* All rights reserved.
*/
public class TrueTypeFont {
public final static int
ALIGN_LEFT = 0,
ALIGN_RIGHT = 1,
ALIGN_CENTER = 2;
/** Array that holds necessary information about the font characters */
private FloatObject[] charArray = new FloatObject[256];
/** Map of user defined font characters (Character <-> IntObject) */
private Map customChars = new HashMap();
/** Boolean flag on whether AntiAliasing is enabled or not */
protected boolean antiAlias;
/** Font's size */
private float fontSize = 0;
/** Font's height */
private float fontHeight = 0;
/** Texture used to cache the font 0-255 characters */
private int fontTextureID;
/** Default font texture width */
private int textureWidth = 1024;
/** Default font texture height */
private int textureHeight = 1024;
/** A reference to Java's AWT Font that we create our font texture from */
protected Font font;
/** The font metrics for our Java AWT font */
private FontMetrics fontMetrics;
private int correctL = 9, correctR = 8;
private class FloatObject {
/** Character's width */
public float width;
/** Character's height */
public float height;
/** Character's stored x position */
public float storedX;
/** Character's stored y position */
public float storedY;
}
public TrueTypeFont(Font font, boolean antiAlias, char[] additionalChars) {
this.font = font;
this.fontSize = font.getSize()+3;
this.antiAlias = antiAlias;
createSet( additionalChars );
System.out.println("TrueTypeFont loaded: "+font+" - AntiAlias = "+antiAlias);
fontHeight -= 1;
if (fontHeight <= 0) fontHeight = 1;
}
public TrueTypeFont(Font font, boolean antiAlias) {
this( font, antiAlias, null );
}
public void setCorrection(boolean on) {
if (on) {
correctL = 2;
correctR = 1;
} else {
correctL = 0;
correctR = 0;
}
}
private BufferedImage getFontImage(char ch) {
// Create a temporary image to extract the character's size
BufferedImage tempfontImage = new BufferedImage(1, 1,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) tempfontImage.getGraphics();
if (antiAlias == true) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
g.setFont(font);
fontMetrics = g.getFontMetrics();
float charwidth = fontMetrics.charWidth(ch)+8;
if (charwidth <= 0) {
charwidth = 7;
}
float charheight = fontMetrics.getHeight()+3;
if (charheight <= 0) {
charheight = fontSize;
}
// Create another image holding the character we are creating
BufferedImage fontImage;
fontImage = new BufferedImage((int)charwidth,(int)charheight,
BufferedImage.TYPE_INT_ARGB);
Graphics2D gt = (Graphics2D) fontImage.getGraphics();
if (antiAlias == true) {
gt.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
gt.setFont(font);
gt.setColor(Color.WHITE);
int charx = 3;
int chary = 1;
gt.drawString(String.valueOf(ch), (charx), (chary)
+ fontMetrics.getAscent());
return fontImage;
}
private void createSet( char[] customCharsArray ) {
// If there are custom chars then I expand the font texture twice
if (customCharsArray != null && customCharsArray.length > 0) {
textureWidth *= 2;
}
// In any case this should be done in other way. Texture with size 512x512
// can maintain only 256 characters with resolution of 32x32. The texture
// size should be calculated dynamicaly by looking at character sizes.
try {
BufferedImage imgTemp = new BufferedImage(textureWidth, textureHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) imgTemp.getGraphics();
g.setColor(new Color(0,0,0,1));
g.fillRect(0,0,textureWidth,textureHeight);
float rowHeight = 0;
float positionX = 0;
float positionY = 0;
int customCharsLength = ( customCharsArray != null ) ? customCharsArray.length : 0;
for (int i = 0; i < 256 + customCharsLength; i++) {
// get 0-255 characters and then custom characters
char ch = ( i < 256 ) ? (char) i : customCharsArray[i-256];
BufferedImage fontImage = getFontImage(ch);
FloatObject newIntObject = new FloatObject();
newIntObject.width = fontImage.getWidth();
newIntObject.height = fontImage.getHeight();
if (positionX + newIntObject.width >= textureWidth) {
positionX = 0;
positionY += rowHeight;
rowHeight = 0;
}
newIntObject.storedX = positionX;
newIntObject.storedY = positionY;
if (newIntObject.height > fontHeight) {
fontHeight = newIntObject.height;
}
if (newIntObject.height > rowHeight) {
rowHeight = newIntObject.height;
}
// Draw it here
g.drawImage(fontImage, (int)positionX, (int)positionY, null);
positionX += newIntObject.width;
if( i < 256 ) { // standard characters
charArray[i] = newIntObject;
} else { // custom characters
customChars.put( new Character( ch ), newIntObject );
}
fontImage = null;
}
fontTextureID = loadImage(imgTemp);
//.getTexture(font.toString(), imgTemp);
} catch (Exception e) {
System.err.println("Failed to create font.");
e.printStackTrace();
}
}
private void drawQuad(float drawX, float drawY, float drawX2, float drawY2,
float srcX, float srcY, float srcX2, float srcY2) {
float DrawWidth = drawX2 - drawX;
float DrawHeight = drawY2 - drawY;
float TextureSrcX= srcX / textureWidth;
float TextureSrcY = srcY / textureHeight;
float SrcWidth = srcX2 - srcX;
float SrcHeight = srcY2 - srcY;
float RenderWidth = (SrcWidth / textureWidth);
float RenderHeight = (SrcHeight / textureHeight);
Tessellator t = Tessellator.instance;
//t.setColorRGBA_F(0f, 0f, 0f, 1f);
t.addVertexWithUV(drawX, drawY, 0, TextureSrcX, TextureSrcY);
//GL11.glTexCoord2f(TextureSrcX, TextureSrcY);
//GL11.glVertex2f(drawX, drawY);
t.addVertexWithUV(drawX, drawY + DrawHeight, 0, TextureSrcX, TextureSrcY + RenderHeight);
//GL11.glTexCoord2f(TextureSrcX, TextureSrcY + RenderHeight);
//GL11.glVertex2f(drawX, drawY + DrawHeight);
t.addVertexWithUV(drawX + DrawWidth, drawY + DrawHeight, 0, TextureSrcX + RenderWidth, TextureSrcY + RenderHeight);
//GL11.glTexCoord2f(TextureSrcX + RenderWidth, TextureSrcY + RenderHeight);
//GL11.glVertex2f(drawX + DrawWidth, drawY + DrawHeight);
t.addVertexWithUV(drawX + DrawWidth, drawY, 0, TextureSrcX + RenderWidth, TextureSrcY);
//GL11.glTexCoord2f(TextureSrcX + RenderWidth, TextureSrcY);
//GL11.glVertex2f(drawX + DrawWidth, drawY);
}
public float getWidth(String whatchars) {
float totalwidth = 0;
FloatObject floatObject = null;
int currentChar = 0;
float lastWidth = -10f;
for (int i = 0; i < whatchars.length(); i++) {
currentChar = whatchars.charAt(i);
if (currentChar < 256) {
floatObject = charArray[currentChar];
} else {
floatObject = (FloatObject)customChars.get( new Character( (char) currentChar ) );
}
if( floatObject != null ){
totalwidth += floatObject.width/2;
lastWidth = floatObject.width;
}
}
//System.out.println("Size: "+totalwidth);
return this.fontMetrics.stringWidth(whatchars);
//return (totalwidth);
}
public float getHeight() {
return fontHeight;
}
public float getHeight(String HeightString) {
return fontHeight;
}
public float getLineHeight() {
return fontHeight;
}
public void drawString(float x, float y, String whatchars, float scaleX, float scaleY, float... rgba) {
if(rgba.length == 0) rgba = new float[]{1f,1f,1f,1f};
drawString(x,y,whatchars, 0, whatchars.length()-1, scaleX, scaleY, ALIGN_LEFT, rgba);
}
public void drawString(float x, float y, String whatchars, float scaleX, float scaleY, int format, float... rgba) {
if(rgba.length == 0) rgba = new float[]{1f,1f,1f,1f};
drawString(x,y,whatchars, 0, whatchars.length()-1, scaleX, scaleY, format, rgba);
}
public void drawString(float x, float y, String whatchars, int startIndex, int endIndex, float scaleX, float scaleY, int format, float... rgba) {
if(rgba.length == 0) rgba = new float[]{1f,1f,1f,1f};
GL11.glPushMatrix();
GL11.glScalef (scaleX, scaleY, 1.0f);
FloatObject floatObject = null;
int charCurrent;
float totalwidth = 0;
int i = startIndex, d, c;
float startY = 0;
switch (format) {
case ALIGN_RIGHT: {
d = -1;
c = correctR;
while (i < endIndex) {
if (whatchars.charAt(i) == '\n') startY -= fontHeight;
i++;
}
break;
}
case ALIGN_CENTER: {
for (int l = startIndex; l <= endIndex; l++) {
charCurrent = whatchars.charAt(l);
if (charCurrent == '\n') break;
if (charCurrent < 256) {
floatObject = charArray[charCurrent];
} else {
floatObject = (FloatObject)customChars.get( new Character( (char) charCurrent ) );
}
totalwidth += floatObject.width-correctL;
}
totalwidth /= -2;
}
case ALIGN_LEFT:
default: {
d = 1;
c = correctL;
break;
}
}
GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureID);
Tessellator t = Tessellator.instance;
t.startDrawingQuads();
// GL11.glBegin(GL11.GL_QUADS);
if(rgba.length == 4) t.setColorRGBA_F(rgba[0], rgba[1], rgba[2], rgba[3]);
while (i >= startIndex && i <= endIndex) {
charCurrent = whatchars.charAt(i);
if (charCurrent < 256) {
floatObject = charArray[charCurrent];
} else {
floatObject = (FloatObject)customChars.get( new Character( (char) charCurrent ) );
}
if( floatObject != null ) {
if (d < 0) totalwidth += (floatObject.width-c) * d;
if (charCurrent == '\n') {
startY -= fontHeight * d;
totalwidth = 0;
if (format == ALIGN_CENTER) {
for (int l = i+1; l <= endIndex; l++) {
charCurrent = whatchars.charAt(l);
if (charCurrent == '\n') break;
if (charCurrent < 256) {
floatObject = charArray[charCurrent];
} else {
floatObject = (FloatObject)customChars.get( new Character( (char) charCurrent ) );
}
totalwidth += floatObject.width-correctL;
}
totalwidth /= -2;
}
//if center get next lines total width/2;
}
else {
drawQuad((totalwidth + floatObject.width) + x/scaleX,
startY + y/scaleY,
totalwidth + x/scaleX,
(startY + floatObject.height) + y/scaleY,
floatObject.storedX + floatObject.width,
floatObject.storedY + floatObject.height,
floatObject.storedX,
floatObject.storedY);
if (d > 0) totalwidth += (floatObject.width-c) * d ;
}
i += d;
}
}
t.draw();
// GL11.glEnd();
GL11.glPopMatrix();
}
public static int loadImage(BufferedImage bufferedImage) {
try {
short width = (short)bufferedImage.getWidth();
short height = (short)bufferedImage.getHeight();
//textureLoader.bpp = bufferedImage.getColorModel().hasAlpha() ? (byte)32 : (byte)24;
int bpp = (byte)bufferedImage.getColorModel().getPixelSize();
ByteBuffer byteBuffer;
DataBuffer db = bufferedImage.getData().getDataBuffer();
if (db instanceof DataBufferInt) {
int intI[] = ((DataBufferInt)(bufferedImage.getData().getDataBuffer())).getData();
byte newI[] = new byte[intI.length * 4];
for (int i = 0; i < intI.length; i++) {
byte b[] = intToByteArray(intI[i]);
int newIndex = i*4;
newI[newIndex] = b[1];
newI[newIndex+1] = b[2];
newI[newIndex+2] = b[3];
newI[newIndex+3] = b[0];
}
byteBuffer = ByteBuffer.allocateDirect(
width*height*(bpp/8))
.order(ByteOrder.nativeOrder())
.put(newI);
} else {
byteBuffer = ByteBuffer.allocateDirect(
width*height*(bpp/8))
.order(ByteOrder.nativeOrder())
.put(((DataBufferByte)(bufferedImage.getData().getDataBuffer())).getData());
}
byteBuffer.flip();
int internalFormat = GL11.GL_RGBA8,
format = GL11.GL_RGBA;
IntBuffer textureId = BufferUtils.createIntBuffer(1);;
GL11.glGenTextures(textureId);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId.get(0));
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
//GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
//GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_NEAREST);
//GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
//GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST_MIPMAP_LINEAR);
//GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST_MIPMAP_NEAREST);
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
GLU.gluBuild2DMipmaps(GL11.GL_TEXTURE_2D, internalFormat, width, height, format, GL11.GL_UNSIGNED_BYTE, byteBuffer);
return textureId.get(0);
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
return -1;
}
public static boolean isSupported(String fontname) {
Font font[] = getFonts();
for (int i = font.length-1; i >= 0; i--) {
if (font[i].getName().equalsIgnoreCase(fontname))
return true;
}
return false;
}
public static Font[] getFonts() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
}
public static byte[] intToByteArray(int value) {
return new byte[] {
(byte)(value >>> 24),
(byte)(value >>> 16),
(byte)(value >>> 8),
(byte)value};
}
public void destroy() {
IntBuffer scratch = BufferUtils.createIntBuffer(1);
scratch.put(0, fontTextureID);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
GL11.glDeleteTextures(scratch);
}
}