Jump to content

[1.12] Recipe registry


Kokkie

Recommended Posts

Hi, I'm trying the new registry using events, but I seem to get a nullpointer exception. The console is not helping at all. Here's my code.

Main class.

@Mod(modid = Reference.ID, name = Reference.NAME, version = Reference.VERSION, acceptedMinecraftVersions = "[" + Reference.MC_VERSION + "]")
public class AutoMiner {

	@Instance
	public static AutoMiner INSTANCE = new AutoMiner();

	@SidedProxy(clientSide = Reference.CLIENT_PROXY, serverSide = Reference.COMMON_PROXY)
	public static CommonProxy PROXY = new CommonProxy();

	@EventHandler
	public static void preInit(FMLPreInitializationEvent event) {
		MinecraftForge.EVENT_BUS.register(new AMRegistryHandler());
		new AMItems();
		new AMBlocks();
		new AMEntities();
		new AMRecipes();

		PROXY.setTitle("Minecraft - " + Reference.MC_VERSION + " AutoMiner - " + Reference.VERSION);
	}

	@EventHandler
	public static void init(FMLInitializationEvent event) {

	}

	@EventHandler
	public static void postInit(FMLPostInitializationEvent event) {

	}
}

Handler.

public class AMRegistryHandler {

	@SubscribeEvent
	public static void registerBlocks(RegistryEvent.Register<Block> event) {
		event.getRegistry().registerAll(AMBlocks.BLOCKS);
	}

	@SubscribeEvent
	public static void registerItems(RegistryEvent.Register<Item> event) {
		event.getRegistry().registerAll(AMItems.ITEMS);
		for (int i = 0; i < AMBlocks.BLOCKS.length; i++) {
			Block block = AMBlocks.BLOCKS[i];
			event.getRegistry().register(new ItemBlock(block).setRegistryName(block.getRegistryName())
					.setUnlocalizedName(block.getUnlocalizedName()));
		}
	}

	@SubscribeEvent
	public static void registerModels(ModelRegistryEvent event) {
		for (int i = 0; i < AMBlocks.BLOCKS.length; i++) {
			Block block = AMBlocks.BLOCKS[i];
			ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(block), 0,
					new ModelResourceLocation(block.getRegistryName(), "inventory"));
		}

		for (int i = 0; i < AMItems.ITEMS.length; i++) {
			Item item = AMItems.ITEMS[i];
			ModelLoader.setCustomModelResourceLocation(item, 0,
					new ModelResourceLocation(item.getRegistryName(), "inventory"));
		}
	}

}

Blocks class.

public class AMBlocks {

	public static final Block STEEL_BLOCK = new Block(Material.IRON).setCreativeTab(AMTabs.AM_TAB).setHardness(8.0F)
			.setResistance(15.0F);
	public static final Block AUTO_MINER = new BlockAutoMiner().setCreativeTab(AMTabs.AM_TAB).setHardness(7.0F)
			.setResistance(20.0F);
	public static final Block[] BLOCKS = new Block[] { STEEL_BLOCK, AUTO_MINER };

	public AMBlocks() {
		STEEL_BLOCK.setHarvestLevel("pickaxe", 2);
		AUTO_MINER.setHarvestLevel("pickaxe", 1);
		AMUtils.setNames(STEEL_BLOCK, "steel_block");
		AMUtils.setNames(AUTO_MINER, "auto_miner");
	}
}

Items class.

public class AMItems {

	public static final Item STEEL_INGOT = new Item().setCreativeTab(AMTabs.AM_TAB);
	public static final Item WRENCH = new Item().setCreativeTab(AMTabs.AM_TAB).setMaxDamage(128).setMaxStackSize(1);
	public static final Item[] ITEMS = new Item[] { STEEL_INGOT, WRENCH };

	public AMItems() {
		AMUtils.setNames(STEEL_INGOT, "steel_ingot");
		AMUtils.setNames(WRENCH, "wrench");
	}
}

Also, the error in the console.

