Jump to content

[1.7.x] Modding with Forge #3b - An Empty Mod File (and Hard-Coding mcmod.info)


Recommended Posts

[1.7.x] Modding with Forge #3b - An Empty Mod File (and Hard-Coding mcmod.info)

 

Hello and welcome to part 2 of Modding with Forge #3. After receiving a few requests, I have decided to do a brief tutorial on creating an empty mod file for Forge for Minecraft 1.7.10 (although this works with 1.7.2, too).

 

Before I launch into this tutorial, I would just like to highlight the new location of these tutorials; the MinecraftForge forums, as opposed to the MinecraftForums. The reason for this is purely aesthetic but I feel that the community would much rather read nicely formatted, nicely printed tutorials with associated code, hence the change.

 

Enough babble, though; onto the actual tutorial.

 

The first thing we are going to want to do is create a new class within the 'src/main/java' folder. I am going to call my class 'Tutorial' and put it in a package called 'tutorial'. By using Eclipse, we will now have a pre-generated class file:

package tutorial;

public class Tutorial {

}

 

Currently, our mod is not going to be recognised as one; to make sure that Forge loads our mod as that, we need to provide an annotation above our class declaration; @Mod, making sure to import it when you do:

import cpw.mods.fml.common.Mod;

@Mod()

public class Tutorial {

}

 

You will be receiving an error on the @Mod annotation, currently, stating "The annotation @Mod must define the attribute modid". So, inside the parentheses, type the following:

@Mod
(
	modid = "Tutorial"
)

 

The main thing to remember about the 'modid' attribute is that it must be unique. Every single mod ever created for Minecraft using Minecraft Forge or Forge ModLoader has had to define a unique mod ID. For testing purposes, using the ID "Tutorial" will work, since you won't have any other mods in your workspace with this ID. However, make sure this is changed to a unique name before you release it for use outside of your workspace.

 

If you take a look at the source code for the @Mod annotation, you will see that there are several other attributes that we could provide. We are going to add an additional four attributes at this point:

@Mod
(
	modid				= "Tutorial",
	name 				= "",
	version 				= "",
	dependencies 			= "",
	acceptedMinecraftVersions	= ""
)

 

As I said, we are going to add four more attributes, each shown above. The 'name' attribute, obviously, is the name of your mod. I will call my mod "Modding with Forge", to accompany the name of this series. Similarly, the 'version' attribute is the version of your mod; in my case, "Tutorial #3b". These two, along with 'name', are the typically used attributes; 'dependencies' and 'acceptedMinecraftVersions' are less commonly used but can be very useful with enforcing players use up-to-date versions of Minecraft or Forge (if new methods are introduced to Forge that you use, for example, that are not in older versions). The 'dependencies' attribute is also helpful if you are developing a mod that requires another mod to run (e.g. an IndustrialCraft2 addon), or you simply want your mod to load after other mods (GregTech loads after almost every mod imaginable to ensure it can f**k with each and every recipe).

 

In this case, we aren't developing an addon for a mod, so our only dependency is Minecraft Forge itself. There are two 'types' of dependency; "required-after" and "after". In the case of GregTech, it's dependency includes a lot of 'after' cases; this means that a certain mod (e.g. Thermal Expansion) does not have to be installed, but, if it is, GregTech will load after it, giving GregTech access to all of Thermal Expansion's blocks, recipes, etc. In the case of, for example, Advanced Machines (an IndustrialCraft2 addon), IC2 is required, so the "required-after" case is used. Our mod relies on Minecraft Forge being installed, so we will use the "required-after" case:

dependencies = "required-after:Forge"

 

The above code will work absolutely fine, but it allows the mod user to have any version of Minecraft Forge installed (Minecraft Forge v2.0 would be accepted as a dependency) and we don't necessarily want this. In fact, we definitely don't want this; we want the mod user to have the version of Forge installed that we are using in our workspace. To do this, we need to specify the version:

dependencies = "required-after:Forge@[10.13.1.1217]"

 

The above code is better than the previous, but we are now forcing the mod user to use only Minecraft Forge version 10.13.1.1217. We don't want this; we simply want them to have at least version 10.13.1.1217 installed. To do this, we alter the final character of the string:

