Skip to main content

Lua v4 Script Content Packs

Script bundles need a place for server-specific route filters, selectors, item names, and messages without turning them into global Hexis constants or hiding them in Lua code. Lua v4 uses typed, bundle-local content packs for that data.

This contract is implemented in the source foundation with focused tests. Manifest schema 1 does not expose this surface, and these docs keep hexis.content.pack non-executable until a named distributed build passes controlled live acceptance.

Manifest schema 2

A schema 2 bundle adds a packs array:

{
"schemaVersion": 2,
"files": [
{
"path": "main.lua",
"sha256": "<lowercase 64-character SHA-256>"
}
],
"packs": [
{
"name": "workload",
"kind": "hexis.galatea_fig",
"schemaVersion": 5,
"path": "packs/workload.json",
"sha256": "<lowercase 64-character SHA-256>"
}
]
}

Each pack descriptor has exactly name, kind, schemaVersion, path, and sha256:

  • name matches [a-z][a-z0-9_-]{0,63} and is unique inside the bundle.
  • The public loadable kinds are hexis.galatea_fig, hexis.zealot_one_shot, hexis.sven_engage_acceptance, hexis.experiment_table_acceptance, and hexis.melody_acceptance. The runtime also reserves hexis.area_catalog for official embedded bundles only.
  • schemaVersion is exactly 5 for hexis.galatea_fig and exactly 1 for the combat and GUI acceptance kinds and hexis.area_catalog.
  • path is a canonical relative path below packs/, ends in .json, and is unique across both the manifest's script files and packs.
  • sha256 is exactly 64 lowercase hexadecimal characters and authenticates the file bytes.

The Lua-readable Galatea pack JSON is limited to 64 KiB, a maximum nesting depth of 8, and at most 256 values. Each combat acceptance pack is limited to 32 KiB, the same maximum depth of 8, and at most 192 values. Each GUI acceptance pack is limited to 32 KiB, depth 8, and 256 values. The host verifies the descriptor, path, bytes, kind-specific JSON bounds, kind, schema version, and complete typed payload before executing Lua. Unknown descriptor fields, unknown pack fields, unknown nested fields, unsupported kinds, and unsupported schema versions reject the bundle before Lua runs.

There are no arbitrary pack paths, process-wide pack names, filesystem reads, or fallback to a similarly named pack. A script can load only the logical names declared by its own validated manifest.

An official embedded bundle may declare at most one hexis.area_catalog pack, which has a tighter 32 KiB limit. It is validated into the semantic hexis.area.enter action but is never exposed through hexis.content.pack. Marketplace and development bundles cannot define this reserved kind, and there is no process-wide area catalog. See Lua v4 Area Transitions.

Lua access

The only content access call is:

local workload = hexis.content.pack({name = "workload"})

The request contains exactly the logical name. It requires no capability. The call returns the payload table directly, without a metadata envelope. Each call receives a fresh mutable Lua copy created from the host's validated immutable payload, so changing one returned table cannot mutate the catalog or another call's result.

Galatea workload

The hexis.galatea_fig version 5 payload has exactly these fields:

{
"tree_route": {
"kind": "mineable_blocks",
"entry_block_types": [
"Stripped Spruce Wood"
]
},
"azalea_route": {
"kind": "mineable_blocks",
"entry_block_types": [
"Flowering Azalea"
]
},
"axe": {
"name_patterns": [
"Treecapitator",
"Figstone Splitter",
"Fig Hew",
"Decent Axe"
]
},
"tree_selector": {
"priorities": {
"minecraft:stripped_spruce_wood": 100,
"minecraft:stripped_spruce_log": 95,
"minecraft:stripped_oak_wood": 90,
"minecraft:stripped_oak_log": 85
},
"connectivity": "faces_edges_corners"
},
"azalea_selector": {
"priorities": {
"minecraft:flowering_azalea": 100
},
"connectivity": "faces"
},
"tree_cooldown_seconds": 15,
"azalea_retry_cooldown_seconds": 15,
"fishing_net": {
"name_patterns": [
"Fishing Net"
]
},
"tadpole_query": {
"area": {
"kind": "radius",
"radius": 4.5
},
"selector": {
"type_ids": [
"minecraft:tadpole"
]
},
"limit": 8
},
"regeneration": {
"type": "chat.received",
"filter": {
"contains_any": [
"You cannot damage a tree while it is regenerating"
],
"case_sensitive": false
}
}
}

