Malkuthe Posted June 14, 2014 Posted June 14, 2014 Hi! I guess the title is fairly self-explanatory, but I feel the need to elaborate so as to avoid any confusion. My question pretty much boils down to: "Is there a way to attach NBT data to the result of a vanilla crafting recipe based on the items used therein?" I've been trying to find something along these lines for the past two hours or so, but to no avail. (granted, I may have been trying out the wrong keywords...) More elaboration: I have an item I call a Boon, and based on the items used in its crafting recipe, it can take on different 'jobs' so to speak. For example, using four Diamond Swords makes it a Boon with job: "Knight", or four bows for a Boon with job: "Archer". Is there a way to do this using vanilla crafting or do I have to come up with my own method of crafting the item? Quote
kosakriszi Posted June 14, 2014 Posted June 14, 2014 Hey there! I had a similar problem in my mod, where I had multiple outcomes based on item combinations. You can add NBT to an item stack and then pass it to the GameRegistry, and that NBT will be present when you craft it! Here I used two metadata items, similar to how the color dyes work. // iterate through all damage values for meat item for(int i = 0; i < meatItem.getItemData().size(); i++) { // create item stack for crafting component ItemStack meatStack = new ItemStack(meatItem, 1, i); // iterate through all damage values for cheese item for(int j = 0; j < cheeseItem.getItemData().size(); j++) { // create item stack for crafting component ItemStack cheeseStack = new ItemStack(cheeseItem, 1, j); // this item stack will be the result with the NBT ItemStack sandwich = new ItemStack(sandwichItem, 1); // assign a new tag compound to the item stack sandwich.setTagCompound(new NBTTagCompound()); // retrieve said compound for modifying NBTTagCompound tags = sandwich.stackTagCompound; // here you can set your NBT data on the item tags.setString("meat", meatStack.getDisplayName()); tags.setByte("meatTier", (byte) ItemMeat.getTier(meatStack)); tags.setString("cheese", cheeseStack.getDisplayName()); // add the recipe to the GameRegistry GameRegistry.addShapelessRecipe(sandwich, new Object[] { breadSliceItem, breadSliceItem, meatStack, cheeseStack }); } } Hope this helps! If I didn't explain anything well enough, please don't hesitate to ask! Quote
Malkuthe Posted June 14, 2014 Author Posted June 14, 2014 Oooh! Thank you so much! I was a bit confused at first but I think I understand what you're doing. *nods* Correct me if I'm wrong, but am I right in assuming that this code goes where I register my items/recipes? Also, what you are doing is basically attaching the specific ingredients used to the resulting item as NBT data, right? I'm trying to reason out how to do this only AND ONLY for specific item combinations, while the recipe won't exist for others. Say, Three diamond swords plus one bow wouldn't work, but four diamond swords or two diamond swords and two bows would. *ponders* Quote
Malkuthe Posted June 15, 2014 Author Posted June 15, 2014 So I was looking around, and I have no idea if the way I'm planning to do this will work. I'm not even sure exactly how to do it just yet, being a newbie to Java and all... However, I have something in mind, and I may need some help implementing it. The fact that I want this thing to be configurable is beating me up. . So, first, and obviously not done in the same class would be retrieving the number of player jobs that are configured. So that should be an integer. Say it's something like below. For now I'll set an arbitrary integer as its value. public static final int NUMBER_OF_JOBS = 4; Then, this is what I currently have written down on Eclipse after the above.: public static void Init(){ String[] jobNames = { //This is just arbitrary. In the future I'd like to pull these values from the config. "Knight", "Thief", "Mage", "Archer" } HashMap<String, Object> jobmap = new HashMap<String, Object>(); for (int i = 0; i < NUMBER_OF_CLASSES; ++i){ jobmap.put(jobKeys[i], *jobRecipes*); } } Where *jobRecipes* are to be the arrays of the "recipes" so to speak, and it's at this point that I am stuck because what I want to do next is a for loop with an if statement that checks the "recipes" against the hashmap key, and if the recipes match, sets the job NBT data to the same as the key... I'm beginning to think it's worth the effort to create a custom block instead... Quote
Kwibble Posted June 15, 2014 Posted June 15, 2014 It seems you are trying to over complicate things just a tad. You know, just a teensy weensy bit. After reading what you have said, it seems you are wanting to make it so certain jobs have certain recipes right? Well, if that's the case, time to harness the power of object orientated programming I would make a class called Job, and that class has all the basic stuff in it that every job will have. So an array of recipes etc.. Then, for each job, subclass Job (e.g. JobKnight, JobMage) and implement the job only stuff you need. You may need to make your own custom 'recipe' class as well that creates the special recipes you want. Just my thoughts Quote We all stuff up sometimes... But I seem to be at the bottom of that pot.
Malkuthe Posted June 15, 2014 Author Posted June 15, 2014 *nods* The problem is, that's perfectly fine for hard-coded jobs, which, in hindsight, are the better and far nicer way to go at this point in time. However, one of the features on the feature-list my friend -- who'll be working on the project with me eventually -- and I compiled is the ability to create jobs through a config file. Unless there's a way to automatically create a subclass from the input of a config file... *shakes his feature-list for being ambitious* Quote
Kwibble Posted June 15, 2014 Posted June 15, 2014 Hmm... Well, you probably could do that You could modify what I said to suit that. Just store all the information you would need in the config file (I would suggest creating your own way of handling this config file though) and then make the Job class more generic. You would make the Job class so that it has multiple parameters passed to it that are taken from the config - same for the custom recipe class. A lot of helper methods would need writing, but its doable. Quote We all stuff up sometimes... But I seem to be at the bottom of that pot.
Malkuthe Posted June 15, 2014 Author Posted June 15, 2014 Yeaah. I don't think the config that comes with forge has the functionality we need. That other config is still useful for the basic stuff though. *nodnods* I'll get back to everyone if I manage to pull it off with the configurability, but for now, I'll do the easy way of defining jobs and then, when I have that done, I'll start working on making it all configurable. Sidenote: I call the jobs classes in the mod, but because talking java, well, it would get really confusing really fast. . Quote
Malkuthe Posted June 15, 2014 Author Posted June 15, 2014 *flails* @Override @SideOnly(Side.CLIENT) public void registerIcons(IconRegister register){ Icon[] iconArray = new Icon[2]; //registering the two icons iconArray[0] = register.registerIcon(BCMInfo.ID + ":" + getUnlocalizedName()); iconArray[1] = register.registerIcon(BCMInfo.ID + ":" + getUnlocalizedName() + "Active"); } @Override @SideOnly(Side.CLIENT) public Icon getIcon(ItemStack itemstack, int renderPass, EntityPlayer player, ItemStack usingItem, int useRemaining){ NBTTagCompound properties = itemstack.stackTagCompound; if (!properties.getString("Owner").isEmpty()){ return iconArray[1]; } else { return iconArray[0]; } } I have a new problem. I have no idea what I'm doing wrong, but Eclipse is telling me that where I return the iconArray[] that it cannot be resolved to a variable. *is confused* Quote
Kwibble Posted June 15, 2014 Posted June 15, 2014 That's because you are trying to access it from somewhere it isn't. Try this: @SideOnly(Side.CLIENT( private Icon[] iconArray; @Override @SideOnly(Side.CLIENT) public void registerIcons(IconRegister register) { iconArray = new Icon[2]; //registering the two icons iconArray[0] = register.registerIcon(BCMInfo.ID + ":" + getUnlocalizedName()); iconArray[1] = register.registerIcon(BCMInfo.ID + ":" + getUnlocalizedName() + "Active"); } @Override @SideOnly(Side.CLIENT) public Icon getIcon(ItemStack itemstack, int renderPass, EntityPlayer player, ItemStack usingItem, int useRemaining){ NBTTagCompound properties = itemstack.stackTagCompound; if (!properties.getString("Owner").isEmpty()){ return iconArray[1]; } else { return iconArray[0]; } } Quote We all stuff up sometimes... But I seem to be at the bottom of that pot.
Malkuthe Posted June 15, 2014 Author Posted June 15, 2014 Ohhhhh. THAT was it. >_> I forgot to define it. . Whoops. Thank you! Quote
Malkuthe Posted June 16, 2014 Author Posted June 16, 2014 I seem to be running headlong into problems all day today. I got the thing working... sort of. http://pastebin.com/WCqYX6yC That's the crash report. The full item class is over here: https://github.com/Malkuthe/BattleClasses/blob/master/battleclassmod/items/BoonItem.java#L68 It may have to do with rendering the object in the player's hand. The reason I say that is because the item is perfectly fine in my inventory. However, another issue is that instead of displaying a sprite, minecraft displays the no-icon texture. Anyway, the one with the iconIndex[1] works just fine rendering in the hand, but as soon as the one with iconIndex[0] is selected, minecraft crashes. I'm not sure what's going on. Quote
Kwibble Posted June 16, 2014 Posted June 16, 2014 No, your crash has to do with your NBT tag/and or the return from getString("Owner") being null. How about you change your check to: @Override @SideOnly(Side.CLIENT) public Icon getIcon(ItemStack itemstack, int renderPass, EntityPlayer player, ItemStack usingItem, int useRemaining){ NBTTagCompound properties = itemstack.stackTagCompound; if (properties != null) { if (!properties.getString("Owner").equals("none")) { return iconIndex[1]; } return iconIndex[0]; } return this.itemIcon; } And if that still crashes with a NullPointerException again, change: if (!properties.getString("Owner").equals("none")) { to: if (properties.getString("Owner") != null && !properties.getString("Owner").equals("none")) { Hope that helps Quote We all stuff up sometimes... But I seem to be at the bottom of that pot.
Malkuthe Posted June 16, 2014 Author Posted June 16, 2014 Yaay! It works now! I had to do a little fiddling around with the code too. Turns out part of the reason for the crash was that I was just taking the item out of the creative inventory and therefore it had no NBT Tag Compound associated with it. I fixed that part with a quick modification to the onUpdate method and made it so that if the item tag compound of the item is null, to set "Owner" to "none" by default. Thanks so much for the help! Sorry for the relentless questions. I'm trying to learn as much as I can as fast as I can. Quote
Kwibble Posted June 16, 2014 Posted June 16, 2014 Good job on that fix It probably isn't the most efficient, but it works right? No worries mate, questions are the only way you can learn really. Keep asking away! Quote We all stuff up sometimes... But I seem to be at the bottom of that pot.
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.