dependencies = "required-after:Forge@[10.13.1.1217,)"

 

This string used as the dependencies means that the mod user needs a minimum of Minecraft Forge 10.13.1.1217 installed, but any build later than that will still let the client run and satisfy the conditions of our mod's dependency. If we wanted to add another dependency (such as IndustrialCraft2), we would use a semi-colon:

dependencies = "required-after:Forge@[10.13.1.1217,); required-after:...; after:..."

 

We can do this for as many dependencies as we would like. We are going to stick with using just Minecraft Forge for now, though.

 

The final attribute that we need to provide is 'acceptedMinecraftVersions'. As the name suggests, this is the versions of Minecraft that will run our mod. This is specified in a similar way to the 'dependencies' attribute above:

acceptedMinecraftVersions = "[1.7.2]"

 

This string would lock our mod to only be playable on Minecraft 1.7.2 (which would not be possible with the Minecraft Forge version we have installed, but you get the idea). To define multiple Minecraft versions, we, again, change the final character:

acceptedMinecraftVersions = "[1.7.2,1.7.10,)"

 

Our finalised @Mod annotation should now look something like this:

@Mod
(
	modid				= "Tutorial",
	name 				= "Modding with Forge",
	version 				= "Tutorial #3b",
	dependencies 			= "required-after:Forge@[10.13.1.1217,)",
	acceptedMinecraftVersions	= "[1.7.2,1.7.10,)"
)

 

If you run your client now, the text in the bottom corner of the screen should now say that there are 4 mods loaded and your mod should appear in the mod list. If you select it, there will be some text displayed on the right that says:

Modding with Forge
Version: Tutorial #3b
Mod State: Available
No mod information found
Ask your mod author to provide a mod mcmod.info file

 

So, let's quickly create an "mcmod.info" file and I will show you how to hard-code the values into the file. Inside your "src/main/resources" folder, create a new file called "mcmod.info". The first thing you are going to want to do in this file is create a pair of square brackets, followed by a set of braces:

[
{

}
]

 

Inside of the braces, you will need to write the following:

[
{
	"modid":	"Tutorial",
	"name":	"Modding with Forge"
}
]

 

You need to make sure that the values for both "modid" and "name" are identical to the values you set in the @Mod annotation for the 'modid' and 'name' attributes. If you launch your client, again, there will be a slightly different screen when you select your mod from the mod list. This time, it should read something like:

