Modding Guide

Full public API reference for addon mod developers — weapons, equipment, trims, events, enchantments, biomes, and AI.

Overview

Craftics exposes a comprehensive Java API through the CrafticsAPI class that lets addon mods extend every major system. All registration methods are static and should be called during your mod's onInitialize().

The following registry types are available:

Registry Method Purpose
Weapons registerWeapon() Add items as Craftics weapons with damage types, abilities, and stats
Equipment Scanners registerEquipmentScanner() Read stat bonuses from non-standard inventory slots (custom equipment slots)
Armor Sets registerArmorSet() Define full-set bonuses for custom armor materials
Trim Patterns registerTrimPattern() Add per-piece and set bonuses for custom trim patterns
Trim Materials registerTrimMaterial() Add stat bonuses for custom trim materials
Events registerEvent() Create between-level events (gambling, traders, ambushes, etc.)
Enchantments registerEnchantment() Map enchantments to passive combat stat bonuses
Biomes registerBiome() Add biomes programmatically (also supports JSON datapacks)
Enemy AI registerAI() Define AI strategies for custom mob types

Craftics also supports no-code modding via JSON datapacks for biomes and .nbt/.schem files for arena maps. See the Biomes and Arena Maps sections below.

Getting Started

To create a Craftics addon mod you need a standard Fabric mod that declares Craftics as a dependency. All API calls go in your mod initializer.

Step 1: Declare the Dependency

In your fabric.mod.json, add Craftics as a dependency so Fabric loads it before your mod:

{
  "schemaVersion": 1,
  "id": "mymod-craftics-compat",
  "version": "1.0.0",
  "name": "MyMod Craftics Compat",
  "environment": "*",
  "entrypoints": {
    "main": ["com.example.mymod.CrafticsCompat"]
  },
  "depends": {
    "fabricloader": ">=0.16.0",
    "craftics": ">=1.0.0"
  }
}

Step 2: Register from onInitialize()

All CrafticsAPI.registerXxx() calls must happen during mod initialization. The API is thread-safe and order-independent.

import com.crackedgames.craftics.api.CrafticsAPI;
import net.fabricmc.api.ModInitializer;

public class CrafticsCompat implements ModInitializer {
    @Override
    public void onInitialize() {
        // Register weapons, scanners, armor sets, etc.
        CrafticsAPI.registerWeapon(myItem, myWeaponEntry);
        CrafticsAPI.registerEquipmentScanner("mymod", myScanner);
        CrafticsAPI.registerArmorSet(myArmorSetEntry);
        // ... more registrations
    }
}

API Package Structure

All public API types live under these packages:

Weapon Registration

Register any Item as a usable weapon in Craftics combat with CrafticsAPI.registerWeapon(). Each weapon needs a WeaponEntry that defines its damage type, stats, and optional ability.

WeaponEntry Builder

Use the fluent builder API to construct a WeaponEntry:

WeaponEntry entry = WeaponEntry.builder(myItem)
    .damageType(DamageType.SLASHING)   // damage category
    .attackPower(8)                    // flat attack value
    .apCost(1)                         // action points per attack
    .range(1)                          // attack range in tiles
    .ranged(false)                     // true for projectile weapons
    .breakChance(0.0)                  // probability of breaking per use (0.0 - 1.0)
    .ability(myAbilityHandler)         // optional on-hit ability
    .build();

CrafticsAPI.registerWeapon(myItem, entry);
Builder Method Type Default Description
damageType(DamageType)enumPHYSICALWeapon's damage category
attackPower(int)int1Base attack power
attackPower(IntSupplier)supplierDynamic attack power (called each attack)
apCost(int)int1Action point cost per attack
range(int)int1Attack range in tiles
ranged(boolean)boolfalseWhether this is a ranged weapon
breakChance(double)double0.0Chance to break on use (0.0–1.0)
ability(WeaponAbilityHandler)handlernullOn-hit ability (see below)

DamageType Enum

Every weapon belongs to one of eight damage types. Armor sets, trims, and player affinity points can grant bonuses to specific types.

ValueDisplay NameTypical Weapons
SLASHINGSlashingSwords
CLEAVINGCleavingAxes
BLUNTBluntMaces, shovels
WATERWaterTridents, corals
SPECIALSpecialBlaze rods, end rods, breeze rods
PETPetPet attacks
RANGEDRangedBows, crossbows
PHYSICALPhysicalDefault / untyped

Abilities (Built-in Ability Factories)

