Modding Snippets
[edit]
Please help us build the Modding community by sharing some of your examples. Feel free to update this page via the wiki editor!
When adding code snippets to the wiki, follow this example:
<pre>
// here is some code!
System.out.println("Necesse is cool");
</pre>
Utilities[edit]
Post your Utilities examples here.
Getting All Textures - Author: Kamikaze[edit]
Put this loop into the postInit() function. run buildModJar and then runClient from the gradle tray. The resource folder will output to your project directory.
for (Map.Entry<String, GameTexture> tex : GameTexture.getLoadedTextures()) { tex.getValue().saveTextureImage("resources/" + tex.getKey()); }
Getting server object - Author: kiriharu[edit]
Server object can be obtained from ServerStartEvent. To simple access to it I set server instance to static variable.
import necesse.engine.GameEventListener; import necesse.engine.GameEvents; import necesse.engine.events.ServerStartEvent; import necesse.engine.modLoader.annotations.ModEntry; import necesse.engine.network.server.Server; @ModEntry public class TestMod { public static Server SERVER; public void init() { // Register ServerStartEvent event listener to obtain server instance GameEvents.addListener(ServerStartEvent.class, new GameEventListener<ServerStartEvent>() { @Override public void onEvent(ServerStartEvent e) { // Setting server instance to static variable SERVER, so it can be accessible everywhere in code TestMod.SERVER = e.server; } }); } } });
Get access to to death messages - Author: kiriharu[edit]
To get access to death messages you can patch DeathMessageTable.getDeathMessage().
public class DeathMessagePath { @ModMethodPatch( target = DeathMessageTable.class, name = "getDeathMessage", arguments = {Attacker.class, GameMessage.class} ) public static class MethodPatch { @Advice.OnMethodExit public static void onExit(@Advice.Return(typing = Assigner.Typing.DYNAMIC) LocalMessage returned) { // do everything what you want with death message } } }
Config - Author: kiriharu[edit]
Fair said mod framework have an official way to create config, so add initSettings method in ModEntry class like this:
public static int myInt = 0; // Setting default value to 0 public ModSettings initSettings() { return new ModSettings() { @Override public void addSaveData(SaveData saveData) { // Save data here saveData.addInt("myInt", myInt); } @Override public void applyLoadData(LoadData loadData) { // Load data here savedInt = loadData.getInt("myInt", myInt); } }; }
It will create a file in %APPDATA%/cfg/mods/modid.cfg file like this:
{ SETTINGS = { myInt = 0 } }
Getting the client from anywhere[edit]
Method 1 - Author: DimitarBogdanov/m4trixglitch
Sometimes, it's quite difficult to find an instance of Client (e.g. in a Control's activate method). This snippet should work, as long as the user is ingame (shocker, I know...) Returns null if the user isn't in-game. Not tested thoroughly, but it appears to work.
public static Client getClient() { State gameState = GlobalData.getCurrentState(); if (!(gameState instanceof MainGame)) { return null; } MainGame mainGame = (MainGame) GlobalData.getCurrentState(); Client client = mainGame.getClient(); return client; }
Method 2 - Author: FerrenF
If the above method does not work for your use-case, then the following method is more robust in the sense that it will return the client regardless of being in game or not.
static Client getGameClient() { State currentState = necesse.engine.GlobalData.getCurrentState(); return currentState instanceof MainGame ? ((MainGame) currentState).getClient() : ((MainMenu) currentState).getClient(); }
Including external dependencies in your .JAR[edit]
Author: FerrenF
There might be a case where you need access to code that is provided by an external java library that is NOT included in the Necesse base game libraries. For example, you might want to include com.google.gson as a JSON parser to read formatted data you have included in your mod.
1. Prerequisites
To do this, we need the library we want to include first:
Store a copy of the library that is compatible with the java language level used by Necesse within your project. For Necesse 0.30.0, you would need to use gson 2.8.9 - far below the latest release. If your project directory is C:/Users/User/eclipse-workspace/ProjectName/* then you might put this library at C:/Users/User/eclipse-workspace/ProjectName/libs/. If the folder does not exist, then create it. The name of the sub-folder is arbitrary.
2. Modifying build.gradle
Let's assume that you are using the build.gradle file contained within the ExampleProject provided by @Fair. Below the all-caps warning to not edit below this line (A suggestion!), you will find a section of code preceded by the word 'dependencies':
dependencies { implementation files(gameDirectory + "/Necesse.jar") implementation fileTree(gameDirectory + "/lib/") implementation fileTree("./mods/") // Add all mods located in local mods folder // Add any third party library dependencies here. Remember to use libDepends, so that they will be added to your jar on build // These are some examples: // libDepends group: 'com.google.guava', name: 'guava', version: '31.1-jre' // libDepends files("path/to/library/jar.jar") }
We are not going to use libDepends, because it is much easier to use implementation and a small modification to the buildModJar routine. First, add the library file (in .jar format) that you have downloaded and moved to your project's directory:
dependencies { implementation files(gameDirectory + "/Necesse.jar") implementation fileTree(gameDirectory + "/lib/") implementation fileTree("./mods/") // Add all mods located in local mods folder ... implementation files('libs/gson-2.8.9.jar') }
We added: `implementation files('libs/gson-2.8.9.jar')` here. Next, farther down in your build.gradle script will be a task called buildModJar. This task is responsible for producing your mod's .jar file that will eventually end up in the game's mod folder.
task buildModJar(type: Jar) { group "necesse" description "Generates the mod jar into the build folder" dependsOn "classes" ... archiveName "${jarName}.jar" destinationDir file(buildLocation)
Here, we are going to instruct gradle to package the external libraries necessary for your project into the same .jar file that will be your mod. This is called making a 'fat jar'. Additionally, we are going to instruct gradle to exclude duplicate meta-info/module-info files that may conflict when copying the external library into the .jar being built.
task buildModJar(type: Jar) { ... // Add only gson-2.12.1.jar, but exclude module-info.class if it exists from { zipTree(file('libs/gson-2.8.9.jar')).matching { exclude 'module-info.class', 'META-INF/versions/**' } } duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Prevent duplicate conflicts archiveName "${jarName}.jar" destinationDir file(buildLocation)
We added:
from { zipTree(file('libs/gson-2.8.9.jar')).matching { exclude 'module-info.class', 'META-INF/versions/**' } } duplicatesStrategy = DuplicatesStrategy.EXCLUDE
3. Adding the library to the project Build Path
Finally, before attempting to utilize the library you just added - make sure that your external library has been added to the project's build path. Depending on the IDE you are using, this might look different.
Using Eclipse to do this, you would right click your project's root in the package explorer, go to 'Properties', then 'Java Build Path', and under the 'libraries' tab you would use the 'Add JARs' button to locate and add the .jar file you moved to your project into the build path.
4. Refresh Gradle and Build
You are almost done. clean, refresh, and then build your gradle project. Assuming there are no compile errors, it's then time to test that this library has been appropriately added to your project. In your main script, import the package name of the library you added to the build path. For gson, importing the Gson class - it looks like this:
package YourProject; ... import com.google.gson.Gson; ...
If your IDE isn't complaining, then it is probably a good sign. Try using some of your libraries' class definitions and then rebuild. If your compiler does not throw any additional errors, then you have successfully added an external library dependency into your project. You do not need to distribute this library with your mod, because it's bundled into your mod.
5. Things to consider
- Don't use unfamiliar libraries that may execute unsafe code. Adding them into your mod means that arbitrary code can be executed any time the game is running.
- Be mindful of the size of the library you include. Your mod's final .jar file will increase in size directly proportional to the size of the library you are including. Be careful not to use libraries that include javadocs, because they are not compressed.
Equipment[edit]
Post your Equipment examples here.
Adding a sword - Author: Quack
To get started start by placing the texture of your sword in /resources/player/weapons/ as well as /resources/items/. Be sure that the name of the image is the same as it's itemStringID. The item icon placed in the items folder should be 32x32 but the actual texture of the sword places in weapons can be bigger.
Within your mod folder (in this example it's named examplemod) create a new folder or "Package". Within this new folder create a new Java class and name it after the weapon. In this case the weapon class is within a package called "tests" and the class itself is named TestSword.java.
The following code is all that it needed to set the properties of you sword. There are also things like attackXOffset and attackYOffset which can be set if the texture doesn't fit in the character's hand quite right.
package examplemod.tests; // Change this to the package name where you have your weapon class import necesse.inventory.item.Item; import necesse.inventory.item.toolItem.swordToolItem.SwordToolItem; // Extends SwordToolItem public class TestSword extends SwordToolItem { // Weapon attack textures are loaded from resources/player/weapons/<itemStringID> public TestSword() { super(400); rarity = Item.Rarity.COMMON; attackAnimTime.setBaseValue(300); // attack time attackDamage.setBaseValue(20) // Base sword damage .setUpgradedValue(1, 95); // Upgraded tier 1 damage attackRange.setBaseValue(60); // range knockback.setBaseValue(100); // knockback } }
In the example above the weapon class is located in /examplemod/tests/TestSword.java.
Now within the main mod java file you want to include three new lines. The first one at the very top to import the newly created weapon class:
import examplemod.tests.*; // Change this to fit your package name
Then in the init() function we need to add:
public void init() { ItemRegistry.registerItem("testsword", new TestSword(), 20, true); }
This registers the weapon in the item registry and sets it's barter value.
Lastly in the postInit() function we need to add:
public void postInit() { Recipes.registerModRecipe(new Recipe("testsword", 1, RecipeTechRegistry.NONE, // Here you define the crafting technology needed to craft new Ingredient[]{ new Ingredient("anylog", 5), new Ingredient("anystone", 5) // Here you define which ingredients are needded to craft }).showAfter("woodboat")); // Change this to which item you want it to show after in the menu }
In this example we have added the test sword as an item which is craftable everywhere for just 5 logs and 5 stones. And it shows after the wood boat item.
NPCs[edit]
Post your NPC examples here.
Mobs[edit]
Post your Mob examples here.