Currently I have an item that has a crafting recipe. Whenever that item is crafted you can't craft it again until I explicitly tell the code that it can be crafted again. The way I made this work is by making a boolean value called isCrafted. By default this is false, but whenever the ItemCraftedEvent is called it is made true. Since it is a variable, however, this is reset every time you restart minecraft. Since I don't want this to be the case I need to have my check check something other than a variable. I think it would be possible to create a seperate file to check this, but I'd prefer not having one since the user can reset the file to craft the item again.
ModCrafting.java
//Field for checking if the reliquary is crafted
private static boolean isReliquaryCrafted = false;
public static void init()
{
if(!isReliquaryCrafted)
{
GameRegistry.addRecipe(new ItemStack(ModItems.itemReliquary), "DGD", "DSD", "DDD", 'D', Items.DIAMOND, 'G', Item.getItemFromBlock(Blocks.GLASS), 'S', Items.NETHER_STAR);
}
}
public static void setReliquaryCrafable(boolean isCrafted)
{
isReliquaryCrafted = isCrafted;
//Make reliquary uncraftable if it has been crafted
if(isReliquaryCrafted)
{
Iterator recipes = CraftingManager.getInstance().getRecipeList().iterator();
while(recipes.hasNext())
{
ItemStack output = ((IRecipe) recipes.next()).getRecipeOutput();
if(output != null && output.getItem() != null)
{
if(ItemStack.areItemsEqual(output, new ItemStack(ModItems.itemReliquary)))
recipes.remove();
}
}
}
}
(If you copy into your project, make sure that you make it non-abstract, may need to adapt it as well)
Acquire instance of world data via: MyWorldData#getDataForWorld(MyWorldData.class, "MyWorldData", world, false)
The boolean isReliquaryCrafted should be a field inside MyWorldData that is set/saved during the writeToNBT/readFromNBT methods (not shown in example).
Make getters and setters but call markDirty() in the setter or world data will never be saved!
You should be able to use a per-map World Saved Data to store this. For server Worlds, you should maintain a single instance, use it for every dimension (like this) and clear it when the server stops (FMLServerStoppedEvent). For client Worlds, you should use the instance stored in the MapStorage (like the example in the documentation).
Create your own implementation of IRecipe (you'll probably want to extend an existing one like ShapedRecipes or ShapedOreRecipe) and implement IRecipe#matches to check the value stored in the World Saved Data.
When the item is crafted (ItemCraftedEvent or Item#onCreated), set the value in the World Saved Data to false.
When the World Saved Data's value changes, send a packet to all clients to update their copy of the value.
When a player logs in (PlayerEvent.PlayerLoggedInEvent) or changes dimension (PlayerEvent.PlayerChangedDimensionEvent), send a packet to their client to update its copy of the value.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Create your own implementation of IRecipe (you'll probably want to extend an existing one like ShapedRecipes or ShapedOreRecipe) and implement IRecipe#matches to check the value stored in the World Saved Data.
I'm not sure I understand how to do this. Do you mind giving an example? For reference this is my ModWorldSaved class
Rollback Post to RevisionRollBack
Teleporting XP, for when you want to improve performance with XP farms
I'm not sure I understand how to do this. Do you mind giving an example? For reference this is my ModWorldSaved class
Extend either ShapedRecipes or ShapedOreRecipes and override the matches method to get the ReliquaryWorldData for the World argument and then return true when the super method returns true (the ingredients match) and ReliquaryWorldData#isReliquaryCrafted returns false (the reliquary hasn't been crafted).
Make sure you register this recipe class with RecipeSorter.
Your ReliquaryWorldData currently doesn't maintain a per-server instance like I recommended, so each dimension will have its own copy of the data.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Extend either ShapedRecipes or ShapedOreRecipes and override the matches method to get the ReliquaryWorldData for the World argument and then return true when the super method returns true (the ingredients match) and ReliquaryWorldData#isReliquaryCrafted returns false (the reliquary hasn't been crafted).
Make sure you register this recipe class with RecipeSorter.
Your ReliquaryWorldData currently doesn't maintain a per-server instance like I recommended, so each dimension will have its own copy of the data.
Is this the right way to do it? If it is, how do I make isReliquaryCrafted true properly? While it might be obvious, calling ReliquaryWorldData#get(worldIn)#setReliquaryCrafted(true) in onCreated in the reliquary item class crashes the game.
Rollback Post to RevisionRollBack
Teleporting XP, for when you want to improve performance with XP farms
Is this the right way to do it? If it is, how do I make isReliquaryCrafted true properly? While it might be obvious, calling ReliquaryWorldData#get(worldIn)#setReliquaryCrafted(true) in onCreated in the reliquary item class crashes the game.
RecipeSorter.register must be called once, not every time an instance of your recipe class is created. It should be done in init.
You can't just create a new instance of ReliquaryWorldData and expect it to have the right value, you need to get the existing one by calling ReliquaryWorldData.get. If it's crashing, post the code and the crash report.
You should replace the if statement in ModShapedRecipe#matches with a return statement to return the if statement's condition. Currently the return of ReliquaryWorldData#isReliquaryCrafted is essentially ignored; the return of the super method (i.e. "do the ingredients match?") is used regardless of whether or not the reliquary has been crafted.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
RecipeSorter.register must be called once, not every time an instance of your recipe class is created. It should be done in init.
You can't just create a new instance of ReliquaryWorldData and expect it to have the right value, you need to get the existing one by calling ReliquaryWorldData.get. If it's crashing, post the code and the crash report.
You should replace the if statement in ModShapedRecipe#matches with a return statement to return the if statement's condition. Currently the return of ReliquaryWorldData#isReliquaryCrafted is essentially ignored; the return of the super method (i.e. "do the ingredients match?") is used regardless of whether or not the reliquary has been crafted.
The register call has been moved to a seperate init method that I call in the main mod class' init method, the matches method has been changed to
@Override
public boolean matches(InventoryCrafting inv, World worldIn)
{
ReliquaryWorldData worldData = ReliquaryWorldData.get(worldIn);
return !worldData.isReliquaryCrafted() && super.matches(inv, worldIn);
}
and this code block has been added in itemReliquary:
@Override
public void onCreated(ItemStack stack, World worldIn, EntityPlayer playerIn)
{
ReliquaryWorldData worldData = ReliquaryWorldData.get(worldIn);
worldData.setReliquaryCrafted(true);
}
If I craft the item in game it crashes and gives me this crash log.
EDIT: Also, if I log back in the crafting ingredients are dropped on the ground (no reliquary is crafted).
I fixed the NullPointerException error, but I can still always create the reliquary. I added a print method to each of the methods in ReliquaryWorldData and found out that isReliquaryCrafted is never called, even if with the overridden matches method I mentioned earlier.
Rollback Post to RevisionRollBack
Teleporting XP, for when you want to improve performance with XP farms
I fixed the NullPointerException error, but I can still always create the reliquary. I added a print method to each of the methods in ReliquaryWorldData and found out that isReliquaryCrafted is never called, even if with the overridden matches method I mentioned earlier.
Is the crafting recipe for the reliquary using your custom recipe class, or is it still using a vanilla shaped recipe?
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Is the crafting recipe for the reliquary using your custom recipe class, or is it still using a vanilla shaped recipe?
This is probably not the right way to do it, but I did it like this:
public static void init()
{
RecipeSorter.register("thedarkness:shaped", ModShapedRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shaped");
ItemStack[] inputs = new ItemStack[3];
inputs[0] = new ItemStack(Items.NETHER_STAR);
inputs[1] = new ItemStack(ModItems.itemDarklingSkin, 7);
inputs[2] = new ItemStack(Blocks.GLASS);
//With only this you can't craft the item
GameRegistry.addRecipe(new ModShapedRecipe(3, 3, inputs, new ItemStack(ModItems.itemReliquary)));
//With only this and with the above statement you can always craft the item
Don't add a vanilla shaped recipe, only add your custom recipe.
If you extend ShapedRecipes, you need to create the ItemStack array in the same way that CraftingManager#addRecipe(ItemStack, Object...) does.
I'd recommend extending ShapedOreRecipe instead, which takes the shape strings and ingredients like GameRegistry#addRecipe(ItemStack, Object...) and does all of this for you (with the added bonus of accepting ore dictionary ingredients).
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
After a lot of tinkering I got it to work- somewhat. The item can only be crafted once every time you start minecraft. This basically puts me in the same position as I was in originially. It seems like ReliquaryWorldData isn't saving the value properly. I added a IMessage called ReliquaryMessage and a IMessageHandler called ReliquaryMessageHandler. I also updated ReliquaryWorldData#setReliquaryCrafted. They look like this
public class ReliquaryMessage implements IMessage
{
private boolean reliquaryCrafted;
public ReliquaryMessage() {}
public ReliquaryMessage(boolean reliquaryCrafted)
{
this.reliquaryCrafted = reliquaryCrafted;
}
public void setReliquaryCrafted(boolean isCrafted)
{
this.reliquaryCrafted = isCrafted;
}
@Override
public void fromBytes(ByteBuf buf)
{
reliquaryCrafted = buf.readBoolean();
}
@Override
public void toBytes(ByteBuf buf)
{
buf.writeBoolean(reliquaryCrafted);
}
}
ReliquaryMessageHandler
public class ReliquaryMessageHandler implements IMessageHandler<ReliquaryMessage, IMessage>
{
public ReliquaryMessageHandler()
{
}
@Override
public IMessage onMessage(ReliquaryMessage message, MessageContext ctx)
{
System.out.print("Item crafted");
return null;
}
}
How I register the above classes
public static final SimpleNetworkWrapper NETWORK = NetworkRegistry.INSTANCE.newSimpleChannel(Reference.MOD_ID);
public void preInit(FMLPreInitializationEvent event)
{
int id = -1;
NETWORK.registerMessage(ReliquaryMessageHandler.class, ReliquaryMessage.class, id++, Side.SERVER);
}
Rollback Post to RevisionRollBack
Teleporting XP, for when you want to improve performance with XP farms
It's not the main issue here, but the Side argument of SimpleNetworkWrapper#registerMessage is the side that should receive and process the message, not the side it's sent from.
I can't see any obvious issues in the snippets of code you've posted, could you post the whole mod as a functional Git repository (e.g. on GitHub)? Look at my mod for an example of the repository structure you should have.
In future, please use Gist/Pastebin to post code snippets or classes with syntax highlighting. It's much easier to read code with proper formatting and syntax highlighting.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
It's not the main issue here, but the Side argument of SimpleNetworkWrapper#registerMessage is the side that should receive and process the message, not the side it's sent from.
I can't see any obvious issues in the snippets of code you've posted, could you post the whole mod as a functional Git repository (e.g. on GitHub)? Look at my mod for an example of the repository structure you should have.
In future, please use Gist/Pastebin to post code snippets or classes with syntax highlighting. It's much easier to read code with proper formatting and syntax highlighting.
Got a repository right here. It includes some irrelevant and unimplemented files (anything in thatmartinguy.thedarkness.block for example), but my git client was acting up, so I'm just happy that it committed properly.
Rollback Post to RevisionRollBack
Teleporting XP, for when you want to improve performance with XP farms
Got a repository right here. It includes some irrelevant and unimplemented files (anything in thatmartinguy.thedarkness.block for example), but my git client was acting up, so I'm just happy that it committed properly.
You didn't include the buildscript (the build.gradle file) or the Gradle wrapper (the gradle directory and gradlew/gradlew.bat) in the repository and you also included several files and folders that don't need to be there (.gradle, .settings, bin, build, run, .classpath, .project and the .launch files).
I'll try and get it working anyway.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
You didn't include the buildscript (the build.gradle file) or the Gradle wrapper (the gradle directory and gradlew/gradlew.bat) in the repository and you also included several files and folders that don't need to be there (.gradle, .settings, bin, build, run, .classpath, .project and the .launch files).
I'll try and get it working anyway.
Some of the files and folders were removed from the local repository I had for some reason. Anyway, updated the online one with the gradle files and removed unnecessary ones.
I've partially fixed the reliquary crafting and cleaned up your code a bit, you can see my changes here.
The reliquary can only be crafted once, but doing so duplicates the ingredients in the crafting grid. This is because ModShapedRecipe#matches returns false when called from CraftingManager#getRemainingItems after the reliquary has been crafted, so IRecipe#getRemainingItems is never called and a copy of the crafting grid is used as the remaining item array.
I'm not sure how to fix this without some hackery, but I'll take another look at it tomorrow.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Currently I have an item that has a crafting recipe. Whenever that item is crafted you can't craft it again until I explicitly tell the code that it can be crafted again. The way I made this work is by making a boolean value called isCrafted. By default this is false, but whenever the ItemCraftedEvent is called it is made true. Since it is a variable, however, this is reset every time you restart minecraft. Since I don't want this to be the case I need to have my check check something other than a variable. I think it would be possible to create a seperate file to check this, but I'd prefer not having one since the user can reset the file to craft the item again.
ModCrafting.java
OnItemCraftedEventHandler.java
Teleporting XP, for when you want to improve performance with XP farms
You can create world data which allows you to save info in NBT.
World data example here from my repo
(If you copy into your project, make sure that you make it non-abstract, may need to adapt it as well)
Acquire instance of world data via: MyWorldData#getDataForWorld(MyWorldData.class, "MyWorldData", world, false)
The boolean isReliquaryCrafted should be a field inside MyWorldData that is set/saved during the writeToNBT/readFromNBT methods (not shown in example).
Make getters and setters but call markDirty() in the setter or world data will never be saved!
Let me know if you need any further info.
~ Crows
Avatar Mod 2 -- Elemental Bending from Avatar: The Last Airbender
Contact: PM or [email protected]
You should be able to use a per-map World Saved Data to store this. For server Worlds, you should maintain a single instance, use it for every dimension (like this) and clear it when the server stops (FMLServerStoppedEvent). For client Worlds, you should use the instance stored in the MapStorage (like the example in the documentation).
Create your own implementation of IRecipe (you'll probably want to extend an existing one like ShapedRecipes or ShapedOreRecipe) and implement IRecipe#matches to check the value stored in the World Saved Data.
When the item is crafted (ItemCraftedEvent or Item#onCreated), set the value in the World Saved Data to false.
When the World Saved Data's value changes, send a packet to all clients to update their copy of the value.
When a player logs in (PlayerEvent.PlayerLoggedInEvent) or changes dimension (PlayerEvent.PlayerChangedDimensionEvent), send a packet to their client to update its copy of the value.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Thanks to both of you!
Teleporting XP, for when you want to improve performance with XP farms
I'm not sure I understand how to do this. Do you mind giving an example? For reference this is my ModWorldSaved class
Teleporting XP, for when you want to improve performance with XP farms
Extend either ShapedRecipes or ShapedOreRecipes and override the matches method to get the ReliquaryWorldData for the World argument and then return true when the super method returns true (the ingredients match) and ReliquaryWorldData#isReliquaryCrafted returns false (the reliquary hasn't been crafted).
Make sure you register this recipe class with RecipeSorter.
Your ReliquaryWorldData currently doesn't maintain a per-server instance like I recommended, so each dimension will have its own copy of the data.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Is this the right way to do it? If it is, how do I make isReliquaryCrafted true properly? While it might be obvious, calling ReliquaryWorldData#get(worldIn)#setReliquaryCrafted(true) in onCreated in the reliquary item class crashes the game.
Teleporting XP, for when you want to improve performance with XP farms
RecipeSorter.register must be called once, not every time an instance of your recipe class is created. It should be done in init.
You can't just create a new instance of ReliquaryWorldData and expect it to have the right value, you need to get the existing one by calling ReliquaryWorldData.get. If it's crashing, post the code and the crash report.
You should replace the if statement in ModShapedRecipe#matches with a return statement to return the if statement's condition. Currently the return of ReliquaryWorldData#isReliquaryCrafted is essentially ignored; the return of the super method (i.e. "do the ingredients match?") is used regardless of whether or not the reliquary has been crafted.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
The register call has been moved to a seperate init method that I call in the main mod class' init method, the matches method has been changed to
and this code block has been added in itemReliquary:
If I craft the item in game it crashes and gives me this crash log.
EDIT: Also, if I log back in the crafting ingredients are dropped on the ground (no reliquary is crafted).
Teleporting XP, for when you want to improve performance with XP farms
Refer to line 101 of ItemReliquiary; a variable is null and you tried to call a method on it.
~ Crows
Avatar Mod 2 -- Elemental Bending from Avatar: The Last Airbender
Contact: PM or [email protected]
I fixed the NullPointerException error, but I can still always create the reliquary. I added a print method to each of the methods in ReliquaryWorldData and found out that isReliquaryCrafted is never called, even if with the overridden matches method I mentioned earlier.
Teleporting XP, for when you want to improve performance with XP farms
Is the crafting recipe for the reliquary using your custom recipe class, or is it still using a vanilla shaped recipe?
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
This is probably not the right way to do it, but I did it like this:
Teleporting XP, for when you want to improve performance with XP farms
Don't add a vanilla shaped recipe, only add your custom recipe.
If you extend ShapedRecipes, you need to create the ItemStack array in the same way that CraftingManager#addRecipe(ItemStack, Object...) does.
I'd recommend extending ShapedOreRecipe instead, which takes the shape strings and ingredients like GameRegistry#addRecipe(ItemStack, Object...) and does all of this for you (with the added bonus of accepting ore dictionary ingredients).
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
After a lot of tinkering I got it to work- somewhat. The item can only be crafted once every time you start minecraft. This basically puts me in the same position as I was in originially. It seems like ReliquaryWorldData isn't saving the value properly. I added a IMessage called ReliquaryMessage and a IMessageHandler called ReliquaryMessageHandler. I also updated ReliquaryWorldData#setReliquaryCrafted. They look like this
ReliquaryWorldData#setReliquaryCrafted
ReliquaryMessage
ReliquaryMessageHandler
How I register the above classes
Teleporting XP, for when you want to improve performance with XP farms
It's not the main issue here, but the Side argument of SimpleNetworkWrapper#registerMessage is the side that should receive and process the message, not the side it's sent from.
I can't see any obvious issues in the snippets of code you've posted, could you post the whole mod as a functional Git repository (e.g. on GitHub)? Look at my mod for an example of the repository structure you should have.
In future, please use Gist/Pastebin to post code snippets or classes with syntax highlighting. It's much easier to read code with proper formatting and syntax highlighting.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Got a repository right here. It includes some irrelevant and unimplemented files (anything in thatmartinguy.thedarkness.block for example), but my git client was acting up, so I'm just happy that it committed properly.
Teleporting XP, for when you want to improve performance with XP farms
You didn't include the buildscript (the build.gradle file) or the Gradle wrapper (the gradle directory and gradlew/gradlew.bat) in the repository and you also included several files and folders that don't need to be there (.gradle, .settings, bin, build, run, .classpath, .project and the .launch files).
I'll try and get it working anyway.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Some of the files and folders were removed from the local repository I had for some reason. Anyway, updated the online one with the gradle files and removed unnecessary ones.
EDIT: Just updated build.gradle
Teleporting XP, for when you want to improve performance with XP farms
I've partially fixed the reliquary crafting and cleaned up your code a bit, you can see my changes here.
The reliquary can only be crafted once, but doing so duplicates the ingredients in the crafting grid. This is because ModShapedRecipe#matches returns false when called from CraftingManager#getRemainingItems after the reliquary has been crafted, so IRecipe#getRemainingItems is never called and a copy of the crafting grid is used as the remaining item array.
I'm not sure how to fix this without some hackery, but I'll take another look at it tomorrow.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.