java.lang.NullPointerException: Initializing game
	at net.minecraft.client.util.SearchTree.lambda$func_194042_b$0(SearchTree.java:57)
	at java.util.ArrayList.forEach(Unknown Source)
	at net.minecraft.client.util.SearchTree.func_194042_b(SearchTree.java:55)
	at net.minecraft.client.util.SearchTree.func_194043_a(SearchTree.java:50)
	at java.util.ArrayList.forEach(Unknown Source)
	at net.minecraft.client.Minecraft.func_193986_ar(Minecraft.java:640)
	at net.minecraft.client.Minecraft.init(Minecraft.java:565)
	at net.minecraft.client.Minecraft.run(Minecraft.java:411)
	at net.minecraft.client.main.Main.main(Main.java:118)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
	at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97)
	at GradleStart.main(GradleStart.java:26)

 

Edited by Kokkie

Classes: 94

Lines of code: 12173

Other files: 206

Github repo: https://github.com/KokkieBeer/DeGeweldigeMod

Link to comment
Share on other sites

Registry events are fired before preInit, so you need to annotate the event handler class with @Mod.EventBusSubscriber to automatically register it at mod construction time (or register it manually). In addition to this, you're registering an instance of the event handler but your methods are static; which is incorrect. Static event handler methods require you to register the Class object rather than an instance, as explained in the documentation.

 

You need to set the registry name of an IForgeRegistryEntry like Block or Item before you register it.

 

Having a constructor modify static fields in a class where there there are no instance fields or methods and calling this constructor purely for the side-effects is very strange and probably a bad idea. If you need to do more stuff to the Items in preInit, create a regular static method instead of a constructor.

 

ModelLoader is a client-only class and can't be referenced from common code. ModelRegistryEvent should be handled in a client-only class that's only registered with the event bus on the physical client (pass Side.CLIENT to the @Mod.EventBusSubscriber annotation or manually register it in a method only called on the physical client).

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I no longer get any errors, but the items and blocks aren't registered. The events aren't fired...

Main.

@Mod(modid = Reference.ID, name = Reference.NAME, version = Reference.VERSION, acceptedMinecraftVersions = "[" + Reference.MC_VERSION + "]")
public class AutoMiner {

	@Instance
	public static AutoMiner INSTANCE = new AutoMiner();

	@SidedProxy(clientSide = Reference.CLIENT_PROXY, serverSide = Reference.COMMON_PROXY)
	public static IProxy PROXY;

	@EventHandler
	public static void preInit(FMLPreInitializationEvent event) {
		PROXY.registerEntities();
		PROXY.registerRecipes();

		PROXY.setTitle("Minecraft - " + Reference.MC_VERSION + " AutoMiner - " + Reference.VERSION);
	}

	@EventHandler
	public static void init(FMLInitializationEvent event) {

	}

	@EventHandler
	public static void postInit(FMLPostInitializationEvent event) {

	}
}

IProxy.

public interface IProxy {

	void setTitle(String title);

	void registerEntities();
	
	void registerRecipes();

}

CommonProxy.

public class CommonProxy implements IProxy {

	@Override
	public void setTitle(String title) {
	}

	@Override
	public void registerEntities() {
		GameRegistry.registerTileEntity(TileEntityAutoMiner.class, "AutoMiner");
	}

	@Override
	public void registerRecipes() {
		AMUtils.addShapedRecipe("wrench", new ItemStack(AMItems.WRENCH), "S S", "SSS", " S ", 'S', AMItems.STEEL_INGOT);
		AMUtils.addShapedRecipe("auto_miner", new ItemStack(AMBlocks.AUTO_MINER), "SSS", "SPS", "SSS", 'S',
				AMItems.STEEL_INGOT, 'P', Items.IRON_PICKAXE);
	}
}

ClientProxy.

public class ClientProxy implements IProxy {

	@Override
	public void setTitle(String title) {
		Display.setTitle(title);
	}

	@Override
	public void registerEntities() {
	}

	@Override
	public void registerRecipes() {
	}
}