The Abilities class provides static factory methods that return WeaponAbilityHandler instances. These are composable — chain them with .and() to combine multiple effects on one weapon.

// Compose two abilities: bleed + sweep
WeaponAbilityHandler handler = Abilities.bleed()
    .and(Abilities.sweepAdjacent(0.10, 0.05));
Factory MethodDescription
bleed()Applies bleed stacks equal to the weapon's Sharpness enchant level
sweepAdjacent(baseChance, bonusPerPoint)Chance to hit one adjacent enemy for half damage (scales with SLASHING affinity)
armorIgnore(baseChance, bonusPerPoint)Chance to deal bonus damage equal to target's defense (scales with CLEAVING affinity)
stun(baseChance, bonusPerPoint)Chance to stun target for one turn (scales with BLUNT affinity)
knockbackDirection(distance)Pushes target away from player by up to N tiles
aoe(radius, damageMultiplier)Hits all enemies within radius (Manhattan distance) of target
applyEffect(type, turns, amplifier)Applies a status effect (POISON, BURNING, SOAKED, SLOWNESS, CONFUSION)
pierce()Hits the first enemy behind the target in the attack direction
fireDamage(bonusDmg)Sets target on fire and deals flat bonus fire damage

Custom Ability Handler

WeaponAbilityHandler is a @FunctionalInterface. Implement it for fully custom on-hit logic:

@FunctionalInterface
public interface WeaponAbilityHandler {
    WeaponAbility.AttackResult apply(
        ServerPlayerEntity player,
        CombatEntity target,
        GridArena arena,
        int baseDamage,
        PlayerProgression.PlayerStats stats,
        int luckPoints
    );

    // Compose with another handler:
    default WeaponAbilityHandler and(WeaponAbilityHandler next);
}

Return a WeaponAbility.AttackResult(totalDamage, messages, extraTargets) where messages is a list of combat log strings and extraTargets is a list of additional entities hit by the ability.

Example: Custom Weapon

import com.crackedgames.craftics.api.CrafticsAPI;
import com.crackedgames.craftics.api.Abilities;
import com.crackedgames.craftics.api.registry.WeaponEntry;
import com.crackedgames.craftics.combat.DamageType;

// Heavy Claymore: cleaving type, armor ignore + knockback
Item myItem = net.minecraft.registry.Registries.ITEM
    .get(net.minecraft.util.Identifier.of("mymod", "heavy_claymore"));
CrafticsAPI.registerWeapon(myItem, WeaponEntry.builder(myItem)
    .damageType(DamageType.CLEAVING)
    .attackPower(7)
    .apCost(2)
    .range(1)
    .ability(Abilities.armorIgnore(0.15, 0.03)
        .and(Abilities.knockbackDirection(2)))
    .build());

Equipment Scanners

Equipment scanners let addon mods contribute stat bonuses from non-standard inventory slots. This is how addon mods with custom equipment slots integrate with Craftics combat stats. Register one with CrafticsAPI.registerEquipmentScanner().

EquipmentScanner Interface

@FunctionalInterface
public interface EquipmentScanner {
    StatModifiers scan(ServerPlayerEntity player);
}

The scanner is called during combat stat calculation. It receives the player and returns a StatModifiers object containing all bonuses from that mod's equipment.

StatModifiers Class

Accumulates bonuses using the TrimEffects.Bonus enum as keys:

StatModifiers mods = new StatModifiers();
mods.add(TrimEffects.Bonus.DEFENSE, 2);      // +2 defense
mods.add(TrimEffects.Bonus.SPEED, 1);        // +1 speed
mods.add(TrimEffects.Bonus.MAX_HP, 4);       // +4 max HP
mods.addSetBonus(TrimEffects.SetBonus.FERAL, "Feral Ring Set"); // optional set bonus

Available Bonus Types

RANGED_POWER, MELEE_POWER, SPEED, AP, DEFENSE, LUCK, ATTACK_RANGE, MAX_HP, ARMOR_PEN, REGEN, ALLY_DAMAGE, STEALTH_RANGE, SWORD_POWER, CLEAVING_POWER, BLUNT_POWER, WATER_POWER, SPECIAL_POWER

Example: Equipment Scanner

import com.crackedgames.craftics.api.CrafticsAPI;
import com.crackedgames.craftics.api.EquipmentScanner;
import com.crackedgames.craftics.api.StatModifiers;
import com.crackedgames.craftics.combat.TrimEffects;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;

