Modding Guide
Introduction to the Craftics addon SDK: how the two extension paths work, how to set up a Fabric mod that depends on Craftics, and a walkthrough of the example addon.
Overview
Craftics exposes an addon SDK through two extension paths. You can use either one, or both together.
The Java API is centered on the CrafticsAPI class, a collection of static registration methods. An addon implements the CrafticsAddon entrypoint interface, declares it in fabric.mod.json, and Craftics calls onCrafticsInit() once at startup after all built-in content is ready.
The JSON datapack path requires no code at all. Place JSON files under data/<namespace>/craftics/ in your mod's resources and Craftics discovers them automatically at load time.
The table below lists every registry, the CrafticsAPI method that covers it, and where in this guide it is documented.
| Registry | CrafticsAPI method | Purpose |
|---|---|---|
| Weapons | registerWeapon() |
Register any item as a Craftics weapon with a damage type, stats, and an optional ability. |
| Armor Sets | registerArmorSet() |
Define full-set bonuses for a custom armor material. |
| Hybrid Sets | registerHybridSet() |
Define the bonus a player gets from wearing exactly two distinct armor materials. |
| Trim Patterns | registerTrimPattern() |
Add per-piece stat bonuses and a set bonus for a custom trim pattern. |
| Trim Materials | registerTrimMaterial() |
Add a stat bonus for a custom trim material. |
| Enchantments | registerEnchantment() |
Map an enchantment to passive combat stat bonuses. |
| Equipment Scanners | registerEquipmentScanner() |
Pull stat bonuses from non-standard inventory slots such as trinkets or curios. |
| Usable Items | registerUsableItem() |
Make a consumable, throwable, or special item usable during a combat turn. |
| Custom Effects | registerEffect() |
Add a custom combat status effect that ticks each round alongside built-in effects. |
| Enemies | registerEnemy() |
Define a reusable enemy template that biome JSON can reference by id. |
| Enemy AI | registerAI() |
Define an AI strategy for a custom or adopted mob type. |
| Allies | registerAlly() |
Register a combat ally recruited from the player hub to fight alongside the player. |
| Biomes | registerBiome() |
Add a biome programmatically. JSON datapacks also work for biomes. |
| Environments | registerEnvironment() |
Define a custom arena environment theme: floor, post, and light blocks. |
| Campaigns | registerCampaign() |
Define a full custom playthrough that replaces the vanilla progression. |
| Events | registerEvent() |
Create a custom between-level event such as a trader, ambush, or gambling screen. |
| Village & Bartering Station scenes | Datapack .schem |
Build the walk-around merchant hub scenes from a schematic using scene marker blocks. |
Getting Started
A Craftics addon is a standard Fabric mod that declares Craftics as a dependency and implements the CrafticsAddon entrypoint. Follow the steps below to set one up from scratch.
Step 1: Get a GitHub Packages token
Craftics is published to GitHub Packages at https://maven.pkg.github.com/ChrisAtwell27/Craftics. GitHub Packages requires a Personal Access Token to resolve packages, even public ones. This is a GitHub requirement, not a Craftics one.
- Go to github.com/settings/tokens and create a classic token with the
read:packagesscope. - Add the token to your user-level Gradle properties file at
~/.gradle/gradle.properties, creating the file if it does not exist:
gpr.user=your-github-username
gpr.key=ghp_yourtokenhere
Do not put the token inside your project's gradle.properties. It would be committed to source control.
Step 2: Add the Maven repository and dependency
In your addon's build.gradle, add the Craftics Maven repository and a modImplementation dependency. The version format is 0.2.0+<mc_version>, for example 0.2.0+1.21.1.
repositories {
maven {
name = 'Craftics'
url = 'https://maven.pkg.github.com/ChrisAtwell27/Craftics'
credentials {
username = providers.gradleProperty('gpr.user')
.orElse(providers.environmentVariable('GITHUB_ACTOR')).orNull
password = providers.gradleProperty('gpr.key')
.orElse(providers.environmentVariable('GITHUB_TOKEN')).orNull
}
}
}
dependencies {
modImplementation "com.crackedgames:craftics:0.2.0+1.21.1"
}
Step 3: Declare the dependency in fabric.mod.json
Add Craftics to your mod's depends block so Fabric loads Craftics before your addon:
{
"schemaVersion": 1,
"id": "myaddon",
"version": "1.0.0",
"environment": "*",
"depends": {
"fabricloader": ">=0.16.0",
"minecraft": "~1.21.1",
"java": ">=21",
"craftics": ">=0.2.0"
}
}
Step 4: Implement CrafticsAddon and declare the entrypoint
Create a class that implements com.crackedgames.craftics.api.CrafticsAddon. Craftics calls onCrafticsInit() once at startup, after all built-in content is registered. This guarantees that addon registrations run deterministically after Craftics finishes, unlike plain ModInitializer where load order against Craftics is undefined.
import com.crackedgames.craftics.api.CrafticsAddon;
import com.crackedgames.craftics.api.CrafticsAPI;
import com.crackedgames.craftics.api.registry.WeaponEntry;
import com.crackedgames.craftics.combat.DamageType;
public final class MyCrafticsAddon implements CrafticsAddon {
@Override
public void onCrafticsInit() {
CrafticsAPI.registerWeapon(MyItems.RUNE_BLADE, WeaponEntry.builder(MyItems.RUNE_BLADE)
.damageType(DamageType.SLASHING)
.attackPower(9)
.apCost(1)
.range(1)
.build());
}
}
Then declare the entrypoint in fabric.mod.json under the craftics key:
"entrypoints": {
"craftics": [
"com.example.myaddon.MyCrafticsAddon"
]
}
Exceptions thrown from onCrafticsInit() are caught and logged by Craftics. A failing addon will not crash the game or prevent other addons from loading.
No-code addons. If your addon only adds JSON content (biomes, environments, biome paths, enemies), you do not need a CrafticsAddon class at all. Place JSON files under data/<namespace>/craftics/ in your mod's resources and Craftics discovers them automatically.
Example Addon
The examples/addon-template/ directory in the Craftics repository is a fully working addon you can copy and rename. It is a compatibility addon for the Aether mod: it takes the Aether's content and makes it playable inside Craftics' turn-based combat. This is the most common type of Craftics addon.
File layout
The template uses both extension paths. The Java side registers a weapon and custom AI. The JSON side builds a complete arena region.
examples/addon-template/
build.gradle
src/main/resources/
fabric.mod.json
data/exampleaddon/craftics/
environments/highlands.json <-- arena environment theme
biomes/highlands.json <-- the Highlands biome
paths/aether.json <-- "The Aether" region path
enemies/moa.json <-- Moa enemy template
src/main/java/com/example/exampleaddon/
ExampleCrafticsAddon.java <-- CrafticsAddon entrypoint
MoaAI.java <-- custom combat AI
The entrypoint: ExampleCrafticsAddon
ExampleCrafticsAddon implements CrafticsAddon and is declared under "craftics" in fabric.mod.json. Its onCrafticsInit() does two things.
First, it registers the MoaAI immediately, because that class belongs to this addon and is always available:
CrafticsAPI.registerAI("exampleaddon:moa", new MoaAI());
Second, it defers the Zanite Sword weapon registration to server start. The Aether mod's items may not be in Minecraft's item registry yet when addons initialize, because mod load order is undefined. By registering a SERVER_STARTING listener, the lookup is postponed until every mod's items are ready. If the Aether mod is not installed the lookup finds nothing and skips silently.
ServerLifecycleEvents.SERVER_STARTING.register(server -> {
Identifier id = Identifier.of("aether", "zanite_sword");
if (!Registries.ITEM.containsId(id)) return; // Aether not installed
Item zaniteSword = Registries.ITEM.get(id);
CrafticsAPI.registerWeapon(zaniteSword, WeaponEntry.builder(zaniteSword)
.damageType(DamageType.SLASHING)
.attackPower(11)
.apCost(1)
.range(1)
.ability(Abilities.applyEffect(CombatEffects.EffectType.SLOWNESS, 2, 0))
.build());
});
The deferred cross-mod lookup pattern is the standard approach for compatibility addons. See ExampleCrafticsAddon.java for the full source.
Custom AI: MoaAI
MoaAI implements EnemyAI and gives the Moa two combat phases. Above half health it closes to melee range and strikes. At or below half health it backs away from the player and attacks at range instead. The phase is checked each turn by reading self.getCurrentHp() against self.getMaxHp().
decideAction returns an EnemyAction record. The available actions include Attack, Move, MoveAndAttack, and RangedAttack. The AIUtils helpers handle common pathfinding tasks such as finding an adjacent tile next to the player or computing a flee target. See MoaAI.java for the full implementation and the Enemies page for the full AI reference.
JSON datapacks: the Highlands region
Four JSON files under data/exampleaddon/craftics/ define a complete arena region with no Java code.
environments/highlands.json defines the arena's visual theme: moss block floors, bamboo fence posts, ochre froglight lamps, and a forest obstacle style.
{
"id": "exampleaddon:highlands",
"floor_block": "minecraft:moss_block",
"post_block": "minecraft:bamboo_fence",
"light_block": "minecraft:ochre_froglight",
"decor_style": "forest"
}
biomes/highlands.json defines the Highlands biome. Its "order": 50 places it in the progression sequence. "environment" points at the environment above. The "enemies" block references the Moa enemy template by its id.
{
"id": "exampleaddon:highlands",
"name": "Highlands",
"order": 50,
"levels": 3,
"environment": "exampleaddon:highlands",
"enemies": {
"hostile": [{ "enemy": "exampleaddon:moa", "weight": 10 }],
"boss": { "enemy": "exampleaddon:moa", "weight": 1 }
}
}
enemies/moa.json adopts the Aether's aether:moa entity as a Craftics enemy. The "ai" field names the key registered in code, linking the JSON template to the Java MoaAI class.
{
"id": "exampleaddon:moa",
"entity": "aether:moa",
"ai": "exampleaddon:moa",
"hp": 12,
"attack": 3,
"defense": 0,
"range": 4,
"speed": 3
}
paths/aether.json groups the biome into a named region called "The Aether", which appears in the player's progression map alongside Craftics' built-in Overworld, Nether, and End regions.
{
"id": "exampleaddon:aether",
"display_name": "The Aether",
"biomes": ["exampleaddon:highlands"]
}
To build and run the template, see the instructions in examples/addon-template/README.md. To adapt it for a different mod, rename the exampleaddon id everywhere and swap the Aether items and entities for those of the mod you want to integrate.