Common Issues and Recommendations
What is this?
This is an updated version of the original common issues and recommendations thread created by diesieben07. It is simply a collection of common issues and recommendations for the Modder Support subforum. Instead of repeating these details over and over again, a link to this thread can be used.
This post will be updated as needed. If you would like to suggest something, either PM me or put it in a separate thread to keep this clean.
- Please use the registry events or a deferred register to add your blocks, items, and other registry entries if a forge registry exists for them.
If this is not applicable, the entry should be deferred and registered in an existing registry event for most cases.
- Do not reach across logical sides. This will cause subtle and not-so-subtle issues that may occur randomly and very rarely. One of the most common side effects is having a dedicated server crash with a
ClassNotFoundException. Read the documentation about sides to understand why this is a bad idea. Instead isolate and reference the code via
IForgeRegistryEntryis singleton-like. That means there is only one instance of your object class. This means you cannot store dynamic data as instance fields on your object class. For example, there is not a new
Blockinstance for every position in the world or a new
Iteminstance for every
ItemStack. Instead, you must use a
TileEntityor the NBT data on an
- Do not use methods that are deprecated in Forge or vanilla Minecraft. Usually there will be a comment above the method explaining what to use instead.
There are some exceptions for some methods such as those in the
Blockclass. These methods may be overridden, but calls to these methods should use their respective supertype in
- Do not use
ContainerBlock. These classes are legacy vanilla code. To add a
TileEntityto your block, override
IForgeBlock#createTileEntity(the method with a
IBlockReaderparameter) in your
- Do not use
IInventory. Instead, use the capability API with
The forge docs on this still need to be updated with my 1.14.4 PR so it can be accurate. There are wrappers available to convert between the two if you need to use legacy APIs:
InvWrapperto turn an
IItemHandlerModifiable(rarely needed, vanilla inventories are patched to provide an
- Capabilities that are invalidated should have their
LazyOptional<?>holders invalidated as well. This can be added directly if you own the object (e.g.
Entity#remove) or indirectly through the event via
- Containers do not get information from the client by default. Inventories and integers are synced when a slot or reference holder is used and tracked with those values. As for other data, it can be synced using a
NetworkHooks::openGui. The container type does need to be registered using
IForgeContainerType::createfor it to send and be received.
- All language keys (“unlocalized names”) and enum entries added via
IExtensibleEnumshould contain your mod ID to avoid conflicts between mods.
TileEntityclass must have a no-argument constructor to be passed into a
TileEntityType<?>for registration. As a general recommendation, a
TileEntityshould not have more than this one constructor to avoid confusion.
- Almost all of world generation is handled through JSON files. This means that if you want to create a biome, dimension, etc., it should be handled through a JSON file in their respective location. This does not apply for adding data to already existing biomes. That is handled through
ItemStackshould never be null as expected of vanilla and Forge code. Instead, use/return
ItemStack#EMPTYover null and
ItemStack#isEmptyto check for empty stacks. Do not compare against
- Packets/Messages should be handled and registered through a
- Handle exceptions properly. Do not avoid a game crash at all costs. It is sometimes okay to crash the game. Read this article for more information.
- Registry names and file names should be written in snake case (e.g. all lowercase letters, with spaces replaced by underscores like
- Just because you cannot find a method name does not mean it doesn’t exist. Most likely, you are using an outdated version of the obfuscation mappings. If this is the case, you can dm the bot from the forge discord using
!mcpfollowed by the mapped or unmapped name to get the method (
!mcpm) or field (
!mcpf) you are looking for.
You can also update your mappings inside
build.gradleto the latest version which can currently be found in the
#modder-support-116’s channel pins on the forge discord.
@Overridewhen you intend to override methods. This helps tremendously when updating your code to new versions of Minecraft, but in general is good practice. Read this Stack Overflow answer for an explanation.
- There are many different ways to handle events. Please pick and stick to one of the following methods listed in the image below.
Credits to the MMD Discord for this image.
- Do not abuse inheritance for code-reuse. This often manifests in classes like
BaseItem. Using this pattern prevents you from extending other essential classes such as
ArmorItemrequiring a large level of code duplication and events. Prefer composition or utility methods instead to reuse code.
- There should not be any reason to use
@OnlyInanywhere within your code regardless of if the extended method has the annotation. This is handled interally to remove certain classes/methods in the server jar. Any sided code should be handled properly via
- JSON files should be created via Data Generators whenever possible instead of copy-pasting/handwriting.
- Do not make “sided proxies” or a “common proxy”. Use the modern
DistExecutorsystem or the
@Mod.EventBusSubscriberto create client/server-only code.
- Do not use “export” or “create jar file” functionalities of your IDE or other means to create your final mod file. You must use the
- When creating a git repository for your mod, the repository root should be where your
build.gradlefile is. The MDK ships with a default
.gitignorefile so that the only necessary files will be added to version control.
- If you are running into gradle decompilation errors when the buildscript hasn’t been modified, try following these steps: First, close your IDE. Next, run
gradlew --stopand then
gradlew clean. Finally, repeat the setup process once again. If that doesn’t work, remove the
.gradlefolder in the local and user directory first. This will usually fix most user problems with gradle.
- Whenever you are asking for help on the forums or discord about code issues, you should provide the following items when applicable: a link to a paste of your stacktrace/log, a link to your current repository holding the mod, and a detailed explanation of the issue you are encountering. This allows others to more accurately help you with your current problem in a single reply rather than 10+ down the line from guessing and checking.
Thank you to diesieben07 for creating the original post and sciwhiz12 for reviewing this thread.