CrafticsAPI.registerEquipmentScanner("mymod", (player) -> {
    StatModifiers mods = new StatModifiers();

    // Read items from your addon's custom equipment slots
    // and map them to Craftics stat bonuses
    ItemStack belt = getCustomSlot(player, "belt");
    if (!belt.isEmpty()) {
        if (belt.isOf(Registries.ITEM.get(Identifier.of("mymod", "swift_belt")))) {
            mods.add(TrimEffects.Bonus.SPEED, 1);
        } else if (belt.isOf(Registries.ITEM.get(Identifier.of("mymod", "iron_belt")))) {
            mods.add(TrimEffects.Bonus.DEFENSE, 2);
        }
    }

    ItemStack amulet = getCustomSlot(player, "amulet");
    if (!amulet.isEmpty() && amulet.isOf(Registries.ITEM.get(Identifier.of("mymod", "lucky_charm")))) {
        mods.add(TrimEffects.Bonus.LUCK, 3);
    }

    return mods;
});

Combat Effects

Overview

Combat effects are custom lifecycle callbacks that fire during combat. Unlike flat stat bonuses, they can react to events — taking damage, killing enemies, moving — and modify combat behavior dynamically. They are registered by calling StatModifiers.addCombatEffect() inside an EquipmentScanner.

CombatEffectHandler Interface

CombatEffectHandler is an interface with 24 default no-op methods. Override only the callbacks your effect needs. The 15 currently wired callbacks are:

Callback Returns When it fires
onCombatStart(ctx) void Combat begins
onTurnStart(ctx) void Player's turn starts
onTurnEnd(ctx) void Player's turn ends
onCombatEnd(ctx) void Combat finishes
onDealKillingBlow(ctx, killed) void Player kills an enemy
onTakeDamage(ctx, attacker, damage) CombatResult Player takes damage
onLethalDamage(ctx, attacker, damage) CombatResult Damage would kill player
onDodge(ctx, attacker) void Player dodges an attack
onMove(ctx, from, to, distance) void Player moves on grid
onEmeraldGain(ctx, amount) CombatResult Emeralds awarded
onLootRoll(ctx, loot) void Loot generated (mutable list)
onEnemySpawn(ctx, enemy) void Enemy enters arena
onEffectExpired(ctx, effect) void Status effect wears off
onCrit(ctx, target, damage) (planned) void Critical hit (future)
onMiss(ctx, target) (planned) void Attack misses (future)

CombatResult

Callbacks that return CombatResult can intercept and modify the value in question. Three factory methods are available:

CombatResult.unchanged(damage)              // pass through unchanged
CombatResult.modify(newValue, "message")    // change the value, display a message
CombatResult.cancel("message")             // cancel the action entirely (e.g., prevent death)

CombatEffectContext

All callbacks receive a CombatEffectContext as their first argument. It exposes the following getters:

ctx.getPlayer()         // ServerPlayerEntity — the combatant
ctx.getArena()          // CombatArena — the active arena
ctx.getPlayerEffects()  // List of active status effects on the player
ctx.getTrimScan()       // TrimScan — the player's trim data
ctx.getAllEnemies()      // List<CombatEntity> — all current enemies
ctx.getAllAllies()       // List<CombatEntity> — all current allies

Statefulness

Handlers are per-combat instances — a fresh instance is created at combat start each time the scanner runs. This means you can safely use instance fields to track state within a single fight:

mods.addCombatEffect("One-Shot Shield", new CombatEffectHandler() {
    private boolean used = false; // resets each combat

    @Override
    public CombatResult onLethalDamage(CombatEffectContext ctx, CombatEntity attacker, int damage) {
        if (!used) {
            used = true;
            // ...
        }
        return CombatResult.unchanged(damage);
    }
});

Registration

Call mods.addCombatEffect(name, handler) inside your EquipmentScanner. Multiple effects per item are allowed — each registered independently with its own name and instance.

CrafticsAPI.registerEquipmentScanner("mymod", (player) -> {
    StatModifiers mods = new StatModifiers();

    ItemStack ring = getCustomSlot(player, "ring");
    if (ring.isOf(MY_THORNS_RING)) {
        mods.addCombatEffect("Thorns Ring", new ThornsCombatEffect());
    }

    return mods;
});

Examples

Thorns Effect (reflect damage)

