Modding

From Necesse Wiki
Revision as of 16:24, 28 June 2022 by Fair (talk | contribs)
Jump to navigation Jump to search

Modding is the act of modifying, adding or removing content and features. Mods are created by the community, and shared through the Steam Workshop. They can be anything like adding more items and monsters, adding a new language, changing the textures in the game, adding new features, tweaking balance and much more.

Necesse mods are created using the Java programming language.

Installing and using mods

Steam Workshop

Modders usually share their mods on the Steam Workshop. If you subscribe to a mod, the next time you launch the game a mods button will appear in the main menu. In this menu you can see the mods you have installed, change their load order, enable or disable them.

Dedicated servers and local mods

For dedicated servers to have mods, they must find and download the mod jar file. Many modders give links to where they can be downloaded on the mods Workshop page. Once you have the jar file, you have to put it inside a mods folder, depending on your system. If the folder does not exist on your system, you can create one yourself.

  • Windows: %APPDATA%/Necesse/mods/
  • Linux: ~/.config/Necesse/mods/
  • Mac: ~/Library/Application Support/Necesse/mods/

Creating mods

Necesse mods are created using the Java programming language. This place is not for you to learn Java, there are plenty of tutorials and resources on that out on the internet already.

Mods are packaged inside a jar file for the game to load during runtime. When modding, it's a good idea to have a decompiler (included in most IDEs). The source code won't be released yet (if ever), and many topics are not explained thoroughly yet. This means you often have to rely on decompiling classes and checking out how they are done in the core game.

The Official Discord Server has a channel dedicated to modding where you can ask questions, get help and request new modding features for the game and all other things Necesse modding.

Getting started

To get started on modding, there is an official example project you can download, found on Github. It includes basic stuff like adding items, tiles, objects, monsters, recipes and more. It also includes build tools using Gradle to easily compile and structure your mod so that it can be read and loaded by the game, as well as development tools like loading your in-development mod, so that you can upload it to the Steam Workshop when complete.

Modding tools

  • A Java development kit. The game is built on Java 8, which you can find here: ttps://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
  • An integrated development environment (IDE). For example Intellij IDEA Community which is free.
  • An image editing tool, like pixel art editors Asesprite or Pyxel Edit.
  • An audio editing tool, like Audacity or REAPER.

Setting up

If you have downloaded the example project, it can be loaded using your IDE and almost everything will already be set up for you. All you have to do is configure your build.gradle file with the correct mod info and the games install directory. Once done, it will prompt you to refresh the project.

To run your in-development mod, you will need to launch the game with -mod <folder path with your mod jar> option. This is already done if in the example project, if you run the runClient Gradle task, found in the far right toolbar inside Intellij. Using this launch option will also allow you to upload your mod to Workshop once it is complete.

Image of where the gradle task can be found inside Intellij

Mod info file

Note: If you are using the example mod, you can skip this section as it is generated for you using the values you set inside the build.gradle file.

Every mod must have a mod.info file in their jars top path. The file structure is custom, but very similar to JSON. It's used troughout the games saved files. The file must have these fields:

  • id - The unique ID of your mod. Must be all lowercase and cannot use special characters.
  • name - The display name of your mod.
  • version - The version of your mod.
  • gameVersion - The target game version of your mod.
  • description - A short description of your mod.
  • author - Your name
  • dependencies (optional) - Your mods dependencies formatted in their ids and array. Like this: [exammple.mod, other.mod]
  • optionalDependecies (optional) - Your mods optional dependencies. They are used together with your dependencies to automatically make a load order for mods.
  • clientside - true/false, if your mod is client/server side only. This makes it possible for clients to connect to servers without the server needing the mod and vice versa.

Important notes about your mod.info file:

  1. Your id should be unique to the mod and never change between versions. A good example for id is "<your name>.<mod name>".
  2. Avoid special characters that might inflict with the format, like commas, quotes etc. This will probably be changed later, and you’ll be able to escape characters, just like in Java.

Example of a mod.info file:

{
   id = fair.examplemod,
   name = Example Mod,
   version = 1.0,
   gameVersion = 0.21.23,
   description = Just an example mod,
   author = Fair
}

Mod entry class

Your mod needs an entry class. This is where the game loads your mod from and calls initialization methods. Create a class with the @ModEntry annotation to tell the game that's where your mod starts.

Important notes about your @ModEntry class:

  1. Make sure your mod only has one @ModEntry annotation. The game will stop looking for more when found one.
  2. Make sure the class does NOT have a constructor.

