7.5 KiB
Modding
mod.json
In the root folder of your jar file (the mod) must be a file called mod.json
. It contains metadata for the mod loader.
Example
{
"uuid": "1f37a8e0-9ec7-45db-ad2f-40afd2eb5a07",
"versionId": 123,
"versionName": "1.0",
"authors": [
"Example dev"
],
"name": "Example Mod",
"moddingAPIVersion": 1,
"identifier": "example",
"mainClass": "de.example.mod.Main",
"loading": {
"priority": "NORMAL"
},
"dependencies": {
"hard": [
{
"uuid": "7fd5d30c-246e-42f6-9dfe-82f2383b4b68",
"version": {
"minimum": 123,
"maximum": 123
}
}
],
"soft": [
{
"uuid": "af8c9c7e-c3c7-41e0-bcc6-3882202d0c18",
"version": {
"minimum": 123,
"maximum": 123
}
}
]
}
}
Explanation
uuid
is a unique id for the mod. Generate 1 and keep it in all versions (used for dependencies, etc). RequiredversionId
like in android there is a numeric version id. It is used to compare between versions (and as identifier). RequiredversionName
,authors
,name
is the classic implementation of metadata. Can be anything, will be displayed in the mod list. RequiredmoddingAPIVersion
Modding API version of minosoft. Currently1
Requiredidentifier
is the prefix of items (for Minecraft it isminecraft
). Aka the thing before the:
. RequiredmainClass
the Main class of your mod (self explaining). The main class needs to extent the abstract classMinosoftMod
. Requiredloading
Loading attributes. Optionalpriority
should the mod be loaded at the beginning or at the end. Possible values areLOWEST
,LOW
,NORMAL
,HIGH
,HIGHEST
Optional
dependencies
Used if you need another mod to work Optionalhard
These mods are needed to work. If the loading fails, your mod is not getting loaded, and a warning message is being displayed. Optionalsoft
These mods are optional to work. Both use the following format: Optionaluuid
the uuid of the mod to load. Requiredversion
Specifies the version you need to load. Optionalminimum
Minimum versionId required. Maximum, minimum, both or nonemaximum
Maximum versionId required. Maximum, minimum, both or none
Getting started
Add Minosoft to your maven dependencies with
Repository:
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
Dependency:
<dependencies>
<dependency>
<groupId>de.bixilon.gitlab.bixilon</groupId>
<artifactId>minosoft</artifactId>
<version>master-SNAPSHOT</version>
</dependency>
</dependencies>
Instead of master-SNAPSHOT
you should write the latest commit, if there is no release tagged yet.
Mod loading (aka Main class)
Your main class must extend the following class: de.bixilon.minosoft.modding.MinosoftMod
.
Phases
There are different phases (states) for the loading. There are the following phases:
BOOTING
Happens after loading all configuration files and while displaying the server list.INITIALIZING
All mods are loaded into the ram and everything before registering anything happens here (like OpenGL stuff, etc). You should also register Events here.LOADING
You have custom items, entities, blocks, etc? Load it here.STARTING
All items, etc are loaded. If you want to do anything else, do it here.STARTED
The loading is complete
The most important thing is performance. To archive fast loading times, etc, all mods (if they don't on each other) are getting loaded async.
One phase is completed (= Next phase starts), once all mods have completed the previous phase. Everything is async.
If your start function needs much time, you can set the loading priority in the mod.json
to start at the beginning. The start
method returns a success boolean.
Create a Main class, here is an example
package de.bixilon.example.mod.main;
import de.bixilon.minosoft.modding.MinosoftMod;
import de.bixilon.minosoft.modding.loading.ModPhases;
public class TestMod extends MinosoftMod {
public boolean start(ModPhases phase) {
if (phase == ModPhases.BOOTING) {
getLogger().info("Hello world!");
}
return true;
}
}
Your mod.json
can look like this
{
"uuid": "1f37a8e0-9ec7-45db-ad2f-40afd2eb5a07",
"versionId": 1,
"versionName": "1.0",
"authors": ["Bixilon"],
"name": "Example Mod",
"identifier": "example",
"mainClass": "de.bixilon.example.mod.main.TestMod"
}
Events
There are global events (which works on all connections) and connections events (server specific).
To register a global event you need to use (in the INITIALIZING
phase) getEventManager().registerGlobalListener(new XYEventListener());
.
If you want to register an event depending on a server address (like server specific support, you can use the following), you can use EventManager::registerConnectionListener
method.
It takes 2 arguments: The first one is your listener, the second one is a ServerAddressValidator
.
There are several validators, choose one or write your own:
HostnameValidator
Simply check the hostname. For example:bixilon.de
.PortValidator
Get all connections with a specific port. For example:25565
SimpleAddressValidator
Check for server address and port. e.g.:bixilon.de:25565
RegexValidator
Check for a regular expression like:*.de
Use the following: getEventManager().registerConnectionListener(new XYEventListener(), new HostnameValidator("127.0.0.1"));
Your event methods need to be annotated by EventHandler
. EventHandler
can take these arguments:
priority
Pretty much self explaining.HIGH
means, that it gets executed at "the beginning",LOW
means the opposite. Defaults toNORMAL
.ignoreCancelled
If it is a cancellable event, your method only gets executed, when all prior listeners (potentially with a higher priority) did not cancel the connectionEvent. Defaults tofalse
.
Your XYEventListener class needs to extend de.bixilon.minosoft.modding.event.EventListener
;
import de.bixilon.minosoft.modding.event.EventListener;
import de.bixilon.minosoft.modding.event.events.ChatMessageReceivingEvent;
import de.bixilon.minosoft.modding.event.events.ChatMessageSendingEvent;
import de.bixilon.minosoft.modding.event.events.annotations.EventHandler;
import de.bixilon.minosoft.modding.loading.Priorities;
public class ChatEvent extends EventListener {
@EventHandler(priority = Priorities.HIGHEST)
public void onChatMessageReceiving(ChatMessageReceivingEvent event) {
if (event.getMessage().getMessage().contains("Bixilon")) {
MinosoftExampleMod.getInstance().getLogger().info("Bixilon wrote a potential bad chat message. Suppressing it!");
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onChatMessageSending(ChatMessageSendingEvent event) {
if (event.getMessage().contains("jeb_ is stupid")) {
event.setCancelled(true);
event.getConnection().getSender().sendChatMessage("jeb_ is awesome!");
}
}
}
The following code would suppress messages containing the word "Bixilon" and if you write "jeb_ is stupid" into the chat, the message's text will be "jeb_ is awesome".
To see a list of all events look into de.bixilon.minosoft.modding.connectionEvent.events
. There is also a javadoc.