mods.addCombatEffect("Thorns Ring", new CombatEffectHandler() {
    @Override
    public CombatResult onTakeDamage(CombatEffectContext ctx, CombatEntity attacker, int damage) {
        if (attacker != null) attacker.takeDamage(Math.max(1, damage / 4));
        return CombatResult.modify(damage, "§6Thorns Ring reflects damage!");
    }
});

Death Prevention (once per combat)

mods.addCombatEffect("Lucky Charm", new CombatEffectHandler() {
    private boolean used = false;

    @Override
    public CombatResult onLethalDamage(CombatEffectContext ctx, CombatEntity attacker, int damage) {
        if (!used) {
            used = true;
            ctx.getPlayer().heal(10);
            return CombatResult.cancel("§d❦ Lucky Charm saves you from death!");
        }
        return CombatResult.unchanged(damage);
    }
});

Bonus Emeralds

mods.addCombatEffect("Fortune Amulet", new CombatEffectHandler() {
    @Override
    public CombatResult onEmeraldGain(CombatEffectContext ctx, int amount) {
        return CombatResult.modify(amount + 2, "§6Fortune Amulet: +2 bonus emeralds!");
    }
});

Armor Sets

Register custom armor set bonuses that activate when a player wears a full set of matching armor. The armor set ID must match what the game detects for your armor material.

ArmorSetEntry Builder

ArmorSetEntry entry = ArmorSetEntry.builder("mymod:mythril")
    .damageBonus(DamageType.SLASHING, 2)  // +2 slashing damage
    .damageBonus(DamageType.CLEAVING, 1)  // +1 cleaving damage
    .speedBonus(1)                        // +1 speed
    .apBonus(0)                           // +0 action points
    .defenseBonus(3)                      // +3 defense
    .attackBonus(1)                       // +1 attack
    .apCostReduction(0)                   // -0 AP cost
    .description("Mythril Armor: light and sharp")
    .build();

CrafticsAPI.registerArmorSet(entry);
Builder MethodTypeDefaultDescription
damageBonus(DamageType, int)per-type0Bonus damage for a specific damage type
allDamageBonus(int)all typesSets the same bonus for every damage type
speedBonus(int)int0Movement speed bonus
apBonus(int)int0Extra action points per turn
defenseBonus(int)int0Defense stat bonus
attackBonus(int)int0Base attack bonus
apCostReduction(int)int0Reduction in AP cost per attack
description(String)string""Tooltip description shown in combat HUD

Trim Effects

Craftics gives armor trims gameplay effects. Each trim pattern grants a per-piece stat bonus and a full-set bonus (when all 4 armor pieces share the same pattern). Each trim material grants its own per-piece stat bonus. Register custom patterns and materials for modded trims.

Trim Pattern Registration

CrafticsAPI.registerTrimPattern(new TrimPatternEntry(
    "mymod:dragon",                          // pattern ID
    TrimEffects.Bonus.MELEE_POWER,           // per-piece stat
    "+1 Melee Power per piece",              // per-piece description
    TrimEffects.SetBonus.FERAL,              // full-set bonus
    "Dragon's Fury",                         // set bonus display name
    "First attack each turn costs 0 AP"      // set bonus description
));

TrimPatternEntry Fields

FieldTypeDescription
patternIdStringRegistry ID of the trim pattern (e.g., "mymod:dragon")
perPieceStatTrimEffects.BonusStat bonus granted per armor piece with this pattern
perPieceDescriptionStringHuman-readable description of the per-piece bonus
setBonusTrimEffects.SetBonusBonus activated when all 4 pieces use this pattern
setBonusNameStringDisplay name for the set bonus
setBonusDescriptionStringHuman-readable description of the set bonus

Trim Material Registration

CrafticsAPI.registerTrimMaterial(new TrimMaterialEntry(
    "mymod:orichalcum",            // material ID
    TrimEffects.Bonus.ARMOR_PEN,   // stat bonus type
    2,                              // value per armor piece
    "+2 Armor Penetration per piece"
));

TrimMaterialEntry Fields

FieldTypeDescription
materialIdStringRegistry ID of the trim material
statTrimEffects.BonusStat bonus type
valuePerPieceintBonus value per armor piece with this material
descriptionStringHuman-readable description

Bonus Enum Values

