Integration API

Build optional mod integrations with MMO Skill Tree

Overview

MMO Skill Tree supports optional integrations with other Hytale mods. External mods can provide adapters that hook into MMO Skill Tree's systems (e.g., awarding Fishing XP when a fishing mod fires a catch event) without either mod hard-depending on the other.

The integration system has two layers:

  1. Built-in adapters — MMO Skill Tree ships with adapters for supported mods. Each adapter uses reflection to detect whether the target mod is installed and self-activates at startup. No server config required.
  2. Config overrides — Server owners can optionally disable or re-prioritize adapters via integrations.json.

Compatible Mods

MMO Skill Tree ships with built-in support for the following mods:

ModDomainWhat it does
HyFishingFishingFish caught via HyFishing's fishing rod system award Fishing XP. Fish mob kills fall back to combat weapon XP so there's no double-dipping.
Perfect ParriesParriesAdds 4 parry-themed reward types to melee combat skill trees (Swords, Daggers, Polearms, Staves, Axes, Blunt, Unarmed) and Defense. Parry rewards appear at levels 40-100 and scale from 2% to 5%. The mod queries bonuses via the API at runtime.
HyCitizensCitizensAdds the TALK_TO_NPC quest objective type. When HyCitizens is installed, quests can require players to interact with specific NPCs by name or ID. NPC conversations are detected automatically via event bus.
Hyronix NPC DialogNot an auto-detected integration. To open the NPC quest UI from an NPC dialog, add mmoquestui <player> <npc_id> as a command in your NPC Dialog config at mods/Hyronix_NPC Dialog/. This lets players interact with an NPC to browse and accept quests tied to that npcViewId.
SimpleEnchantmentsEnchantingEnchanting items awards ENCHANTING skill XP automatically. XP scales with enchantment level and can be tuned via the ENCHANTING xp-map config. Also unlocks a 10-tier enchanting skill tree with mana-focused rewards.

No configuration is needed — just install both mods and the integration activates automatically. Check [Integrations] in your server log to confirm it's active.

For Mod Authors

To integrate your mod with MMO Skill Tree, add the API jar as a compile-only dependency and implement the appropriate interface. Your adapter is discovered automatically at server startup.

Step 1: Add the API Dependency

The API is published as a separate, lightweight jar (mmoskilltree-api) versioned independently from the main plugin. Add it as compileOnly so it's available at compile time but not bundled into your jar — MMO Skill Tree provides it at runtime.

// build.gradle
dependencies {
    compileOnly 'ziggfreed:mmoskilltree-api:1.0.0'
}

The API jar contains only interfaces and annotations — no plugin logic, no transitive dependencies beyond JSR-305 nullability annotations.

Step 2: Implement the Domain Interface

Each integration domain has a specific interface. Currently available:

DomainInterfaceMethods
FishingFishingIntegrationonFishCaught(), isFishItem(), getFishDisplayName()
ParriesParriesIntegrationMarker interface — presence activates parry rewards in skill trees. Bonuses queried via MMOSkillTreeAPI.
CitizensCitizensIntegrationEnables TALK_TO_NPC quest objectives. Adapter listens for NPC interaction events.
EnchantingEnchantingIntegrationFires when a player enchants an item. Adapter awards ENCHANTING XP via the event bus.

Implement the interface and annotate your class with @IntegrationMeta to declare your domain and priority:

import com.ziggfreed.mmoskilltree.integration.IntegrationDomain;
import com.ziggfreed.mmoskilltree.integration.IntegrationMeta;
import com.ziggfreed.mmoskilltree.integration.fishing.FishingIntegration;

@IntegrationMeta(
    domain = IntegrationDomain.FISHING,
    priority = 10
)
public class YourFishingAdapter implements FishingIntegration {

    @Override
    public String getModName() {
        return "Your Fishing Mod";
    }

    @Override
    public boolean initialize() {
        // Set up reflection handles, verify your mod's API is available
        // Return false to gracefully skip this adapter
        return true;
    }

    @Override
    public void shutdown() {
        // Clean up resources
    }

    @Override
    public void onFishCaught(String playerName, String fishIdentifier, int rarity) {
        // Called by MMO Skill Tree when it detects a fish catch
    }

    @Override
    public boolean isFishItem(String itemIdentifier) {
        // Return true if your mod recognizes this as a fish
        return false;
    }

    @Override
    public String getFishDisplayName(String fishIdentifier) {
        // Return a human-readable name for the fish, or null
        return null;
    }
}

@IntegrationMeta Fields

FieldTypeDefaultDescription
domainIntegrationDomain(required)Which integration category this adapter belongs to
priorityint100Lower values are tried first. If two mods integrate the same domain, the lower-priority adapter wins.

Step 3: Submit Your Adapter