Modding with Forge
Version: (Tutorial #3b)
Mod ID: 'Tutorial' Mod State: Available
Authors:
URL:
No child mods for this mod

 

You may also notice that two buttons have appeared on the bottom left of the screen; one is a disabled button called "Config" and the other is a button with red text that reads "Disable". I will explain the purpose of the "Config" button in more detail in the following tutorial, but the "Disable" button is added for client-only mods (e.g. mini-map mods, NotEnoughItems, etc). It essentially allows the mod user to disable the mod (obviously) from inside their client, rather than having to close Minecraft, remove the mod from their mod folder and relaunch the client. If you are planning on creating a client-only mod that supports in-game disabling, simply add the following line to your @Mod annotation:

canBeDeactivated = true

 

Most of the time, however, you will not want your mod to be disabled from in-game (any mod that adds any sort of content, such as a block or item), since this will cause syncing issues with the server and likely cause severe problems for your mod users.

 

Back to the mcmod.info file. Now that Minecraft reads our basic mcmod.info file, it is time to hard-code some values into it. To do this, we are going to need to add some new methods to our Tutorial class. Well, we technically only need to add one method for now, but, still.

 

The first thing you are going to want to do is create another annotation; this time, it will read @Mod.EventHandler. At the moment, you will now get an error on this annotation, stating "Syntax error, insert "EnumBody" to complete BlockStatement". To anybody who doesn't quite understand what this means (myself included), you need to add a "EnumBody" (i.e. a method) beneath it:

@Mod.EventHandler
public void preInit() {

}

 

Now, the reason for the annotation above the preInit() method is that Forge will know to call this method during it's loading stages. However, it does not know at what stage of loading it needs to call the preInit() method. To specify this, we are going to add a parameter to our method; FMLPreInitializationEvent:

@Mod.EventHandler
public void preInit (FMLPreInitializationEvent event) {

}

 

If you wanted to, you could add a simple "System.out.println()" command here and run your client; this will show that the preInit() method is now being loaded by Forge. Perfect! But, how do we hard-code our mcmod.info file's information? That is the point of this, after all.

 

The first thing we are going to want to do is create a ModMetadata object. This needs to be created outside of the preInit() method, and remember that import:

import cpw.mods.fml.common.ModMetadata;

public static ModMetadata modMetadata;

 

So, we now have access to a ModMetadata object. If you don't know what a ModMetadata object is, this is the class that gets modified by your mcmod.info file. What we're going here is acquiring our mod's instance of ModMetadata and then hard-coding some of the values in. So, inside your preInit() method, the first thing you want to do is acquire your mod's instance of ModMetadata:

@Mod.EventHandler
public void preInit (FMLPreInitializationEvent event) {
modMetadata = event.getModMetadata();
}

 

Our mod's unique ModMetadata class is now stored inside our static 'modMetadata' object that we created a moment ago. We can now modify this class to our desires:

modMetadata.modId		=	"Tutorial";												//	This is the ID of your mod (the 'modid' attribute from @Mod)
modMetadata.name		=	"Modding with Forge";									//	This is the name of your mod (the 'name' attribute from @Mod)
modMetadata.version		=	"Tutorial #3b";									//	This is the version of your mod (the 'version' attribute from @Mod)
modMetadata.description	=	"A hard-coded mcmod.info file";						//	This is the basic description of your mod
modMetadata.url		=	"http://www.minecraftforum.net/users/MrrGingerNinja";	//	A URL relating to the mod itself or the mod author
modMetadata.updateUrl	=	"http://www.minecraftforum.net/users/MrrGingerNinja";	//	Not quite sure of the difference between url and updateUrl, so I make them the same
modMetadata.authorList	=	Arrays.asList (new String[] { "MrrGingerNinja" });		//	A list of author names that worked on the mod
modMetadata.credits		=	"To all those who use and credit these tutorials!";		        //	Any additional credits you want to provide
modMetadata.logoFile	        =	"/logo.png";								        //	The location of the logo file (relative to the location of the mcmod.info file)

 

Just in case you weren't sure regarding imports, you need to import "java.util.Arrays" for the authorList. If you launch your client now and check out your mod details, it will look a little bit fancier (especially if you added a logo file):

<LOGO FILE IF YOU SPECIFIED ONE>
Modding with Forge
Version: Tutorial #3b (Tutorial #3b)
Mod ID: 'Tutorial' Mod State: Available
Credits: To all those who use and credit these tutorials!
Authors: MrrGingerNinja
URL: http://www.minecraftforum.net/users/MrrGingerNinja
No child mods for this mod

A hard-coded mcmod.info file

 

So, there you have it! A hard-coded mcmod.info file, and the basic setup for your mod. I hope you have enjoyed this tutorial; let me know if you did!

 

In the next tutorial, we are going to take a look at creating a basic configuration file and how we can use the new 'guiFactory' attribute in @Mod to allow the user to alter the config file through that great little "Config" button we say in the mod screen earlier on.

 

I'll see you in the next one.

 

~MrrGingerNinja

 

View the last tutorial (Tutorial 3 - The Basics of 1.7.x Mod Creation)

    > http://www.minecraftforum.net/forums/mapping-and-modding/mapping-and-modding-tutorials/2223722-1-7-x-modding-with-forge-3-the-basics-of-1-7-x

 

View the next tutorial (Tutorial 4 - In-Game Configuration)

    > COMING SOON

Link to comment
Share on other sites

  • 2 weeks later...

A few notes:

  • You might want to explain that a ModID should be all lowercase to avoid problems with asset-loading (textures, etc.)
  • Coding the mcmod.info into your Mod-File is kinda a bad idea, because then Launchers like MultiMC will not be able to show that information about your mod

 

or you could do what i do

 

public static final String modId = modName.toLowerCase();

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
  • Topics

×
×
  • Create New...

Important Information

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