TrimEffects.BonusEffect
RANGED_POWERBonus ranged attack damage
MELEE_POWERBonus melee attack damage (all melee types)
SPEEDMovement speed (tiles per turn)
APExtra action points per turn
DEFENSEDamage reduction
LUCKAffects loot rolls and ability proc chances
ATTACK_RANGEExtra attack range in tiles
MAX_HPBonus maximum hit points
ARMOR_PENIgnore portion of enemy defense
REGENHP regeneration per turn
ALLY_DAMAGEBonus damage for pet/ally attacks
STEALTH_RANGEReduced enemy detection range
SWORD_POWERBonus SLASHING damage specifically
CLEAVING_POWERBonus CLEAVING damage specifically
BLUNT_POWERBonus BLUNT damage specifically
WATER_POWERBonus WATER damage specifically
SPECIAL_POWERBonus SPECIAL damage specifically

SetBonus Enum Values

TrimEffects.SetBonusNameEffect
NONENo set bonus
OVERWATCHSentryCounter-attack at range
SANDSTORMDuneEnemy speed reduction aura
TIDALCoastWater heals the player
FERALWildFirst attack each turn is free
FORTRESSWardHalve damage when stationary
ALL_SEEINGEyeRanged critical hit bonus
ETHEREALVexDodge chance
OCEAN_BLESSINGTideEmergency heal at low HP
BRUTE_FORCESnoutAttacks deal splash damage
INFERNALRibFire attacks deal bonus damage
FORTUNE_PEAKSpireDouble emerald rewards
PATHFINDERWayfinderIgnore obstacles when moving
TERRAFORMERShaperMovement deals AoE damage
PHANTOMSilenceStart combat invisible
RALLYRaiserBuff allies at start of turn
SYMBIOTEHostHeal on kill
CURRENTFlowKills refund AP
THUNDERSTRIKEBoltCritical hits stun the target

Events

Between-level events fire after completing a combat level. Register custom events with CrafticsAPI.registerEvent(). Events are selected randomly based on probability after each level.

EventEntry Fields

CrafticsAPI.registerEvent(new EventEntry(
    "mymod:treasure_chest",    // unique event ID
    "Treasure Chest",          // display name
    0.15f,                     // probability (0.0 - 1.0)
    2,                         // minimum biome ordinal (0-indexed) to appear
    true,                      // isChoiceEvent: player picks from options
    myEventHandler             // EventHandler implementation
));
FieldTypeDescription
idStringUnique event identifier
displayNameStringName shown in the event popup
probabilityfloatChance to trigger after each level (0.0–1.0)
minBiomeOrdinalintEarliest biome where this event can appear (0 = first biome)
isChoiceEventbooleanWhether the player gets to choose between options
handlerEventHandlerLogic executed when the event fires

EventHandler Interface

@FunctionalInterface
public interface EventHandler {
    void execute(List<ServerPlayerEntity> participants,
                 ServerWorld world,
                 EventManager eventManager);
}

The EventManager provides helper methods for showing UI popups, giving items, applying effects, and managing event state.

EventTemplates

The EventTemplates class will provide pre-built patterns for common event types. Planned templates include:

EventTemplates are currently under development. For now, implement EventHandler directly.

Example: Custom Event

CrafticsAPI.registerEvent(new EventEntry(
    "mymod:healing_spring",
    "Healing Spring",
    0.10f,
    1,      // available from biome index 1 onwards
    false,  // not a choice event - just happens
    (participants, world, eventManager) -> {
        for (ServerPlayerEntity player : participants) {
            // Heal each player by 4 HP
            player.heal(4.0f);
        }
    }
));

Enchantments

Register enchantments that grant passive stat bonuses during Craftics combat. The handler receives an EnchantmentContext with the enchantment level, the player, and a StatModifiers accumulator.

EnchantmentEffectHandler and EnchantmentContext

@FunctionalInterface
public interface EnchantmentEffectHandler {
    void apply(EnchantmentContext ctx);
}

public class EnchantmentContext {
    public int getLevel();                  // enchantment level (1, 2, 3...)
    public ServerPlayerEntity getPlayer();  // the player
    public StatModifiers getModifiers();    // accumulator to add bonuses to
}

Example: Custom Enchantment

// Holy Blessing: +1 defense and +1 regen per enchantment level
CrafticsAPI.registerEnchantment("mymod:holy_blessing", (ctx) -> {
    ctx.getModifiers().add(TrimEffects.Bonus.DEFENSE, ctx.getLevel());
    ctx.getModifiers().add(TrimEffects.Bonus.REGEN, ctx.getLevel());
});

// Swiftness: +1 speed at any level
CrafticsAPI.registerEnchantment("mymod:swiftness", (ctx) -> {
    ctx.getModifiers().add(TrimEffects.Bonus.SPEED, 1);
});