Built-in adapters are registered explicitly inside MMO Skill Tree (Hytale mod classloaders don't support Java ServiceLoader discovery). To add your adapter:

  1. Build your adapter following the patterns above
  2. Open a pull request or reach out on Discord to have it included in the next release

Once registered, MMO Skill Tree calls your adapter's initialize() at startup. If your mod isn't installed, initialize() returns false (via a failed Class.forName()) and the adapter is silently skipped. No server owner configuration needed.

Step 4: Reflection Pattern for External API Calls

Your adapter should never directly import classes from the mod it integrates with. Instead, use reflection to access the external mod's API. This ensures your adapter compiles even if the target mod isn't present at build time.

// WRONG - breaks if the mod isn't on the classpath
import com.example.fishmod.FishAPI;

// RIGHT - reflection-safe
public class MyAdapter implements FishingIntegration {
    private static final String API_CLASS = "com.example.fishmod.FishAPI";
    private Method isFishMethod;
    private Object apiInstance;

    @Override
    public boolean initialize() {
        try {
            Class<?> api = Class.forName(API_CLASS);
            apiInstance = api.getMethod("getInstance").invoke(null);
            isFishMethod = api.getMethod("isFish", String.class);
            return true;
        } catch (Exception e) {
            return false;  // Gracefully skip
        }
    }

    @Override
    public boolean isFishItem(String id) {
        try {
            return (Boolean) isFishMethod.invoke(apiInstance, id);
        } catch (Exception e) {
            return false;
        }
    }
}

Selection Behavior

When multiple adapters are discovered for the same domain (e.g., two fishing mod integrations), MMO Skill Tree selects one using this process:

  1. All discovered adapters are grouped by domain
  2. Within each domain, adapters are sorted by effective priority (lowest first)
  3. Each adapter is tried in order:
    • If disabled in config → skip
    • If initialize() returns false or throws → skip (target mod not installed)
    • First adapter that passes all checks becomes active
  4. If no adapter succeeds, the domain uses a no-op implementation (safe, does nothing)

Config Overrides (Server Owners)

By default, all discovered adapters are enabled and use their annotation-declared priority. Server owners can override this in mods/mmoskilltree/integrations.json:

{
  "schemaVersion": 1,
  "overrides": {
    "com.example.MyFishingAdapter": {
      "enabled": false
    },
    "com.other.BetterFishingAdapter": {
      "priority": 1
    }
  }
}

Override keys are the fully qualified class name of the adapter. Available fields:

FieldTypeDefaultEffect
enabledbooleantrueSet to false to prevent this adapter from activating
priorityinteger(from annotation)Override the priority. Lower values are tried first.

If the file doesn't exist, an empty one is generated on first startup. Server owners never need to edit it unless they want to disable or re-order integrations.

Startup Logging

MMO Skill Tree logs the full integration resolution process at startup. Look for lines prefixed with [Integrations] in the server log:

[INFO] [Integrations] Discovered 4 adapter(s) (explicit registry)
[INFO] [Integrations] Fishing: activated HyFishing via ...HyFishingAdapter
[INFO] [Integrations] Parries: activated PerfectParries via ...PerfectParriesAdapter
[INFO] [Integrations] Citizens: activated HyCitizens via ...HyCitizensAdapter
[INFO] [Integrations] SimpleEnchantments adapter initialized — event bus handlers registered
[INFO] [Integrations] === Integration Resolution Summary ===
[INFO] [Integrations] Fishing: ACTIVE - HyFishing | ...
[INFO] [Integrations] Parries: ACTIVE - PerfectParries | ...
[INFO] [Integrations] Citizens: ACTIVE - HyCitizens | ...
[INFO] [Integrations] Enchanting: ACTIVE - SimpleEnchantments | ...
[INFO] [Integrations] ========================================

API Reference

All classes are in the com.ziggfreed.mmoskilltree.integration package.

ClassTypeDescription
OptionalIntegrationInterfaceBase interface. Defines getModName(), initialize(), shutdown().
FishingIntegrationInterfaceExtends OptionalIntegration. Adds fishing-specific hooks.
IntegrationMetaAnnotationDeclares domain, priority, and target plugin identity on adapter classes.
IntegrationDomainEnumIntegration categories: FISHING, PARRIES, CITIZENS, ENCHANTING.
PluginIdClassIdentifies a plugin by manifest Group + Name.
IntegrationCandidateClassData holder for a candidate integration's metadata.
NoOpFishingIntegrationClassDefault no-op. Returned when no fishing mod is active.
ParriesIntegrationInterfaceExtends OptionalIntegration. Marker interface for parry mod adapters.
NoOpParriesIntegrationClassDefault no-op. Returned when no parry mod is active.
CitizensIntegrationInterfaceExtends OptionalIntegration. Enables NPC interaction quest objectives.
NoOpCitizensIntegrationClassDefault no-op. Returned when no citizens mod is active.
EnchantingIntegrationInterfaceExtends OptionalIntegration. Awards ENCHANTING XP on enchant events.
NoOpEnchantingIntegrationClassDefault no-op. Returned when no enchanting mod is active.

Quick Start Checklist

StepWhat to do
1Add compileOnly 'ziggfreed:mmoskilltree-api:1.0.0' to your build
2Implement the domain interface (e.g., FishingIntegration)
3Annotate with @IntegrationMeta (domain, priority)
4Use reflection for all calls to external mod APIs (no direct imports)
5Submit your adapter via PR or Discord for inclusion in the next release