In Development

A Hytale Tool by Ionforge Labs

Crucible

An in-game automated testing framework for Hytale server mods. Provides a test harness that runs inside a live server instance, executing test suites against the actual game engine.

Test against real game state — not mocks or simulations.

Hytale Server 2026.05.07+Java 25+Maven 3.9+ (build only)

Why Crucible

Built for Mod Testing

Real Game State

Tests execute against the actual Hytale engine. Real block placement, item resolution, ECS components, and world state — not mocks or simulations.

CI-Ready

JUnit XML output compatible with GitHub Actions, Jenkins, and any CI system. Headless mode boots, runs all suites, reports, and shuts down automatically.

Zero Config

Register your test suites and Crucible handles the rest. Ephemeral world creation, chunk isolation, cleanup — all managed for you.

Execution Modes

Three Ways to Run

From interactive development to headless CI pipelines, Crucible adapts to your workflow.

Player Command

In-game chat commands

Run tests from in-game chat. Results are displayed in both chat and the server console. Perfect for interactive development.

Chat Commands
/crucible run
/crucible run <suite>
/crucible list

Console

Server console, no clients needed

Run suites directly from the server console without any connected clients. Ideal for dedicated server environments.

Server Console
crucible run
crucible run <suite>
crucible list

Headless / CI

Automated pipeline integration

Boot the server, run all tests, write JUnit XML reports, and shut down. Purpose-built for CI/CD pipelines.

Launch Command
java -Dcrucible.autorun=true \
     -jar HytaleServer.jar
GitHub Actions
- name: Run Crucible Tests
  run: |
    java -Dcrucible.autorun=true \
         -jar HytaleServer.jar
- name: Publish Results
  uses: dorny/test-reporter@v1
  with:
    name: Crucible
    path: crucible-reports/*.xml
    reporter: java-junit

TestContext API

Full Engine Access

The TestContext API gives your suites direct access to world manipulation, entity management, and game event observation.

Block Operations

Place, query, and break blocks in the test world. Assert block types, states, and metadata against expected values.

ctx.placeBlock(pos, type)
ctx.getBlockType(pos)
ctx.breakBlock(pos)

Entity Operations

Spawn NPCs and entities, manipulate positions, and verify entity state through the real ECS component system.

ctx.spawnNPC(pos, type)
ctx.removeEntity(entity)
ctx.getPosition(entity)

Container Testing

Insert items into containers, check slot contents, and clear inventories. Test chest, hopper, and custom container logic.

ctx.insertItem(pos, item)
ctx.getSlot(pos, index)
ctx.clearContainer(pos)

Processing Bench

Test furnaces, workbenches, and custom processing blocks. Set inputs, fuel, advance ticks, and verify outputs.

ctx.setInput(pos, item)
ctx.setFuel(pos, fuel)
ctx.advanceProcessing(pos, ticks)

Event Capture

Observe and assert on game events fired during test execution. Capture block breaks, entity spawns, and custom mod events.

ctx.captureEvents(type)
capture.assertFired()
capture.assertCount(n)

Async Testing

Implement AsyncTestSuite for tick-based waiting. Use CompletableFuture to test time-dependent mechanics across game ticks.

AsyncTestSuite interface
ctx.waitTicks(n)
CompletableFuture<TestResult>

Ephemeral Test World

Crucible creates a purpose-built test world for every run. Chunk saving is disabled, player state is not persisted, and NPC spawning is suppressed. Each suite receives an isolated 64-block region, ensuring tests never interfere with each other.

Chunk saving disabledPlayer state isolatedNPC spawning suppressed64-block regions per suite

Architecture

Module Structure

Clean separation between public API, engine core, and output reporters.

crucible/

Project root

api/

Public interfaces

CrucibleAPI
TestSuite
AsyncTestSuite
TestContext
TestResult
EventCapture
core/

Engine internals

TestRegistry
TestRunner
TestWorldManager
reporter/

Output adapters

ConsoleReporter
ChatReporter
JUnitXmlReporter
commands/

Player & console commands

builtin/

Built-in test utilities

plugin/

Server plugin bootstrap

Getting Started

Up and Running in Four Steps

1

Add Dependency

Add Crucible as an OptionalDependency in your mod's manifest.json.

manifest.json
{
  "OptionalDependencies": [
    { "Name": "Crucible" }
  ]
}
2

Register Suites

In your mod's setup() method, register your test suites with the Crucible API.

MyMod.java
@Override
public void setup(ModSetupContext ctx) {
    CrucibleAPI crucible =
        ctx.getOptionalAPI(CrucibleAPI.class);
    if (crucible != null) {
        crucible.register(new MyModTests());
    }
}
3

Implement TestSuite

Write your test methods using the TestContext API for world manipulation and assertions.

MyModTests.java
public class MyModTests implements TestSuite {

    @Override
    public String name() { return "my-mod"; }

    @Override
    public void run(TestContext ctx) {
        ctx.placeBlock(pos, "mymod:machine");
        ctx.assertEqual(
            ctx.getBlockType(pos),
            "mymod:machine"
        );
    }
}
4

Run Tests

Execute your suites from chat, console, or CI. Results appear instantly.

In-Game Chat
/crucible run my-mod