Biomes

Biomes can be added via JSON datapacks (no code required) or programmatically through CrafticsAPI.registerBiome().

JSON Datapacks (No Code)

Place biome JSON files at data/<namespace>/craftics/biomes/my_biome.json. The full JSON schema:

{
  "id": "my_biome",
  "name": "My Custom Biome",
  "order": 20,
  "levels": 5,
  "grid": {
    "base_width": 10,
    "base_height": 10,
    "width_growth": 1,
    "height_growth": 1
  },
  "floor_blocks": ["minecraft:stone_bricks", "minecraft:mossy_stone_bricks"],
  "obstacle_blocks": ["minecraft:cobblestone_wall"],
  "obstacle_density": 0.1,
  "obstacle_density_growth": 0.02,
  "environment": "cave",
  "night": true,
  "enemies": {
    "passive": [
      {"type": "minecraft:bat", "weight": 3, "hp": 2, "attack": 0, "defense": 0, "range": 1}
    ],
    "hostile": [
      {"type": "minecraft:skeleton", "weight": 8, "hp": 10, "attack": 3, "defense": 0, "range": 3},
      {"type": "minecraft:spider", "weight": 6, "hp": 8, "attack": 3, "defense": 0, "range": 1}
    ],
    "boss": {"type": "minecraft:warden", "hp": 50, "attack": 8, "defense": 4, "range": 2}
  },
  "loot": [
    {"item": "minecraft:diamond", "weight": 5},
    {"item": "minecraft:iron_ingot", "weight": 15}
  ]
}

Field Reference

FieldTypeDescription
idstringRequired. Unique identifier.
namestringDisplay name in HUD and level select.
orderintSort position. Lower = earlier in progression.
levelsintNumber of levels (typically 5). Last level = boss.
grid.base_widthintStarting grid width.
grid.base_heightintStarting grid height.
grid.width_growthintWidth increase per level.
grid.height_growthintHeight increase per level.
floor_blocksstring[]Floor tile blocks (checkerboard pattern).
obstacle_blocksstring[]Obstacle blocks placed on the grid.
obstacle_densityfloatBase obstacle probability (0.0–1.0).
obstacle_density_growthfloatDensity increase per level.
environmentstringVisual style: plains, forest, desert, jungle, river, mountain, snowy, cave, nether_wastes, end, deep_dark
nightboolNight mode (prevents undead burning).
enemies.passivearrayPassive mob pool (weighted random).
enemies.hostilearrayHostile mob pool (weighted random).
enemies.bossobjectBoss for the final level.
lootarrayWeighted loot table (1–3 items rolled per level).

Programmatic Registration

CrafticsAPI.registerBiome(myBiomeTemplate);
int totalLevels = CrafticsAPI.getTotalLevels();

Use the same id as a built-in biome to override its settings. Use /reload to hot-reload biome JSONs without restarting.

Enemy AI

Register custom AI strategies for mob types that Craftics does not support natively. The AI controls what action an enemy takes each turn.

AI Registration

CrafticsAPI.registerAI("mymod:custom_zombie", (self, arena, playerPos) -> {
    // Your AI logic: decide what to do this turn
    return new EnemyAction.Attack(self.getAttackPower());
});

Available Action Types

27 action types are available for custom AI. Return any of these from your AI strategy:

Move, Attack, MoveAndAttack, Flee, Teleport, TeleportAndAttack, Pounce, Explode, RangedAttack, Swoop, StartFuse, Detonate, Idle, AttackMob, MoveAndAttackMob, AttackWithKnockback, MoveAndAttackWithKnockback, SummonMinions, AreaAttack, CreateTerrain, LineAttack, ModifySelf, ForcedMovement, BossAbility, CeilingAscend, CeilingDrop, CompositeAction

Supported Mob Types (Built-in)

The following mobs already have registered AI and can be used in custom biomes without additional code:

Complete Example

A full addon mod skeleton registering custom weapons, an equipment scanner, an armor set, and an event with Craftics.

fabric.mod.json

{
  "schemaVersion": 1,
  "id": "mymod-craftics-addon",
  "version": "1.0.0",
  "name": "MyMod Craftics Addon",
  "description": "Adds MyMod weapons, equipment, armor sets, and events to Craftics combat.",
  "environment": "*",
  "entrypoints": {
    "main": ["com.example.mymod.CrafticsAddon"]
  },
  "depends": {
    "fabricloader": ">=0.16.0",
    "craftics": ">=1.0.0",
    "mymod": ">=1.0.0"
  }
}

