JoeStrout Posted December 27, 2017 Posted December 27, 2017 My son and I are trying to get started making MC mods. We're using Forge 1.12.2 and gradle, and following the Forge docs. We've got as far as successfully printing to stdout in the pre-init, init, and post-init events. But everything else we've attempted (including copying & pasting the snippets in the docs) has so far failed. This is not because we don't understand Java; it's because we don't understand the Forge API. So I have two related questions: Does anyone have a simple full example of doing something more? Adding a simple new block or item type (of the sort that doesn't require a custom subclass), perhaps. Or responding to a chat event by chatting back. Or something similarly trivial. Where is the API reference documentation? For example, all the events that can be registered for, and all the methods we can call to affect things in the game? Or do we just trawl the Forge source code for that? Many thanks, - Joe Quote
American2050 Posted December 28, 2017 Posted December 28, 2017 YouTube is also a good source if you like watching videos over reading documentation. The basics can be learn from those videos. Just try to find updated content from 1.12 as old videos for other Forge versions may be not so accurate and basic stuff wont work. Quote
JoeStrout Posted December 28, 2017 Author Posted December 28, 2017 OK, thanks all. We were trying to code with just a text editor, but it seems that Eclipse (or similar) is pretty much required for this work. Incidentally, we managed to get a simple example put together that responds to chat events. We put this in a separate class from the main entry class (the one identified with @Mod), like so: package net.strout.mod1; import net.minecraft.client.Minecraft; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.client.event.ClientChatEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber public class MyForgeEventHandler { @SubscribeEvent public static void onChat(ClientChatEvent event) { String msg = event.getMessage(); System.out.println("ClientChatEvent: " + msg); if (msg.contains("Hello")) { Minecraft.getMinecraft().player.sendChatMessage("Hi Yourself!"); } else if (msg.contains("Bye")) { Minecraft.getMinecraft().player.sendChatMessage("Later!"); } } } The only funny thing about this is that the responses appear before your own input in the chat log (since the chat event is not fully processed at this point). If we were making a more serious chat mod, we'd have to solve that... but for the sake of a "hello world" level example to get started, I think this is good enough. The key bit is importing the correct stuff at the top to avoid the dreaded "cannot find symbol" errors. Eclipse will more or less automatically fill those in for you, or you can look in MinecraftByExample and discover the necessary imports from there. Hopefully this will be helpful to the next poor soul who comes along! Quote
Draco18s Posted December 28, 2017 Posted December 28, 2017 Append to the message rather than displaying a new message. Quote Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable. If you think this is the case, JUST REPORT ME. Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice. Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked. DO NOT PM ME WITH PROBLEMS. No help will be given.
JoeStrout Posted December 28, 2017 Author Posted December 28, 2017 10 hours ago, Draco18s said: Append to the message rather than displaying a new message. That appends the new text on the same line (even when I insert a "\n" or a System.getProperty("line.separator")). To get the effect I was after, I had to go to more extreme measures, like so: @SubscribeEvent public static void onChatReceived(ClientChatReceivedEvent event) { ITextComponent msg = event.getMessage(); String formattedText = msg.getFormattedText(); System.out.println("Chat type " + event.getType() + " received: " + formattedText); String plaintext = msg.getUnformattedText().toLowerCase(); if (plaintext.contains("hello")) { // Cancel the event, so the player doesn't see the given message AFTER our response. event.setCanceled(true); // Display the given message immediately. Minecraft.getMinecraft().player.sendStatusMessage(msg, false); // Then, display our response. Minecraft.getMinecraft().player.sendStatusMessage(new TextComponentString( "<§rVoice In Your Head§r> §rHi yourself.§r"), false); } } I don't know if all those §r (reset) formatting codes are actually necessary, but that's how the player messages are formatted, so I'm doing the same thing in the response. Quote
JoeStrout Posted December 28, 2017 Author Posted December 28, 2017 Also, here's the main entry class that illustrates adding a simple item type. Posting here for posterity in case somebody else finds it useful, and also so I can dig it up later if I decide to write my own beginner modding tutorial. package net.strout.mod1; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; @Mod(modid = StroutMod1.MODID, version = StroutMod1.VERSION) @Mod.EventBusSubscriber public class StroutMod1 { public static final String MODID = "stroutmod1"; public static final String VERSION = "0.1"; public static Item testItem; @EventHandler public void preinit(FMLPreInitializationEvent event) { System.out.println("PRE-INITIALIZATION"); testItem = (Item)(new Item()); testItem.setRegistryName("stroutmod1_testitem1"); testItem.setUnlocalizedName(testItem.getRegistryName().toString()); testItem.setCreativeTab(CreativeTabs.MISC); System.out.println("Created item: " + testItem.getRegistryName()); } @SubscribeEvent public static void registerBlocks(RegistryEvent.Register<Item> event) { event.getRegistry().registerAll(testItem); System.out.println("Registered item: " + testItem.getRegistryName()); } @EventHandler public void init(FMLInitializationEvent event) { System.out.println("INITIALIZATION"); // Just some sample code showing how to get info on common blocks: System.out.println("DIRT BLOCK >> " + Blocks.DIRT.getUnlocalizedName()); // Register the model for our custom item type. // Assumes a properly named and located JSON file, in this case: // models/item/stroutmod1_testitem1.json ModelResourceLocation res = new ModelResourceLocation(testItem.getRegistryName(), "inventory"); Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(testItem, 0, res); } @EventHandler public void postinit(FMLPostInitializationEvent event) { System.out.println("POST-INITIALIZATION"); } } And of course, if anybody spots anything I'm doing wrong, please do educate me! Quote
JoeStrout Posted December 28, 2017 Author Posted December 28, 2017 3 hours ago, diesieben07 said: One thing, Problematic code, issue 2. OK, thanks for that. I see that I should use ModelLoader.setCustomModelResourceLocation in ModelRegistryEvent to register your item models, rather than ItemModelMesher. But I've been learning mostly from the MinecraftByExample project, which does not do it this way, and I'm having trouble getting it to work. Here's what I've got: @EventHandler public void registerModels(ModelRegistryEvent event) { ModelResourceLocation res = new ModelResourceLocation(testItem.getRegistryName(), "inventory"); ModelLoader.setCustomModelResourceLocation(testItem, 0, res); System.out.println("Set model for " + testItem.getRegistryName() + " to " + res); } This is in my main class (shown a couple posts up), which is marked with @Mod and @Mod.EventBusSubscriber, and successfully gets other events (for example RegistryEvent.Register<Item>). But this ModelRegistryEvent doesn't appear to get invoked; I never see the console output from this method. And as a result, my beautiful frog texture has reverted to the purple checkerboard no-texture texture. What am I doing wrong? Quote
jeffryfisher Posted December 28, 2017 Posted December 28, 2017 20 hours ago, JoeStrout said: Does anyone have a simple full example of doing something more? You can Google for "github" at site:http://www.minecraftforge.net/forum/topic You can go to github and then search for Forge projects. Stick to mods using the same version of Minecraft (1.12.2). After looking at a few, you'll quickly distinguish between matters of style versus matters of necessity. You'll also quickly get a sense for who knows what he's doing (and who knows even less than you do). Once you've settled on one or two worthy examples, emulate them (don't cut and paste). You learn by assimilating and doing. Finally, when you are getting ready to run something, run it in debug mode (with some break points set within your own code). Step through and into the various methods, examining some of the changing fields as you go. More than any static examination of vanilla code can ever teach you, a ride-through will illuminate how the program functions. Try to scan each operation at least once so you have some idea how it hangs together. No need to sit through 500 cycles of a loop, but try a few at least once. And have fun. 1 Quote The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
JoeStrout Posted December 28, 2017 Author Posted December 28, 2017 (edited) 1 hour ago, diesieben07 said: @EventHandler is only used for the FML lifecycle events (subtypes of FMLEvent). You need to use @SubscribeEvent to subscribe to the modern forge-style events (subtypes of Event). Ah, OK, I should have known that. Unfortunately, I've changed it to @SubscribeEvent and it's still not getting called. EDIT: I had also failed to make it a static method. Oops! All good now. Thanks everyone for the help! Edited December 28, 2017 by JoeStrout figured it out Quote
Daeruin Posted December 29, 2017 Posted December 29, 2017 Check out Shadowfacts' tutorials for the basics of creating blocks and items. Also check out Choonster's TestMod3 for lots of examples. 1 Quote
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.