Jump to content

[1.12.2] Stuck getting started; need simple example


JoeStrout

Recommended Posts

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:

 

  1. 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.
  2. 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

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

Append to the message rather than displaying a new message.

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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!

 

 

Link to comment
Share on other sites

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?

 

Link to comment
Share on other sites

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.

  • Like 1

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.

Link to comment
Share on other sites

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 by JoeStrout
figured it out
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.