ActionRegistryService
Register typed handlers and execute JSON action descriptors with validation, cooldowns, and permissions.
What is it for?
The action system provides a reusable registry for executing JSON-declared actions through typed C# handlers. Mods register IActionHandler implementations during startup; JSON assets declare ActionDescriptor entries that reference the handler by id. The registry validates, executes, and reports outcomes.
This replaces the older ItemAction data-only descriptor with a full execution pipeline.
When to use it
- Your items or blocks have JSON-declared actions that need typed C# execution.
- You want validation, cooldowns, and permission checks handled uniformly.
- You need to execute a sequence of actions with early-exit on failure.
- You want to migrate from
ItemActionto a richer descriptor without breaking assets.
Quick example
Register a handler
using ArcanumLib.Actions;
using ArcanumLib.Core;
public class TeleportAction : IActionHandler
{
public string Id => "teleport";
public bool IsAvailable(ActionContext context)
{
return context.PlayerEntity != null;
}
public ActionResult Execute(ActionContext context)
{
var pos = context.TargetPos;
if (pos == null) return ActionResult.Invalid("No target position.");
context.PlayerEntity?.TeleportTo(pos);
return ActionResult.Success();
}
}
// In StartServerSide:
var registry = ArcanumServices.Get<IActionRegistryService>(ArcanumServiceScope.Server)!;
registry.Register(new TeleportAction());
Declare in JSON
{
"id": "teleport",
"args": [],
"cooldownMs": 5000,
"requiredPermission": "build"
}
Execute
var executor = ArcanumServices.Get<IActionExecutorService>(ArcanumServiceScope.Server)!;
var descriptor = ActionDescriptor.FromJson(jsonString);
var context = new ActionContext(sapi, player, itemSlot, targetPos);
ActionResult result = executor.Execute(descriptor, context);
if (result.IsSuccess)
sapi.Logger.Notification("Action succeeded.");
else
sapi.Logger.Warning("Action failed: {0}", result.Message);
API overview
ActionRegistryService
| Method | Description |
|---|---|
Register(IActionHandler) | Registers a handler by its Id. |
RegisterAll(IEnumerable) | Registers multiple handlers. |
Unregister(string) | Removes a handler. |
GetHandler(string) | Returns the handler or null. |
IsRegistered(string) | Checks if a handler exists. |
Validate(descriptor, context) | Checks availability without executing. |
Execute(descriptor, context) | Validates and executes. |
ExecuteAll(descriptors, context, continueOnError) | Executes a sequence. |
Clear() | Clears all handlers. |
ActionExecutorService
| Method | Description |
|---|---|
Execute(ActionDescriptor, context) | Executes with cooldown and permission checks. |
GetRemainingCooldown(entityId, actionId) | Returns remaining cooldown in ms (uses ArcanumServices API time). |
GetRemainingCooldown(entityId, actionId, sapi) | Returns remaining cooldown using the provided server API. |
ClearCooldowns(entityId) | Clears cooldowns for a player. |
ActionDescriptor
| Field | Description |
|---|---|
Id | Handler identifier. |
Args | String arguments passed to the handler. |
CooldownMs | Per-player cooldown in ms. |
RequiredPermission | VS privilege required to execute. |
Condition | Optional declarative condition evaluated before the handler. |
Declarative conditions
Actions can declare a condition in JSON that is evaluated before the handler runs. If the condition fails, the action returns NotAvailable without calling the handler.
{
"id": "giveitem",
"args": ["game:ingot-iron", "1"],
"condition": {
"type": "All",
"conditions": [
{ "type": "HasKey", "key": "reputation" },
{ "type": "MinValue", "key": "reputation", "value": "100" }
]
}
}
The context’s Extra dictionary is checked. Set values before executing:
var context = new ActionContext(sapi, player, itemSlot, targetPos);
context.Extra["reputation"] = 150;
ActionResult result = executor.Execute(descriptor, context);
Condition types
| Type | Description |
|---|---|
Always | Always true. |
MinValue | Extra[key] >= value. |
MaxValue | Extra[key] <= value. |
HasKey | Extra contains key. |
Equals | Extra[key] equals value (string comparison). |
Permission | Player has the privilege named in value. |
All | All nested conditions must be true. |
Any | At least one nested condition must be true. |
Not | Negates the first nested condition. |
ActionResult
| Property | Description |
|---|---|
IsSuccess | True when Outcome == Success. |
Outcome | Success, NotAvailable, Invalid, HandlerNotFound, Failed. |
Message | Optional human-readable detail. |
Notes
ActionRegistryServiceandActionExecutorServiceare registered inArcanumServices(Server scope) byArcanumDataModSystemduringStartServerSide.- The registry is thread-safe (locked).
- Cooldowns are per-player per-action-id, tracked server-side, and use
World.ElapsedMilliseconds. ArcanumDataModSystem.Dispose()unregisters the services on world unload.- Handlers should not throw; exceptions are caught and returned as
Failed.