JoeStrout
Members-
Posts
39 -
Joined
-
Last visited
Everything posted by JoeStrout
-
Really? The ParticleMagic class shown above was nothing but overriding that method; take that out, and it has no data and no methods. How does that make a custom particle? (Unless there was more code to it that wasn't considered relevant in the original post.) Instead of repeating what to not do, it'd be great if somebody could show or say what one should do. @MSpace-Dev, can you share your working solution?
-
how to properly change the world from a client event?
JoeStrout replied to JoeStrout's topic in Modder Support
That all makes great sense. And it's good to know about registering commands — while I'm currently just doing quick hacks to explore various bits of the API, I may as well do them properly! -
(I apologize for all the questions this week... I'm sure things will "click" for me soon, and later when I know what I'm doing, I promise to repay my karma by helping newbies whenever I can!) I have a ClientChatEvent handler from which I wish to change the world — for starters, just clear a block to air. I have no trouble telling what block the user is looking at, and I can call world.setBlockToAir and it clears the block locally... but it fails to do an update (so water doesn't flow into the new hole, for example), and of course this is a blatant siding violation. But though I think I understand the concept of sides — and the rule that any world changes need to happen on the logical server — I'm still clueless as to how to actually do that. One post I found here recommended wrapping any state changes in if (!world.isRemote), but when I do that, then world.setBlockToAir simply doesn't get called at all. Current, non-working code looks like this: @SubscribeEvent public static void onChat(ClientChatEvent event) { String msg = event.getMessage(); if (msg.equals("/evanesco")) { // Vanish whatever we're pointed at RayTraceResult trace = PointingAt(); // (helper method, don't worry about it) if (trace == null || trace.typeOfHit == RayTraceResult.Type.MISS) { SendStatus("§6Whiff!§r"); } else { BlockPos pos = trace.getBlockPos(); // sort-of works, but is a siding violation, and doesn't update water etc: //Minecraft.getMinecraft().world.setBlockToAir(pos); // attempt to do it more properly: WorldClient world = Minecraft.getMinecraft().world; if (!world.isRemote) { world.setBlockToAir(pos); System.out.println("Set block to air on the server"); } else { // (this is what actually happens in my tests) System.out.println("Not on the server, so doing nothing"); } world.playSound(Minecraft.getMinecraft().player, pos, SoundEvents.ENTITY_ENDERMEN_TELEPORT, SoundCategory.PLAYERS, 1.0F, 1.0F); SendStatus("§5Shoop!§r"); } event.setCanceled(true); } } Can anyone point me in the right direction for going from my client-side event detection, to changing block states on the server?
-
[1.12.2] Stuck getting started; need simple example
JoeStrout replied to JoeStrout's topic in Modder Support
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! -
[1.12.2] Stuck getting started; need simple example
JoeStrout replied to JoeStrout's topic in Modder Support
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? -
I'm trying to catch LivingJumpEvent and log to the console (following Jabelar's excellent article). But it's not working — no matter how I jump around, I see no logging in the console. Other events subscribed in the same class do work, so I don't know what the problem could be. But since I don't know what it might be, here's the whole class: package net.strout.mod1; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.text.*; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.client.event.*; import net.minecraftforge.event.entity.living.LivingEvent.*; import net.minecraftforge.event.entity.player.*; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; // Note: for a great explanation of Forge events, see: // http://jabelarminecraft.blogspot.com/p/minecraft-forge-172-event-handling.html @Mod.EventBusSubscriber public class MyForgeEventHandler { private static void SendStatus(String message) { Minecraft.getMinecraft().player.sendStatusMessage(new TextComponentString(message), false); } @SubscribeEvent public static void pickupItem(EntityItemPickupEvent event) { System.out.println("Item picked up:" + event.getItem()); SendStatus("You picked up a " + event.getItem()); } @SubscribeEvent(priority=EventPriority.HIGHEST, receiveCanceled=true) public void onLivingJump(LivingJumpEvent event) { if (event.getEntity() instanceof EntityPlayer) { System.out.println("Boing"); } else { System.out.println("get LivingJumpEvent, but not with EntityPlayer?!"); } } @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. SendStatus("<§rVoice In Your Head§r> §rHi yourself.§r"); } } @SubscribeEvent public static void onChat(ClientChatEvent event) { String msg = event.getMessage(); if (msg.equals("/test")) { event.setCanceled(true); SendStatus("This is a test. This is only a test."); } else if (msg.equals("/menu")) { event.setCanceled(true); // Does not actually work in our testing: Minecraft.getMinecraft().displayInGameMenu(); } else if (msg.equals("/apparate")) { event.setCanceled(true); Minecraft.getMinecraft().player.setPositionAndUpdate(50, 66, 250); SendStatus("§6You apparate.§r"); } } } (Sorry for the poor indentation — it appears that Eclipse has mixed tabs and spaces, how lovely.) I've tried the @SubscribeEvent both with and without the optional parameters; no difference. Any idea why my LivingJumpEvent handler isn't getting invoked?
-
[1.12.2] Stuck getting started; need simple example
JoeStrout replied to JoeStrout's topic in Modder Support
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! -
[1.12.2] can't get localized display name to appear
JoeStrout replied to JoeStrout's topic in Modder Support
Oops, looks like we must have found some old docs/samples. I'll look into this right away. That's it! Renaming the file to en_us.lang did the trick. Thanks very much! -
We're stumped on getting this to work, despite considerable googling and experimentation. Here's the item declaration: @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("Registered item: " + testItem.getRegistryName()); ForgeRegistries.ITEMS.register(testItem); } Note the println there showing us the registry name; when we launch, it shows "stroutmod1:stroutmod1_testitem1". Now we have a en_US.lang file at stroutmod1/src/main/resources/assets/stroutmod1/lang/en_US.lang. It's UTF-8 with no BOM, and contains: item.stroutmod1:stroutmod1_testitem1.name=Test Item Yet when we run the game, the item shows up as "item.stroutmod1:stroutmod1_testitem1.name" rather than "Test Item". Any idea what we're missing?
-
[1.12.2] Stuck getting started; need simple example
JoeStrout replied to JoeStrout's topic in Modder Support
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. -
[1.12.2] Stuck getting started; need simple example
JoeStrout replied to JoeStrout's topic in Modder Support
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! -
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