Kimi swarm project: mc-heroes-mod
Find a file
hermes 2a7db01fc6
All checks were successful
Build Mod / build (push) Successful in 4m33s
ci: re-run via runner pickup verification
2026-09-26 20:06:53 -07:00
.forgejo/workflows fix #20: upload-artifact v4 not supported on Forgejo — pin v3 (verified mirror SHA) 2026-08-11 04:20:38 -07:00
.githooks fix #18: Add pre-commit hooks to mc-heroes-mod 2026-06-16 20:22:45 -07:00
.gsd/gates add pre-dispatch gate and .gitignore negation for .gsd/gates/ 2026-08-04 20:09:57 -07:00
.kilo/plans add issue #4 plan file for verify gate 2026-08-04 20:50:08 -07:00
project fix #4: tune task scheduler scoring 2026-08-04 20:44:04 -07:00
src fix #3: add client-side assets, hero items, and CI gate scaffolding 2026-06-16 20:22:45 -07:00
tests fix #3: add client-side assets, hero items, and CI gate scaffolding 2026-06-16 20:22:45 -07:00
.gitignore fix #19, #20: CI workflow never succeeds — route to healthy runner, use Forgejo action mirror 2026-08-11 03:25:12 -07:00
.pre-commit-config.yaml fix #18: Add pre-commit hooks to mc-heroes-mod 2026-06-16 20:22:45 -07:00
AUDIT.md docs: add AUDIT.md from feature completeness evaluation 2026-05-10 15:15:23 -07:00
Cargo.toml fix #3: add client-side assets, hero items, and CI gate scaffolding 2026-06-16 20:22:45 -07:00
generate_item_textures.py fix #3: add client-side assets, hero items, and CI gate scaffolding 2026-06-16 20:22:45 -07:00
generate_skins.py fix #3: add client-side assets, hero items, and CI gate scaffolding 2026-06-16 20:22:45 -07:00
gradle fix #3: add client-side assets, hero items, and CI gate scaffolding 2026-06-16 20:22:45 -07:00
gradlew fix #3: add client-side assets, hero items, and CI gate scaffolding 2026-06-16 20:22:45 -07:00
package.json fix #3: add client-side assets, hero items, and CI gate scaffolding 2026-06-16 20:22:45 -07:00
plan.md Add Stage 10 — Equipment & Inventory System (issue #12) 2026-05-13 22:03:14 +00:00
README.md docs: document CI workflow, runner registration, and label routing 2026-08-11 04:29:32 -07:00
SPEC.md Add equipment/inventory system section (issue #12) 2026-05-13 22:03:13 +00:00

Heroes Mod — Virtual Players for Minecraft

Heroes is a NeoForge 1.21.1 server-side Minecraft mod that adds roaming hero characters — autonomous fake-player actors that perform small, flavorful scenes in your world. Heroes make the world feel inhabited and reactive without adding automation grind or heavy processing overhead.

Mod ID: heroesmod | Version: 1.0.0 | License: MIT


Overview

Heroes are rare (1–8 per world) diegetic actors with distinct personalities, roles, and tasks. They spawn as fake-player entities, wander villages, repair walls, light dark paths, keep watch at night, set up camps, and share their catch. Everything is server-side — clients only need standard entity rendering from the active backend (SiliconeDolls or NeoForge's built-in FakePlayer).

Architecture at a glance:

Level Tick → HeroTicker → HeroSpawner / SceneDirector / HeroDespawner
                              │
                    ┌─────────┼─────────┐
                    │         │         │
              Spawn/Despawn  Task     Scene
              (Backend)   Scheduling  Lifecycle

Hero Roles

Each hero belongs to one of four built-in roles. Roles define default personality traits, task-weight preferences, and preferred biomes.

Role Traits Likes Dislikes Signature
Caretaker Frugal, Cautious Patching walls (×2.0), lighting paths (×1.8) Camping (×0.3), watching (×0.5) Village repair & maintenance
Wayfarer Brave, Curious Setting up camp (×1.5), visiting villages (×1.0) Patching walls (×0.1), watching (×0.3) Wilderness travel & camping
Watcher Brave, Cautious Keeping watch (×2.5), lighting paths (×1.0) Fishing (×0.2), wall patching (×0.3) Night patrol & village defense
Fisher Frugal, Curious Fishing (×2.5), camping (×0.8) Wall patching (×0.1), watching (×0.4) Dawn fishing & food sharing

Extensibility: Custom roles can be added via JSON datapack — see Custom Roles below.


Tasks & Scenes

Heroes autonomously select tasks based on their role, current traits, location, time of day, and cooldowns. Each task produces a scene — a lifecycle-driven script that the hero performs in the world.

Task Lifecycle

Every scene follows a finite-state machine:

PREPARE → SPAWN → PERFORM → COMMIT → (DESPAWN | IDLE)
              ↑                    │
              └──── retry (max 3) ←┘
Phase Description
PREPARE Validate preconditions, find target positions, reserve blocks
SPAWN Ensure the hero's fake-player embodiment exists
PERFORM Execute the task script (movement + actions) tick by tick
COMMIT Apply world edits atomically via WorldEditValidator
DESPAWN Remove the embodiment and mark the hero offline
IDLE Keep the embodiment present but idle in the world

Built-in Tasks

Task Role Boost Preconditions What Happens World Edits
Visit Village Wayfarer +0.3, Caretaker +0.1 Daytime, within 256 blocks of a village Walk to village center, wander 4 waypoints, leave None
Patch Wall Caretaker +0.5 Within 128 blocks of a village, damaged wall blocks found Walk along wall, inspect, place up to 4 matching blocks Blocks (≤4)
Light Path Caretaker +0.4, Watcher +0.2 Nighttime (13000–23000), dark path blocks near village Walk path, place 1–2 lanterns/torches Lights (≤2)
Keep Watch Watcher +0.5 Village edge, nighttime or post-raid Patrol 3–4 waypoints, look toward threat directions None
Forage Camp Wayfarer +0.4 Wilderness (not in village), forest/plains biome, evening Place campfire + decor, sit/stand for 400–600 ticks, pack up Campfire (temporary)
Fish & Share Fisher +0.5 Dawn (0–3000 ticks), within 64 blocks of water Walk to water, fish, leave a small food crate Barrel/chest with fish

Commands

All commands require permission level 2 (operator).

Command Description
/heroes list List all heroes with name, role, online status, current task, location
/heroes info <name> Full dump of one hero's persona, state, fatigue, and cooldowns
/heroes spawn <name> [x y z] Force-spawn a hero at a position (or their home region)
/heroes despawn <name> Force-despawn a hero's embodiment
/heroes task force <name> <taskType> Force-assign a specific task to a hero
/heroes task clear <name> Clear a hero's current task
/heroes config reload Reload configuration from disk

Configuration

Global config is stored in config/heroesmod-common.toml (NeoForge spec format).

[maxHeroes]

Key Default Range Description
maxHeroes 4 1–32 Maximum heroes active per world

[spawning]

Key Default Range Description
spawnIntervalTicks 60 20–200 Ticks between spawn/despawn checks
maxSpawnAttempts 2 1–10 Max spawn attempts per check
spawnBatchSize 1 1–8 Max heroes to spawn per batch
minTPS 15.0 10–20 Minimum TPS to allow spawning
despawnIdleTicks 6000 1200–72000 Idle timeout before despawn

[tasks]

Key Default Range Description
taskFrequencyTicks 1200 200–10000 Approx ticks between task assignments
maxSceneDurationTicks 1200 200–6000 Maximum scene duration before timeout

[worldEdit]

Key Default Range Description
maxBlocksPerScene 8 1–64 Max blocks placed per hero per scene
maxBlocksPerHeroPerHour 100 10–1000 Hourly cap per hero (real-time)
maxBlocksPerChunkPerHour 500 10–5000 Hourly cap per chunk

[backend]

Key Default Description
backendMode "auto" "auto", "silicone_dolls", or "fakeplayer_only"

[integration]

Key Default Description
villageIntegrationEnabled true Enable Villager Behavior mod integration

Architecture

com.heroesmod/
├── api/              # Core data model (HeroActor, HeroPersona, HeroRole, HeroTraits,
│                     #   HeroState, Task, TaskType, Scene, ActorHandle)
├── backend/          # ActorBackend abstraction: SiliconeDollsBackend, FakePlayerBackend,
│                     #   BackendManager (auto-discovery)
├── commands/         # /heroes command tree (list, info, spawn, despawn, task, config)
├── config/           # HeroesCommonConfig (TOML spec), HeroIndividualConfig (per-hero overrides)
├── data/             # HeroSavedData (world-scoped SavedData), HeroDataAttachments
├── integration/      # VillagerBehaviorIntegration (optional, reflection-based)
├── registry/         # HeroRegistry (CRUD), JsonHeroLoader (datapack JSON loading)
├── scene/            # SceneDirector (lifecycle state machine driver)
├── spawn/            # HeroSpawner, HeroDespawner, SpawnValidator
├── tasks/            # VisitVillageTask, PatchWallTask, LightPathTask, KeepWatchTask,
│                     #   ForageCampTask, FishAndShareTask, TaskScheduler
├── tick/             # HeroTicker (low-frequency scheduler)
├── util/             # HeroNames (name generation), SafePositionFinder
└── worldedit/        # WorldEditValidator (protection hooks), PatchBuilder, RateLimiter

Key Design Decisions

  • Server-side only — All hero logic runs on the server. Clients only need entity rendering (provided by the active backend).
  • Low population — 1–8 heroes per entire world, not per village. Each hero is a persistent character, not a generic NPC.
  • Scene lifecycle — Every task produces a Scene with a well-defined FSM (PREPARE → SPAWN → PERFORM → COMMIT → IDLE/DESPAWN).
  • Atomic world edits — Edits are planned during PERFORM and validated/applied atomically at COMMIT through WorldEditValidator.
  • Rate-limited world editing — Per-hero per-hour and per-chunk per-hour caps prevent runaway world modification.
  • Backend abstraction — The ActorBackend interface decouples hero embodiment from any specific fake-player library. SiliconeDolls is preferred; NeoForge's built-in FakePlayerFactory is the fallback.
  • Fatigue & cooldowns — Heroes get tired and have per-task cooldowns, ensuring they don't loop the same behavior endlessly.

Dependencies

Dependency Type Version Notes
NeoForge Required ≥21.1.1 (MC 1.21.1) Mod loader and framework
Minecraft Required 1.21.1 – 1.21.x Game version
Java Required 21+ Language and toolchain
SiliconeDolls Optional ≥1.0.0 Preferred fake-player backend (auto-detected)
Villager Behavior Optional Any Village needs integration (event-based, reflection)

Build & Setup

Prerequisites

  • JDK 21+
  • Gradle (included via wrapper)

Building

cd project/
./gradlew build

The compiled JAR will be in build/libs/heroesmod-1.0.0.jar.

CI (Forgejo Actions)

.forgejo/workflows/ci.yml builds and uploads the mod JAR on every push. Action references are SHA-pinned to the Forgejo mirror (https://data.forgejo.org/actions/*); runs-on: linux routes to the healthy containerized runners (a bare-binary runner on this instance claims ubuntu-latest but kills every job it picks up). The repo has its own runner registered (localhost-mcheroes-runner) — if runs ever sit in waiting, check that the repo still has a registered runner matching the linux label.

Running in Development

# Client (with NeoForge dev environment)
./gradlew runClient

# Dedicated server
./gradlew runServer

Installing

  1. Install NeoForge 21.1.1+ for Minecraft 1.21.1 on your server.
  2. Place heroesmod-1.0.0.jar in the mods/ folder.
  3. (Optional) Install SiliconeDolls for better entity rendering.
  4. Restart the server.
  5. Heroes will start spawning automatically as chunks load around villages.

First run: The mod seeds the world with 1–4 starter heroes if none exist. Use /heroes list to see them.


Persistence

Hero state is stored as NeoForge SavedData under the key heroesmod_actors. Data is saved to the world folder automatically on server stop and during normal save cycles.

On-disk NBT structure:

heroesmod_actors
├── heroes (ListTag)
│   └── [0..n] (CompoundTag per hero)
│       ├── id (UUID)
│       ├── name (String)
│       ├── role (String enum)
│       ├── traits (Int bitmask)
│       ├── homeRegionX/Z (Int)
│       ├── homeDimension (ResourceLocation)
│       ├── currentTask (String, nullable)
│       ├── locationX/Y/Z (Double)
│       ├── online (Boolean)
│       ├── fatigue (Float)
│       ├── lastSeenTime (Long)
│       ├── embodimentId (Int)
│       └── cooldowns (CompoundTag)

Extensibility

Custom Hero Roles (JSON Datapack)

Create a datapack with JSON files at:

data/<namespace>/heroes/roles/<role_id>.json
{
  "name": "my_role",
  "default_traits": ["brave", "curious"],
  "task_weights": {
    "visit_village": 1.0,
    "patch_wall": 0.5,
    "forage_camp": 1.5,
    "fish_and_share": 0.3,
    "light_path": 0.2,
    "keep_watch": 0.8
  },
  "preferred_biomes": ["minecraft:plains", "minecraft:forest"],
  "home_structure": "minecraft:village"
}

Roles are loaded at datapack reload and merged with the internal registry. Weights are relative — higher values make the hero more likely to choose that task.

Custom Tasks

Implement the Task interface:

public class MyCustomTask implements Task {
    @Override
    public TaskType getType() {
        return TaskType.get(ResourceLocation.parse("mymod:my_task"));
    }

    @Override
    public boolean canRun(HeroActor hero, ServerLevel level) { ... }

    @Override
    public double score(HeroActor hero, ServerLevel level) { ... }

    @Override
    public Scene createScene(HeroActor hero, ServerLevel level) { ... }

    @Override
    public int getEstimatedDuration() { return 600; }

    @Override
    public float getFatigueCost() { return 0.2f; }

    @Override
    public int getCooldownTicks() { return 2400; }
}

Register the task type:

TaskType.register(ResourceLocation.parse("mymod:my_task"), "My Task");

Then add it to any hero role's task_weights in their JSON definition.

Adding Custom Traits

Extend the HeroTraits enum to add new personality flags. Traits are stored as a bitmask integer, so up to 32 distinct traits are supported.


Integration Points

SiliconeDolls (Optional)

Auto-detected at startup. When present, heroes are rendered as fully animated doll entities with smooth movement. When absent, the mod falls back to NeoForge's FakePlayerFactory, which renders heroes as standard player-like entities.

Configure with: backendMode = "silicone_dolls" or "auto" (prefers SiliconeDolls).

Villager Behavior Mod (Optional)

When present, heroes read "village needs" data and adjust their task priorities accordingly — e.g., boosting repair tasks when village damage is detected.

Configure with: villageIntegrationEnabled = true (default).

Protection Mods

WorldEditValidator checks for common protection APIs via reflection (FTB Chunks, WorldGuard, etc.) and skips block edits in protected regions. Each integration is optional and silently skipped if the mod is not present.


Performance

Heroes are designed for minimal server impact:

  • Low frequency ticker — The HeroTicker runs every spawnIntervalTicks (default 60 ticks = ~3 seconds), not every single tick.
  • Small population — 1–8 heroes per world keeps entity count negligible.
  • TPS gating — Spawning is skipped if server TPS drops below minTPS (default 15.0).
  • Chunk unloading — Heroes despawn if their chunk stays unloaded for 600+ ticks.
  • Tiny world edits — At most maxBlocksPerScene (default 8) blocks per scene, with hourly per-hero and per-chunk caps.

Project Structure

heroes-mod/
├── plan.md                     # Implementation plan (10 stages)
├── SPEC.md                     # Full design specification
├── project/
│   ├── build.gradle            # NeoForge moddev build
│   ├── settings.gradle         # Gradle settings
│   ├── gradle.properties       # Version & mod metadata
│   ├── src/main/
│   │   ├── java/com/heroesmod/ # Main source (packages above)
│   │   └── resources/
│   │       ├── META-INF/neoforge.mods.toml
│   │       ├── pack.mcmeta
│   │       └── data/heroesmod/heroes/roles/
│   │           ├── caretaker.json
│   │           ├── wayfarer.json
│   │           ├── watcher.json
│   │           └── fisher.json
│   └── build/                  # Compiled output
└── README.md                   # This file

License

This project is licensed under the MIT License — see the LICENSE file for details (or refer to the mod_license field in gradle.properties).