CrafticsAddon.java

package com.example.mymod;

import com.crackedgames.craftics.api.*;
import com.crackedgames.craftics.api.registry.*;
import com.crackedgames.craftics.combat.DamageType;
import com.crackedgames.craftics.combat.TrimEffects;
import net.fabricmc.api.ModInitializer;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;

public class CrafticsAddon implements ModInitializer {

    @Override
    public void onInitialize() {
        registerWeapons();
        registerEquipmentScanner();
        registerArmorSet();
        registerEvent();
    }

    private void registerWeapons() {
        // --- Heavy Claymore: cleaving weapon with armor ignore + knockback ---
        Item claymore = getItem("mymod", "heavy_claymore");
        CrafticsAPI.registerWeapon(claymore, WeaponEntry.builder(claymore)
            .damageType(DamageType.CLEAVING)
            .attackPower(7)
            .apCost(2)
            .range(1)
            .ability(Abilities.armorIgnore(0.15, 0.03)
                .and(Abilities.knockbackDirection(1)))
            .build());

        // --- Swift Rapier: fast slashing weapon with bleed + pierce ---
        Item rapier = getItem("mymod", "swift_rapier");
        CrafticsAPI.registerWeapon(rapier, WeaponEntry.builder(rapier)
            .damageType(DamageType.SLASHING)
            .attackPower(4)
            .apCost(1)
            .range(1)
            .ability(Abilities.bleed()
                .and(Abilities.pierce()))
            .build());

        // --- Longreach Glaive: slashing weapon with extended range + sweep ---
        Item glaive = getItem("mymod", "longreach_glaive");
        CrafticsAPI.registerWeapon(glaive, WeaponEntry.builder(glaive)
            .damageType(DamageType.SLASHING)
            .attackPower(5)
            .apCost(1)
            .range(2)
            .ability(Abilities.sweepAdjacent(0.20, 0.04))
            .build());
    }

    private void registerEquipmentScanner() {
        // Scan mymod's custom equipment slots and contribute stats to Craftics
        CrafticsAPI.registerEquipmentScanner("mymod", (player) -> {
            StatModifiers mods = new StatModifiers();
            // Read items from your addon's custom equipment slots
            // and map them to Craftics stat bonuses
            Item swiftBelt = getItem("mymod", "swift_belt");
            Item ironBelt  = getItem("mymod", "iron_belt");
            Item luckCharm = getItem("mymod", "lucky_charm");

            ItemStack belt = getCustomSlot(player, "belt");
            if (!belt.isEmpty()) {
                if (belt.isOf(swiftBelt))  mods.add(TrimEffects.Bonus.SPEED, 1);
                else if (belt.isOf(ironBelt)) mods.add(TrimEffects.Bonus.DEFENSE, 2);
            }

            ItemStack amulet = getCustomSlot(player, "amulet");
            if (!amulet.isEmpty() && amulet.isOf(luckCharm)) {
                mods.add(TrimEffects.Bonus.LUCK, 3);
            }
            return mods;
        });
    }

    private void registerArmorSet() {
        // Full-set bonus for mymod:mythril armor
        CrafticsAPI.registerArmorSet(ArmorSetEntry.builder("mymod:mythril")
            .damageBonus(DamageType.SLASHING, 2)
            .damageBonus(DamageType.CLEAVING, 1)
            .speedBonus(1)
            .defenseBonus(2)
            .description("Mythril Armor: light and sharp")
            .build());
    }

    private void registerEvent() {
        // A healing spring event available from biome index 1 onwards
        CrafticsAPI.registerEvent(new EventEntry(
            "mymod:healing_spring",
            "Healing Spring",
            0.12f,
            1,
            false,
            (participants, world, eventManager) -> {
                for (ServerPlayerEntity player : participants) {
                    player.heal(5.0f);
                }
            }
        ));
    }

    private static Item getItem(String namespace, String path) {
        return Registries.ITEM.get(Identifier.of(namespace, path));
    }
}

Custom Arena Maps

Step 1: Build Your Arena

Create the full scene in creative mode including a flat area for the grid, surrounding decorations (trees, ruins, water, cliffs), and any blocks you want. The area outside the grid is purely cosmetic. The game only reads the grid boundaries and spawn markers.

Step 2: Place Marker Blocks