Blocks.

public class AMBlocks {
	public static final Block STEEL_BLOCK = new Block(Material.IRON).setCreativeTab(AMTabs.AM_TAB).setHardness(8.0F)
			.setResistance(15.0F).setRegistryName("steel_block").setUnlocalizedName("steel_block");
	public static final Block AUTO_MINER = new BlockAutoMiner().setCreativeTab(AMTabs.AM_TAB).setHardness(7.0F)
			.setResistance(20.0F).setRegistryName("auto_miner").setUnlocalizedName("auto_miner");
	public static final Block[] BLOCKS = new Block[] { STEEL_BLOCK, AUTO_MINER };
}

Items.

public class AMItems {
	public static final Item STEEL_INGOT = new Item().setCreativeTab(AMTabs.AM_TAB).setRegistryName("steel_ingot")
			.setUnlocalizedName("steel_ingot");
	public static final Item WRENCH = new Item().setCreativeTab(AMTabs.AM_TAB).setMaxDamage(128).setMaxStackSize(1)
			.setRegistryName("wrench").setUnlocalizedName("wrench");
	public static final Item[] ITEMS = new Item[] { STEEL_INGOT, WRENCH };
}

Client Handler.

@Mod.EventBusSubscriber(modid = Reference.ID, value = Side.CLIENT)
public class AMClientHandler {
	@SubscribeEvent
	public void registerModels(ModelRegistryEvent event) {
		for (int i = 0; i < AMBlocks.BLOCKS.length; i++) {
			Block block = AMBlocks.BLOCKS[i];
			ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(block), 0,
					new ModelResourceLocation(block.getRegistryName(), "inventory"));
		}

		for (int i = 0; i < AMItems.ITEMS.length; i++) {
			Item item = AMItems.ITEMS[i];
			ModelLoader.setCustomModelResourceLocation(item, 0,
					new ModelResourceLocation(item.getRegistryName(), "inventory"));
		}
	}
}

Common Handler.

@Mod.EventBusSubscriber(modid = Reference.ID, value = Side.SERVER)
public class AMCommonHandler {
	@SubscribeEvent
	public void registerBlocks(RegistryEvent.Register<Block> event) {
		AMBlocks.STEEL_BLOCK.setHarvestLevel("pickaxe", 2);
		AMBlocks.AUTO_MINER.setHarvestLevel("pickaxe", 1);
		event.getRegistry().registerAll(AMBlocks.BLOCKS);
	}

	@SubscribeEvent
	public void registerItems(RegistryEvent.Register<Item> event) {
		event.getRegistry().registerAll(AMItems.ITEMS);
		for (int i = 0; i < AMBlocks.BLOCKS.length; i++) {
			Block block = AMBlocks.BLOCKS[i];
			event.getRegistry().register(new ItemBlock(block).setRegistryName(block.getRegistryName())
					.setUnlocalizedName(block.getUnlocalizedName()));
		}
	}
}

 

Classes: 94

Lines of code: 12173

Other files: 206

Github repo: https://github.com/KokkieBeer/DeGeweldigeMod

Link to comment
Share on other sites

Does this happen if you switch the for-loop to for-each loops? eg for(Block block : AMBlocks.BLOCKS){...}
You can also try to switch over to lambda's. For arrays, you need to use Arrays.stream(array) to be able to call forEach()

Also previously known as eAndPi.

"Pi, is there a station coming up where we can board your train of thought?" -Kronnn

Published Mods: Underworld

Handy links: Vic_'s Forge events Own WIP Tutorials.

Link to comment
Share on other sites

It seems to have gone away... But now it's stuck on the while loop in here...

		if (recipeComponents[i] instanceof String[]) {
			String[] astring = (String[]) ((String[]) recipeComponents[i++]);

			
			for (int s3 = 0; s3 < astring.length; s3++) {
				String s2 = astring[s3];
				++k;
				j = s2.length();
				s = s + s2;
			}
		} else {
			while (recipeComponents[i] instanceof String) {
				String s1 = (String) recipeComponents[i++];
				++k;
				j = s1.length();
				s = s + s1;
			}
		}

 