Both route filters contain exactly kind and entry_block_types; a workload pack no longer contains a route ID. Both kinds are exactly mineable_blocks. Their required entry_block_types contain 1 through 16 exact block display strings of at most 80 characters. Route resolution filters to those entry blocks before applying its result cap. The axe and fishing-net selectors contain 1 through 16 nonblank name patterns of at most 80 characters. Each block selector contains 1 through 16 exact namespaced IDs of at most 120 characters mapped to integer priorities from 1 through 1,000. Larger numbers are preferred. Connectivity is exactly faces or faces_edges_corners.

The version 5 pack has no azalea-count field. The manifest configuration's validated max_azaleas value owns that customer policy, and the removed max_azaleas_between_trees field is rejected as unknown. Both cooldowns are integers from 1 through 300 seconds. The Tadpole query is fixed to a radius from 0.5 through 4.5, exact type minecraft:tadpole, and limit 1 through 8. regeneration.type is exactly chat.received. Unknown nested fields reject the bundle.

Lua can then compose validated data with implemented actions and events:

local workload = hexis.content.pack({name = "workload"})
local config = hexis.config.snapshot()
local arrival = hexis.await(hexis.area.enter({
destination = "hypixel.skyblock.galatea",
}), {timeout = 30})
if not arrival.ok then return arrival end

local regeneration = hexis.events.subscribe(workload.regeneration)
local route = hexis.routes.seeds({
route = config.route,
kind = workload.tree_route.kind,
entry_block_types = workload.tree_route.entry_block_types,
})

local harvest = hexis.mining.mine_connected({
world_generation = route.world_generation,
seeds = route.seeds,
blocks = workload.tree_selector,
held = workload.axe,
handoff = "confirmed",
navigation = {allow_ether_transmission = false},
})

local selected = hexis.select({harvest, regeneration}, {timeout = 600})
if selected.kind ~= "action" then
hexis.cancel(harvest)
end

This moves Galatea-specific selectors and scheduling data out of main.lua without duplicating the customer-selected route. That route comes from the strict configuration contract described in Lua v4 Script Configuration. Mining algorithms, budgets, retries, and vantage selection remain engine-owned. The pack carries the fixed azalea selectors, cooldown, Tadpole query, and regeneration filter consumed by the configurable scheduler described in Lua v4 Galatea Workload. Adding another workload requires a new explicit pack kind and schema rather than weakening this boundary into generic JSON or global server data.

Reduced combat acceptance workloads

The official Zealot one-shot and Sven engagement bundles use strict schema 1 packs with kinds hexis.zealot_one_shot and hexis.sven_engage_acceptance. These schemas carry only the fixed destination, bounded entity query, exact targeting evidence, action parameters, and retry timing needed by those reduced workloads. They are not generic combat configuration, a server-wide target catalog, or a promise of Zealot Farmer or Sven Slayer parity. Sven's flee_health is a strict manifest configuration field, not workload-pack data. See Lua v4 Combat Actions for their exact acceptance scope and exclusions.

Reduced GUI acceptance workloads

The official Experiment Table and Melody bundles use strict schema 1 packs with kinds hexis.experiment_table_acceptance and hexis.melody_acceptance. The first carries fixed titles, layout slots, item signatures, and click delay for its three reduced puzzle policies. The second carries the Harp title and slot count, note and stack item IDs, score-chat filter, and click delay. Strings are nonblank and bounded to 128 characters; arrays are nonempty, unique, and bounded by their typed schema. Unknown fields reject the bundle before Lua runs.

These packs do not expose raw click parameters, purchase policy, arbitrary screen rules, or timing control for unrelated scripts. They do not establish Experiment Table auto-renew or Melody perfect-score parity. See Lua v4 GUI Evidence and Actions for the precise transaction, event, workload, and live-acceptance boundaries.