Place special marker blocks to define the playable grid and spawn positions. The game scans for these blocks when loading the arena.

┌─────────────────────────────┐ │ Decorations... │ │ DIAMOND────────────────EMERALD │ ← Diamond + Emerald on opposite corners OUTSIDE grid │ │ GOLD │ │ ← Gold = Player 1 spawn (inside grid) │ │ (playable grid) │ │ │ │ IRON │ │ ← Iron = Player 2 spawn (optional) │ │ │ │ │ │ │ │ │ More terrain... │ └─────────────────────────────┘

Marker Block Reference

BlockPurpose
Diamond BlockCamera corner. Place on one corner outside the grid (required).
Emerald BlockOpposite corner. Place on the corner diagonally opposite the Diamond Block (required).
Gold BlockPlayer 1 spawn (primary)
Iron BlockPlayer 2 spawn (multiplayer)
Copper BlockPlayer 3 spawn
Coal BlockPlayer 4 spawn

All markers must be at the same Y level.

Step 3: Export

Option A: WorldEdit (recommended)

  1. Select: //pos1 and //pos2
  2. Copy: //copy
  3. Save: //schem save <name>
  4. Find in config/worldedit/schematics/
  5. Copy to craftics_arenas/<biome>/<number>.schem

Option B: Vanilla Structure Block (48×48×48 limit)

  1. /give @s structure_block
  2. Set to Save mode, define box, name it, click SAVE
  3. Find in <world>/generated/minecraft/structures/
  4. Copy to datapack at data/craftics/structures/arenas/<biome>/<number>.nbt

File Naming

craftics_arenas/          (in game run directory, for .schem)
  plains/
    1.schem
    2.schem
    boss_1.schem
  forest/
    1.schem

data/craftics/structures/arenas/   (in datapack, for .nbt)
  plains/
    1.nbt
    boss_1.nbt

Biome IDs for Arena Folders

OverworldNetherEnd
plainsnether_wastesouter_end_islands
forestsoul_sand_valleyend_city
desertcrimson_forestchorus_grove
junglewarped_forestdragons_nest
riverbasalt_deltas
mountain
snowy
cave
deep_dark

Tips

Mob Head Textures

The combat HUD displays a small head icon for every enemy and ally in the arena. Craftics ships 80+ vanilla mob heads and auto-discovers textures for modded mobs at runtime, so no code changes are needed to add heads for new mobs.

Resolution Order

When the HUD requests a head for entity type somemod:bigwolf, MobHeadTextures.get() checks three sources in order:

  1. Hardcoded vanilla map — ~80 built-in entries for all vanilla mobs. Always checked first.
  2. Runtime registration — entries added via the Java API (see below). Checked second.
  3. Resource auto-discovery — probes the loaded resource manager for a PNG at two path conventions (see below). Results are cached until /reload.

If none of the three sources return a texture, the HUD falls back to a colored square with the mob’s first initial.

Resource Pack Method (No Code)

Drop a 16×16 PNG at one of these two paths inside any resource pack:

ConventionPathUse Case
Craftics namespace assets/craftics/textures/mob_heads/{modid}/{mobname}.png Resource packs shipping heads for any modded mob under Craftics’ namespace
Mod namespace assets/{modid}/textures/mob_heads/{mobname}.png A mod shipping its own head texture in its own namespace

For a mob with entity type alexsmobs:bone_serpent, the auto-discovery probes:

assets/craftics/textures/mob_heads/alexsmobs/bone_serpent.png   (Craftics namespace)
assets/alexsmobs/textures/mob_heads/bone_serpent.png            (mod namespace)

Run /reload or toggle the resource pack and the head appears on the combat HUD immediately — no client restart required.

Java API Method (Mod Code)

Addon mods can register head textures explicitly during client initialization:

import com.crackedgames.craftics.client.MobHeadTextures;
import net.minecraft.util.Identifier;

// In your ClientModInitializer.onInitializeClient():
MobHeadTextures.register(
    "somemod:bigwolf",
    Identifier.of("somemod", "textures/hud/bigwolf_head.png")
);

Runtime-registered entries take priority over auto-discovery but not over the built-in vanilla map.

Cache & Reload

Auto-discovered textures are cached after the first lookup. The cache is cleared automatically whenever /reload runs or resource packs change (via a SimpleSynchronousResourceReloadListener registered in CrafticsClient), so new or updated PNGs are picked up without restarting the client.

Addon Policy

Allowed

Not Allowed