Example for your mod entry class:

import necesse.engine.modLoader.annotations.ModEntry;

@ModEntry
public class ExampleMod {

    public void init() {
        System.out.println("Hello world from my example mod!");
    }

}

The game will look for specific methods within your @ModEntry class. Here's a description of them:

public void preInit()

This method is called before loading of the core game. It should only be used on rare occasions. If you are not sure about it, don't use it.

public void init()

This method is called after the core game has been loaded. Here you should register your own tiles, objects, items, mobs and so on.

The general order in which you should register your mod objects to avoid issues are (not forced):

  1. Tiles
  2. Objects
  3. Biomes
  4. Buffs
  5. Global ingredients
  6. Recipe techs
  7. Items
  8. Enchantments
  9. Mobs
  10. Pickup entities and projectiles
  11. Level, world events, level data and settlers
  12. Containers
  13. World generators
  14. Packets
  15. Quests
  16. Other

public void initResources()

This method is called only on the client and should load any extra resources your mod uses that the game doesn't automatically load.

The resources will be loaded from a resource folder. You can read more about this in a later section.

Example: Assign a texture:

GameTexture texture = GameTexture.fromFile("path/to/file")

If you have a texture at resources/texture.png you can load it using GameTexture.fromFile("texture")

All sound (.ogg) files need to be placed in resources/sound folder and can be loaded using

GameSound.fromFile("path/to/file")

public void postInit()

This method is called after the game is done loading all its core, mods and resources.

This is where you should register recipes, create or modify loot tables and spawn tables and register chat commands.

public void dispose()

This methodd is called when the game closes. If you have anything that needs to be disposed, that the game doesn't already dispose on it's own, do it here.

Things like textured loaded using GameTexture.fromFile(...) and sounds are automatically disposed.

Building your mod

If you are using the example project, a lot of this is already done for you. Simply run the buildModJar Gradle task, and it will generate the jar inside the ./build/jar folder.

For the game to recognize your jar, it has to follow a specific structure:

ExampleMod.jar
↳ resources
↳ Your resource files
↳ Java class files
↳ mod.info file

Uploading your mod

To uplod your mod to the Steam Workshop, it has to be enabled, have a preview.png file in resources folder and loaded through the -mod launch option. You can find more about this under the beginning of setting up section.

When all of these conditions are met, a button to upload your mod will appear when you select it inside the main menu mods screen. Click this and it will walk you through uploading to workshop. When you first upload, the mod will be hidden and only you will be able to see it. You can change this when you are ready to launch on your mods workshop page.

Image of the upload button when mod is loaded from development

Localization

Localization files are needed to give your tiles, objects, items, mobs and other things names. The files should be placed inside the resources/locale folder, and be named the same as the language they are using. Example: en.lang for the english translation.

You can also see how the localization file is structured inside the example mod project.

The file structure

The file is divided up into categories and keys. If your item has the localization item.exampleitem, it means that it's under the item category and has the key exampleitem.

The language file is read line by line in order. If one line is a category change, all the next keys will be under that category. Here's an example:

[mycategory]
mykey=Text
otherkey=Other text

[newcategory]
differentkey=Different text

[item]
exampleitem=Example item

Translations can have replacements that can be done in runtime. To add a replacement key in your translation, add a <key> somewhere. The key can be anything like <name>, <number> etc. Example: mobhealth=Mob health: <health>

Using a translation inside the game

Localization.translate(category, key) Localization.translate(category, key, replaceKey1, replaceString1, replaceKey2, replaceString2, ...)

A lot of places also use the GameMessage class. This is essentially a localizable string, by using LocalMessage which extends GameMessage. Goes the same as above: new LocalMessage(category, key, replaceKey1, replaceString1, replaceKey2, replaceString2, ...)

If you don't want to use a translation, you can also just give it a static string with new StaticMessage(string...)

Resources

For the game to load your resources, they have to placed inside a resources folder in your mod jar.

Using this, it is also possible to overwrite existing ingame textures by placing another texture at the exact same path as the core game ones. In the Discord server, there is a wiki channel with a pinned message where the core textures can be downloaded and used for modding and this wiki.

This also means that your resource files can get overwritten by other mods, so try and keep your file names unique.

Resource loading happens automatically for any files in the resources folder. But some things will look at specific subfolders to load their textures. Examples:

  • Items - items/<item stringiD>
  • Buffs - buffs/<buff stringiD>
  • Biomes - biomes/<biome stringiD>
  • Projectiles - projectiles/<projectile stringiD>