Classes: 94

Lines of code: 12173

Other files: 206

Github repo: https://github.com/KokkieBeer/DeGeweldigeMod

Link to comment
Share on other sites

I see 2 possible exit conditions to this loop:

1. recipeComponents is not a string, the loop exits normally.

2. i => recipeComponents.length(the last element of the recipeComponents array is a string), the loop throws an ArrayIndexOutOfBounds exception and the exception is passed along potentially crashing the game. That could be your issue.

1 hour ago, Kokkie said:

(String[]) ((String[]) recipeComponents[i++]);

Why is there a String[] to String[] cast? Isn't it a tad bit redundant?

Edited by V0idWa1k3r
Link to comment
Share on other sites

Set a breakpoint in the lambda with the condition p_194039_2_ == null. When the breakpoint is hit, look at the value of the element parameter to see which Item has a null registry name.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

3 hours ago, Kokkie said:

@Mod.EventBusSubscriber(modid = Reference.ID, value = Side.SERVER)

Correct me if I'm wrong but I think that this value param is dictating the physical side for the forge to run the subscribption on(FMLCommonHandler::getSide) and not the logical side(FMLCommonHandler::getEffectiveSide)? Therefore if the SERVER is specified as a side here would FML not subscribe the class to the event bus unless the code is running on an actual server(that is the Minecraft Server is chosen as a run configuration or the user launches a server)?

In any case blocks(and items) being in the registry is a common thing. It makes no sense for them to only be present on the server, the client needs to know about them too.

Edited by V0idWa1k3r
Link to comment
Share on other sites

40 minutes ago, Choonster said:

Set a breakpoint in the lambda with the condition p_194039_2_ == null. When the breakpoint is hit, look at the value of the element parameter to see which Item has a null registry name.

How can I set that condition?

Classes: 94

Lines of code: 12173

Other files: 206

Github repo: https://github.com/KokkieBeer/DeGeweldigeMod

Link to comment
Share on other sites

Have you removed 

4 hours ago, Kokkie said:

value = Side.SERVER

from your 

 

4 hours ago, Kokkie said:

AMCommonHandler

's EventBusSubscriber annotation(that you have now called AMServerHandler)?

Just leave the annotation be as EventBusSubscriber(modid = Reference.ID) and check if that helps.

 

As I've said objects being in registry is common for both client and server, it makes no sense for the server only to have them registered, the client needs it too.

Edited by V0idWa1k3r
Link to comment
Share on other sites

Your methods in the AMServerHandler(and in your AMClientHandler) are not annotated with SubscribeEvent. Even if you annotate the class with EventBusSubscriber you still need to annotate the methods that you want to be listening for the event specified.

Also CraftingManager.register is private in the latest versions of forge, so you must use the appropriate registry event.

Link to comment
Share on other sites

5 minutes ago, V0idWa1k3r said:

Your methods in the AMServerHandler(and in your AMClientHandler) are not annotated with SubscribeEvent. Even if you annotate the class with EventBusSubscriber you still need to annotate the methods that you want to be listening for the event specified.

Just noticed that :D.

5 minutes ago, V0idWa1k3r said:

Also CraftingManager.register is private in the latest versions of forge, so you must use the appropriate registry event.

Is the event in newer versions of Forge? (I have 14.21.0.2321)

Also, the wrench recipe now works :D.

Edited by Kokkie

Classes: 94

Lines of code: 12173

Other files: 206

Github repo: https://github.com/KokkieBeer/DeGeweldigeMod

Link to comment
Share on other sites

IRecipe is a IForgeRegistryEntry as are all it's implementations at least in 14.21.0.2343 so there should be an event for them. Not sure about the version you are using. 

The recipes and registries have been going through a lot of changes recently and will go through a lot more so I usually try to stay on the latest available version so I have the chance to adapt to the changes gradualy instead of having to rewrite everything once things settle down.

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.