Customize beat-game strategy
Replace beat-game steps, combine behaviors, add safety checks, and call plugin APIs.
Strategy hooks replace one policy action. The runner still manages timeouts, retries, claims, checkpoints, events, and control.
Replace one policy step
import { Effect } from "effect";
import { beatGame } from "@soulfiremc/beat-game";
const run = yield* beatGame(bot, {
hooks: {
fightEnderDragon: ({ driver, strategy }) =>
customDragonFight(driver, strategy).pipe(Effect.as(true)),
},
});A hook performs one stable unit of work, then returns. The planner reads a new observation before it continues. A completed hook does not prove that the world changed.
Available hooks cover:
- death recovery
- eating and retreat
- equipment preparation
- requirement acquisition
- Nether construction and entry
- portal return
- eye throwing and stronghold search
- End portal activation
- the dragon fight.
Compose exported behaviors
Use behavior programs when the built-in phase planner is not needed:
import {
collectBlocks,
craftItem,
equipBestArmor,
} from "@soulfiremc/beat-game";
yield* collectBlocks(driver, {
blockIds: ["minecraft:oak_log"],
count: 8,
searchRadius: 48,
});
yield* craftItem(driver, {
resultItemId: "minecraft:shield",
count: 1,
});
yield* equipBestArmor(driver);Behaviors call generic server tasks where one already models the work. Portal casting, item throwing, and stronghold triangulation remain TypeScript programs composed from lower-level operations.
Call a plugin-defined RPC
Require the generated companion SDK before starting the run, then close over the typed plugin client in a hook:
const combat = yield* soulfire.plugins.require(combatPlugin);
const run = yield* beatGame(bot, {
hooks: {
fightEnderDragon: ({ checkpoint }) =>
combat.fightDragon({
instanceId: checkpoint.instanceId,
botId: checkpoint.botId,
}).pipe(
Effect.map((result) => result.defeated),
),
},
});The plugin owns the optional domain behavior. It can also expose a durable task when work must continue through an SDK disconnect. SoulFire core does not gain a dragon-specific RPC.
Use soulfire.plugins.reflective(pluginId) when no generated companion package
is available. Reflective calls still validate protobuf input and plugin
compatibility.
Tune the default strategy
const run = yield* beatGame(bot, {
strategy: {
portalStrategy: PortalStrategy.CAST,
minimumHealth: 10,
eatBelowFood: 15,
maximumActionRetries: 7,
actionTimeoutMs: 180_000,
path: {
allowMining: true,
allowPlacing: true,
maxFallDistance: 2,
},
},
});Strategy options are a deep partial for path. Invalid counts, thresholds,
timeouts, and path limits fail before the run starts.
Do not put an infinite loop inside a hook. Return after one stable action so pause, stop, retry, checkpointing, and team claims remain responsive.
Deploy as a worker
For a long-lived deployment:
- Place the worker close to SoulFire to reduce action latency.
- Use a durable checkpoint store.
- Use one shared coordinator for multi-process teams.
- Drain the event stream into structured logs or telemetry.
- Let the process manager restart the worker with the same run identity.
- Treat
BeatGameCheckpointErrorconflicts as another active writer, not as a transient network failure.
How is this page?
Last updated on
