Skip to content
This repository was archived by the owner on Oct 16, 2026. It is now read-only.
Legends11 edited this page Sep 28, 2026 · 1 revision

🏠 vortacraftmc/core — Complete Wiki

Build & Lint Minecraft Gradle JDK Loader License

The consolidated monorepo for the vortacraftmc ecosystem: Fabric mods, datapacks, resource packs and the tooling that keeps them honest. Original project by Runtoolkit (runtoolkit/suite) · maintained by vortacraftmc.


📑 Table of contents

  1. Overview
  2. Getting Started
  3. Repository Structure
  4. Build System
  5. CI and DevContainer
  6. ⭐ macroEngine (framework datapack)
  7. macroEngine Resource Pack
  8. Fabric Mods
  9. GUIKit — in-game GUI editor
  10. Utility Packs
  11. Archived Datapacks
  12. Examples
  13. Scripts and Tools
  14. Merge Manifest & mergeDatapacks
  15. Pack Formats and Versions
  16. Contributing
  17. Security
  18. Troubleshooting
  19. FAQ
  20. Glossary

1 · Overview

What is this repository?

vortacraftmc/core is a monorepo consolidating what used to be a dozen separate repositories under the retired runtoolkit organization:

Directory Contents Built by Gradle?
mods/ Fabric mods (Java, Loom) ✅ yes
packs/ Datapacks & resource packs 📦 packaged/validated only
examples/ Templates & sample projects ✅ yes (mod example)
scripts/ Helper tooling (Python/Node) 🔧 standalone
.github/ CI workflows, issue templates, CODEOWNERS ⚙️ CI
build-logic/ shared Gradle script for Fabric subprojects ⚙️ build
.devcontainer/ one-click dev environment ⚙️ DX
archived/ reserved for frozen projects (empty today) —
other/ reserved for uncategorized content (empty today) —

Important

Datapacks are in maintenance mode. Bug fixes, security hardening and compatibility fixes are in scope; new feature work belongs in Fabric mods. Every existing pack is additionally locked by packs/.datapack-lock.json and enforced in CI — see §16.3 the lock protocol.

Project status at a glance

Project Kind Target Status
macroEngine v26.4 framework datapack MC 26.4-snapshot-1 ✅ current
macroEngine v26.3 framework datapack MC 26.3 🗄️ archived
macroEngine resource pack resource pack MC 26.4-snapshot-1 ✅ required by macroEngine
guikit-datapack in-world GUI editor MC 26.3 🔒 locked, maintained
BorderPing / DailyBonus / QuickShare utility packs format [122, 1] 🔒 locked, maintained
datapack-blocker Fabric mod MC 1.21.1 ✅ maintained
datapack-fixer Fabric mod (standalone build) MC 1.21.4 ✅ maintained
rtwrapper-mod Fabric mod MC 1.21.1 ✅ maintained
opmod-example (LevelOp) Fabric mod MC 26.3 ✅ example
TEMPLATE-MOD Fabric template MC 26.x 📄 template
itemExampleMod example Fabric mod MC 26.1.2 📄 example
TunnelScript · cmdTunnel · inv_gui · click-detection packs · RTWrapper (datapack) datapacks 1.19.2 – 26.3 🗄️ archived

Legend: ✅ active · 🔒 locked in CI · 🗄️ archived · 📄 template/example

History

  • Originated as runtoolkit/suite by Runtoolkit, consolidating the runtoolkit organization's repositories: TunnelScript, LeftClickDetection, dp-depman, RTWrapper, datapack-fixer, itemExampleMod, template-datapack, InteractionClickDetection, cmdTunnel-datapack, dpgen, TEMPLATE-MOD, inv_gui, macroEngine, guigen.
  • The runtoolkit organization was retired in favour of vortacraftmc; the old repositories are archived and point here.
  • Original copyright notices are preserved in each LICENSE/NOTICE file.
  • Skipped during consolidation (empty/inconsistent): FunctionPP (2 files), DataLibFabric (placeholder), the old .github repo (2 files).

2 · Getting Started

2.1 Prerequisites

Requirement Version Notes
JDK 25 Required — the wrapper will not build with older JDKs. Temurin recommended[^1].
Git any recent
Gradle (none) The Gradle wrapper (./gradlew) is committed — do not install Gradle separately.
Disk space ~2 GB free Gradle cache + Minecraft jars via Fabric Loom.
RAM 2 GB+ for Gradle Root gradle.properties sets -Xmx4G; see §18.4 OOM for small machines.

[^1]: CI uses actions/setup-java with the temurin distribution — matching it locally avoids "works on CI" surprises.

Tip

On a 2 GB VPS or Codespace, override the heap instead of editing files:

./gradlew buildAll --max-workers=1 -Dorg.gradle.jvmargs="-Xmx1500m -XX:MaxMetaspaceSize=512m"

2.2 Cloning

git clone https://github.com/vortacraftmc/core.git
cd core

2.3 Your first build

./gradlew buildAll

What that actually runs:

flowchart LR
    A[buildAll] --> B[":mods:*:build\n(Fabric Loom)"]
    A --> C[":examples:*:build"]
    A --> D[zipPacks]
    D --> E[checkPacks\npack.mcmeta + JSON + refs]
    D --> F["package packs/ → build/packs-dist/"]
Loading
  • Fabric subprojects (mods/, examples/itemExampleMod) are compiled and remapped by Fabric Loom; JARs land in each subproject's build/libs/.
  • zipPacks validates every pack (checkPacks) and packages them into build/packs-dist/. It demands confirmation — pass -PconfirmZip=yes non-interactively (CI does exactly this).
  • lint is separate: ./gradlew lint.

Other useful entry points:

Command What it does
./gradlew build root lifecycle: mergeDatapacks → build/dist/
./gradlew verifyMod fabric.mod.json sanity, mixin refs, duplicate mod ids
./gradlew checkPacks pack.mcmeta / JSON validation only (no zipping)
./gradlew printPackList / printPackFormats / printModList / printModVersions inventory reports
./gradlew mergeDatapacks merge packs per §14
./gradlew showOriginWatermarks / checkOriginWatermarks provenance watermark audit

2.4 Building one subproject

./gradlew :mods:datapack-blocker:build
./gradlew :mods:rtwrapper-mod:build
./gradlew :examples:itemExampleMod:build

Warning

Scoped builds are fine while iterating, but always run the full ./gradlew buildAll and ./gradlew lint before opening a PR — a shared dependency bump can silently break a sibling subproject. This is the #1 CI failure mode called out in NOTICE.md.

2.5 Using the datapacks

Datapacks are not compiled. To use one:

  1. Copy the pack folder (or the zip produced by zipPacks) into your world's datapacks/ directory — or configure a server-side pack source.
  2. Run /reload or restart.
  3. For macroEngine you must also install the companion resource pack — messages, sounds and trim assets live there.

Version compatibility is per-pack: see §15.

2.6 Devcontainer (zero-setup)

The repo ships a devcontainer definition (.devcontainer/) with GitHub CLI, zsh, and postCreateCommand / postStartCommand hooks (setup.sh / start.sh) that provision the toolchain. VS Code extensions are pre-declared:

  • misode.vscode-datapack-helper & SPGoding.datapack-language-server — datapack DX
  • redhat.java + vscjava.vscode-java-pack — mod development
  • vscjava.vscode-gradle — Gradle integration

Open the repo via Reopen in Container (or GitHub Codespaces) and run ./gradlew buildAll. Details: §5.5.

2.7 IDE setup tips

  • IntelliJ IDEA — import the root build.gradle; each Fabric subproject gets Loom run configurations (Minecraft Client/Minecraft Server).
  • VS Code — the devcontainer extensions above cover both Java and datapack languages; datapack-language-server understands mcfunction, SNBT and pack.mcmeta.
  • Datapack authors: keep an eye on the pack-format matrix — min_format/max_format replaced pack_format for modern releases.

3 · Repository Structure

3.1 Top-level layout

core/
├── mods/                      Fabric mods (Gradle subprojects)
│   ├── TEMPLATE-MOD/            MC 26.x template, split client/main sourcesets
│   ├── datapack-blocker/        MC 1.21.1 — locks the world datapacks/ folder
│   ├── datapack-fixer/          MC 1.21.4 — standalone build, excluded from shared build
│   ├── opmod-example/           MC 26.3 — "LevelOp", /op <player> <level>
│   └── rtwrapper-mod/           MC 1.21.1 — Fabric successor of RTWrapper
├── packs/                     Datapacks & resource packs (NOT compiled)
│   ├── macroEngine-Datapack-v26.3 / -v26.4
│   ├── macroEngine-Resourcepack-v26.3 / -v26.4
│   ├── guikit-datapack/ guikit-demo/
│   ├── BorderPing/ DailyBonus/ QuickShare/
│   ├── TunnelScript/ cmdTunnel-datapack/ inv_gui/
│   ├── LeftClickDetection/ InteractionClickDetection/
│   ├── RTWrapper/ RTWrapper-1.21.1/ RTWrapper-v1.0.1/
│   ├── merge-manifest.json      input for the mergeDatapacks task
│   └── .datapack-lock.json      CI immutability locks
├── examples/
│   ├── itemExampleMod/          example Fabric mod (MC 26.1.2, Gradle subproject)
│   └── template-datapack/       minimal datapack skeleton
├── scripts/                   standalone tooling (Python / Node)
│   ├── datapack_risk_scan.py    read-only security audit → Markdown report
│   ├── datapack_lock/check_lock.py
│   ├── dp-depman/               datapack dependency manager (Python, stdlib only)
│   ├── dpgen/                   config-driven datapack generator (Node)
│   └── gui_generator/           "guigenmc" — JSON → GUI datapack (Python, web UI)
├── build-logic/
│   └── shared-fabric-mod.gradle common processResources/jar/publishing blocks
├── .github/
│   ├── workflows/               build.yml, datapack-immutability.yml, …
│   ├── ISSUE_TEMPLATE/          structured bug/security reports
│   └── CODEOWNERS
├── .devcontainer/             devcontainer.json + setup.sh + start.sh
├── settings.gradle            subproject auto-discovery (see §3.2)
├── build.gradle               root aggregate tasks (~2,200 lines)
├── gradle.properties          daemon JVM args (-Xmx4G), parallel, caching
├── README.md · NOTICE.md · CONTRIBUTING.md · SECURITY.md · LICENSE
└── banner.png · index.html

3.2 Gradle wiring: settings.gradle discovery

settings.gradle auto-discovers subprojects — you normally never edit it when adding a project:

  1. Scans SCAN_ROOTS = ['mods', 'packs', 'examples'] recursively for any build.gradle / build.gradle.kts.
  2. Includes each hit as :<root>:<relative-dir> (e.g. :mods:datapack-blocker).
  3. Skips anything under a build/ or .gradle/ output directory.
  4. Skips explicit exclusions, each with a recorded reason:
Excluded path Reason
mods/datapack-fixer legacy tool, not yet migrated to the shared build — has its own wrapper + GameTests
packs/RTWrapper/rtwrapper-fabric superseded by mods/rtwrapper-mod; kept for historical reference

Add -PdebugSettings=1 to any Gradle invocation for verbose per-directory discovery logs. Every build prints a summary:

[settings] subproject discovery summary:
[settings]   mods/ -> 5 subproject(s)
[settings]   packs/ -> 1 subproject(s)
[settings]   examples/ -> 1 subproject(s)
[settings]   total: 7 subproject(s), 2 excluded

3.3 Shared build logic

build-logic/shared-fabric-mod.gradle is applied via apply from: (not as a precompiled plugin — deliberately, so each subproject can pin its own Fabric Loom version). It factors out only:

  • the processResources block that expands ${version} into fabric.mod.json
  • withSourcesJar()
  • the basic mavenJava publication

Intentionally not shared (because they differ per project): the plugins{} block, version/group, dependencies{}, Java release levels (21 vs 25), and loom{} special cases like TEMPLATE-MOD's splitEnvironmentSourceSets().

3.4 Provenance watermarks

Every datapack under packs/ carries a _vc_origin.mcfunction file under data/<namespace>/function/:

  • zipPacks fails the build if a watermark is missing.
  • showOriginWatermarks / checkOriginWatermarks audit them (cleanOriginWatermarks exists but is disabled).
  • Contributors must not remove, rename or hand-edit watermarks in packs/ — this is a conduct expectation, not a license restriction (the Unlicense still governs copies you obtain).
  • Some packs additionally keep an older _rt_origin.mcfunction (Runtoolkit-era) tag entry; both coexist without conflict.

3.5 The datapack lock file

packs/.datapack-lock.json marks every existing top-level pack as locked: true:

BorderPing · DailyBonus · InteractionClickDetection · LeftClickDetection · QuickShare · RTWrapper · RTWrapper-1.21.1 · RTWrapper-v1.0.1 · TunnelScript · cmdTunnel-datapack · inv_gui · macroEngine-Datapack-v26.3/-v26.4 · macroEngine-Resourcepack-v26.3/-v26.4 · guikit-datapack · guikit-demo

The datapack-immutability.yml workflow fails any PR touching a file under a locked pack. Editing one requires the three-PR protocol — §16.3. New top-level pack directories are allowed through (that's how packs get added) but must be added to the lock file, locked, in a prompt follow-up PR.


4 · Build System

4.1 Toolchain

Component Version Source of truth
Gradle 9.4.0 gradle/wrapper/gradle-wrapper.properties
JDK 25 CI (temurin) and mod toolchains
Fabric Loom per-subproject (see §4.3) each build.gradle plugins{} block
Fabric Maven https://maven.fabricmc.net/ settings.gradle pluginManagement

4.2 Root task map

flowchart TD
    buildAll["buildAll (aggregate)"] --> modBuilds[":mods:*:build · :examples:*:build"]
    buildAll --> zipPacks
    zipPacks --> checkPacks
    zipPacks --> dist["build/packs-dist/*.zip"]
    build["build (root lifecycle)"] --> mergeDatapacks
    mergeDatapacks --> merged["build/merged-datapack/ + .zip"]
    build --> distRoot["build/dist/"]
    check["check (root lifecycle)"] --> verifyMod
    lint["lint (aggregate)"] --> modLints["per-subproject lint hooks"]
Loading

4.3 Fabric Loom policy

Gradle plugin versions are per-subproject in this monorepo, by design:

Subproject MC target Loom Mappings Java
mods/datapack-blocker 1.21.1 1.15.5 Yarn 1.21.1+build.3 21
mods/rtwrapper-mod 1.21.1 1.15.5 Yarn 1.21.1+build.3 21
mods/opmod-example 26.3 1.15.5 none (unobfuscated) 25
mods/TEMPLATE-MOD 26.1.2 1.16-SNAPSHOT none (unobfuscated) 25
examples/itemExampleMod 26.1.2 1.15.5 none (unobfuscated) 25

Key rules that follow from this:

Important

MC 26.1+ ships unobfuscated. For those targets:

  • there is no mappings dependency — Mojang no longer publishes mappings for 26.x;
  • fabric.loom.disableObfuscation=true is set in gradle.properties;
  • dependencies use plain implementation / compileOnly — the mod* configurations are never created when obfuscation is disabled.

mods/opmod-example is the reference implementation of this pattern.

Caution

Fabric publishes Loom per-patch only: 1.17.21, 1.18.2, … A bare 1.17 does not exist on maven.fabricmc.net and fails with "Plugin … was not found". See §18.2.

4.4 JVM memory settings

The root gradle.properties sets the daemon args for the whole multi-project build (subproject-local gradle.properties jvmargs only apply when that subproject is built as its own root):

org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=1g
org.gradle.parallel=true
org.gradle.caching=true

History: 512 MiB (Gradle default) used to OOM once several Loom subprojects ran remapJar in one daemon; 4G is the conservative fix. On small machines, override on the CLI instead of editing the file (see §2.1).

4.5 Task reference

Aggregates

Task Description
buildAll builds every Fabric subproject, then runs zipPacks
lint aggregate lint across subprojects
build (root) mergeDatapacks → copies output to build/dist/
check (root) runs verifyMod

Pack tooling

Task Flags Description
checkPacks -PcheckPacksReport=<path> writes JSON summary validates pack.mcmeta, JSON files and cross-references for every pack
zipPacks -PconfirmZip=yes (required in CI) packages each pack into build/packs-dist/; fails on missing _vc_origin watermark
mergeDatapacks -PmergeManifest=<path>, -PmergeReport=<path> merges packs listed in packs/merge-manifest.json into one datapack — see §14
printPackList / printPackFormats — inventory of packs and their formats
printModList / printModVersions — inventory of mods and MC/Loom/loader versions

Watermarks & verification

Task Description
showOriginWatermarks prints every _vc_origin.mcfunction found
checkOriginWatermarks fails if a pack lacks its watermark (also detects missing ones)
cleanOriginWatermarks exists but is disabled
verifyMod fabric.mod.json required fields, duplicate mod ids, entrypoint/mixin source existence, mavenLocal() smell

Lifecycle

Task Notes
clean extended to also wipe build/packs-dist, build/packs-remap, build/merged-datapack(.zip), build/dist

Note

The root build.gradle is deliberately Gradle-10-ready: every task action captures configuration-time values into locals instead of touching the Project API at execution time.


5 · CI and DevContainer

5.1 Workflows overview

Workflow Trigger Job
build.yml push / PR to main·master, manual build all subprojects, lint, artifacts, release packs
datapack-immutability.yml PR to main block edits to locked packs
codeowners-sync.yml repo metadata events keep .github/CODEOWNERS aligned
get-source-code.yml manual source snapshot helper
test-guigenmc.yml push / PR unit-test the guigenmc generator

All workflows cancel superseded runs on the same ref (concurrency: cancel-in-progress: true).

5.2 build.yml — Build & Lint

sequenceDiagram
    participant G as GitHub runner
    participant J as JDK 25 (temurin)
    participant W as ./gradlew
    G->>J: actions/setup-java@v5
    G->>W: buildAll -PconfirmZip=yes
    W-->>G: subproject JARs + packs-dist zips
    G->>W: root build (mergeDatapacks → build/dist/)
    G->>G: upload-artifact (if: always())
    G->>G: release-packs job (needs: build)
Loading

Notable engineering decisions (documented inline in the workflow):

  • -PconfirmZip=yes — zipPacks refuses to run without explicit confirmation; this flag is the sanctioned non-interactive path for CI.
  • The root build task runs in addition to buildAll, because buildAll historically never invoked mergeDatapacks (they are independent aggregates). Without this the merged datapack never reached artifacts.
  • Artifacts upload with if: always() so partial outputs remain inspectable on failure; release-packs uses needs: build and is skipped on genuine failure.

5.3 datapack-immutability.yml — locked packs

Blocks PRs that modify files under packs/<name>/ when that pack is "locked": true in packs/.datapack-lock.json on the base branch.

Security properties, by design:

  • No pull_request_target — read-only diff check, no secrets, no elevated base-branch token against untrusted PR content.
  • Both the lock file and the checker script are loaded from the base branch, so a PR cannot unlock a pack or neuter the checker in the same change.
  • No paths: filter — as a required status check it must report on every PR, otherwise path-filtered silence would block merges. The diff step itself handles "nothing changed under packs/".

Editing a locked pack anyway → §16.3.

5.4 Supporting workflows

  • codeowners-sync.yml — regenerates .github/CODEOWNERS from a canonical mapping so review routing never drifts from directory ownership.
  • test-guigenmc.yml — installs scripts/gui_generator and runs its test suite, guarding the guigenmc generator.
  • get-source-code.yml — utility workflow producing a source snapshot.

5.5 Devcontainer

.devcontainer/devcontainer.json:

{
  "name": "vortacraftmc-core",
  "features": {
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/devcontainers/features/common-utils:2": {
      "configureZshAsDefaultShell": true
    }
  },
  "postCreateCommand": "bash setup.sh",   // provisions the toolchain
  "postStartCommand": "bash start.sh",
  "customizations": { "vscode": { "extensions": [
    "misode.vscode-datapack-helper",
    "SPGoding.datapack-language-server",
    "redhat.java", "vscjava.vscode-java-pack",
    "vscjava.vscode-gradle"
  ]}}
}

Works with VS Code Remote-Containers and GitHub Codespaces. After create, ./gradlew buildAll is all you need. The datapack-language-server extension gives completion/diagnostics for mcfunction, SNBT and pack.mcmeta.

5.6 Issue templates

Template Use for
bug_report_mod.yml Fabric mod defects (mods/)
bug_report_pack.yml Datapack/resource-pack defects (packs/)
feature_request.yml New features (remember: packs are in maintenance mode — expect mod suggestions)
security_report.yml Pointer to private vulnerability reporting — see §17

6 · macroEngine (framework datapack)

macroEngine is a macro/module framework datapack for Minecraft Java Edition: a large library of reusable command-based systems — math, string, NBT, geo, permissions, UUID cache, hooks, rate limiting and more — plus a multi-source text/value input system (dialogs, writable books, signs, lecterns, name tags, command-block minecarts).

Owner: runtoolkit (original) · Maintainer: vortacraftmc · License: Unlicense · Namespace: macroengine

Build Minecraft Pack format Status
macroEngine-Datapack-v26.4 26.4-snapshot-1 [122, 0] ✅ current
macroEngine-Datapack-v26.3 26.3 121 🗄️ archived — see §6.14

Scale of the pack (v26.4): 1,533 files, of which ~1,000 are mcfunction files — core/ 558 · api/ 220 · systems/ 157 · input/ 36 · experimental/ 16 · events/ 11.

6.1 Installation

  1. Drop the datapack folder into your world's datapacks/ directory (or add it as a server-side pack source).
  2. Install the companion resource pack — without it, messages fall back to raw translation keys and players get a recurring join warning.
  3. /reload or restart. macroEngine initialises automatically via #macroengine:events/on_load.

Server-side enforcement (recommended):

# server.properties
require-resource-pack=true
resource-pack=<url to macroEngine-Resourcepack-v26.4.zip>
resource-pack-prompt=macroEngine resource pack is required

Default tick configuration lives in data/macroengine/function/config/ (see §6.13).

6.2 Architecture

flowchart TB
    subgraph public["api/ — stable public entry points (220 functions)"]
        api[cmd · cb · dialog · perm · title\ninteraction · item · macro · toggle\ntrigger · wand · color · gamerule]
    end
    subgraph internal["systems/ — internal modules (157 functions)"]
        sys[math · string · nbt · logic · geo · flag\nhook · log · rate_limit · sound · uuid · color · trim]
    end
    subgraph io["input/ — player value capture (36 functions)"]
        inp[book · sign · lectern · name tag\ndialog · anvil · command-block minecart\n+ input/validate]
    end
    subgraph triggers["event sources"]
        adv["advancement/ (core · hidden · systems)"] --> hook
        tags["function tags\n#macroengine:events/on_load · loop"] --> core["core/ (558 functions)"]
    end
    api --> sys
    api --> io
    hook[systems/hook] --> sys
    exp["experimental/ (16 functions)\ngated by toggle/experimental"] --> sys
    core --> api
Loading

Content registries shipped by the pack: advancement/, damage_type/, dialog/, enchantment/, function/, item_modifier/, loot_table/, predicate/, recipe/, tags/, trim_material/, trim_pattern/.

Lifecycle function tags (tags/function/events/): on_load · on_join · on_death · on_respawn · on_jump · on_lc (left click) · on_rc (right click) · on_enchant · on_open_gui.

6.3 API layer (api/)

Stable public entry points. Anything under systems/ may change without notice; the API surface is what pack authors should call.

api/cmd — command wrappers (~105 functions)

Typed wrappers around vanilla commands, grouped by domain:

Domain Wrappers
Chat & titles actionbar, msg, msg_raw, title, title_all, title_bold, title_sub, title_times, title_clear, title_reset, subtitle
Teleport & movement tp, tp_facing, tp_to_coords, tp_to_entity, tp_to_player, spreadplayers, spectate, spectate_stop, ride, ride_dismount
Items & inventory give, give_one, clear, clear_item, item_modify, item_rename, loot_drop, loot_give
Entities & effects summon, kill, damage, damage_typed, heal, effect_give, effect_give_all, effect_clear, effect_clear_one, enchant, freeze, unfreeze, swing
World setblock, fill, clone, clone_masked, place_feature, place_structure, locate_structure, forceload_add, forceload_remove, time_set, time_add, time_of, weather, particle
Scoreboard & storage scoreboard_add, scoreboard_get, scoreboard_set, storage_set, data_remove_block, data_remove_entity, data_remove_storage, trigger_set
Advancements advancement_check, advancement_grant, advancement_revoke
Attributes attribute_get, attribute_set, attribute_add_modifier, attribute_get_modifier, attribute_remove_modifier
Boss bars bossbar_add, bossbar_remove, bossbar_set_max, bossbar_set_players, bossbar_set_value
Players & admin op, deop, ban, ban_ip, kick, whitelist, gamemode, gamerule, difficulty, xp_add, xp_get, xp_set, tag_add, tag_remove, publish, datapack, console_say, console_me, display_name, as_player
Sound sound, sound_all, stopsound
Dispatch helpers function, execute_if_pred, run_with_cb, run_cb_reset, set_clock_rate, disable

api/cb — callback queue

Schedule work to run later: run · run_delayed · run_sequence · cancel · list · queue_size.

api/perm — permissions

grant · revoke · has · check · exec · run · list · clear · trigger/ (permission-aware /trigger handling).

api/wand — editor wand

give · give_custom · give_lore · register · register_cmd · register_fn · unregister · unregister_all · has · list · cooldown_set · cooldown_check.

api/dialog — dialog UI

show · open · show_dialog_exec · notify_admins — backed by dialog/input_prompt.json.

api/interaction — interaction entities

spawn · bind_attack · bind_use · unbind_attack · unbind_use · remove · list.

api/item — item utilities

combo_marker · durability_overlay · hidden_flag · owner_tag · use_cooldown · use_cooldown_check.

api/trigger — /trigger plumbing

bind · bind_cmd · enable · disable · unbind · unbind_all · list.

api/color — colour resolution

resolve · validate · lerp · from_score · palette API (palette_set/get/list/delete) · gradient API (gradient_set/delete).

api/title / api/gamerule / api/macro / api/toggle

6.4 Systems layer (systems/)

Internal utility modules used by the API layer (advanced integrations may call them directly).

systems/math

abs · atan2 · average · ceil_div · clamp · cos · distance2d · distance3d · divmod · factorial · gcd · is_between · lcm · lerp · lerp_clamped · log2 · map · max · min · minmax · …

systems/string

announce · announce_prefix · format_coords · format_number · format_ticks · header · hover_text · ordinal · pad_left · player_raw · …

systems/nbt

append · clear · copy · count · exists · first · merge · move · pop · swap

systems/geo

in_region · in_region_unless · in_sphere · near_entity · near_entity_unless · as_nearby_player · region_watch/

systems/uuid — UUID cache

store · recall · recall_array · from_entity · from_array · match · has · forget · cache_clear

systems/flag

set · set_if · get · get_or_default · unset · clear · copy · any · toggle · list · list_systems · toggle_system — boolean flags in storage, plus per-system toggles.

systems/logic

if_eq · if_not_eq · if_gt · if_gte · if_lt · if_lte · if_and · if_or

systems/log

Levelled logging: debug · info · warn · error · add · show · clear · set_level · get_level

systems/sound

play · play_at · stop — uses the sounds from the resource pack.

systems/hook, systems/rate_limit, systems/color, systems/trim

Dedicated sections: §6.6 · §6.7 · §6.12.

6.5 Input system (input/)

Capture player-provided values through whichever UI fits the situation — all sources normalise into one pipeline with shared validation (input/validate/check) for int / float / bool / tag-safe strings.

Source Entry points
✍️ Writable book input/writable_book, input/give_writable_book
🪧 Sign input/sign
📖 Lectern input/lectern
🏷️ Name tag input/name_tag, input/give_name_tag
💬 Dialog input/dialog
⚒️ Anvil input/anvil, input/give_anvil, input/give_anvil_custom
🚃 Command-block minecart input/command_block_minecart, input/summon_cbm

6.6 Hook system (systems/hook)

Bind arbitrary functions to gameplay events. Bindings live in storage; use bind / unbind / unbind_all / list, plus raycast/ helpers.

Fired events (on_*):

Category Events
Blocks on_break_block, on_placed_block
Movement on_dimension_change, on_jump
Combat on_entity_kill, on_killed_by_arrow, on_target_hit
Interaction on_item_use, on_using_item, on_interact_anvil, on_interact_shulker_box, on_open_chest, on_drop, on_trade
Misc on_eat, on_fish_caught, on_hero_of_the_village, on_advancement_fire

Advancement-driven hooks live under advancement/systems/hook/ (break_block, dimension_change, eat_food, entity_kill, fish_caught, hero_of_the_village, interact_anvil, interact_shulker_box, item_use, killed_by_arrow, placed_block, trade), while advancement/core/internal/player/ contains ~30 interaction advancements (anvil, barrel, beacon, blast furnace, brewing stand, cake, campfire, cartography table, cauldron, chest, crafting table, dispenser, dropper, ender chest, flower pot, furnace, grindstone, hopper, jukebox, lectern, loom, noteblock, shulker box, smithing table, smoker, stonecutter, trapped chest, vault, click/attack entity).

# bind a handler to an event, then let the engine fire it
data modify storage macroengine:input event set value "macroengine:trim_matched"
data modify storage macroengine:input func  set value "macroengine:systems/trim/on_matched_example"
function macroengine:systems/hook/bind with storage macroengine:input

6.7 Rate limiting

systems/rate_limit throttles requests with sliding windows at three scopes. Rules live in macroengine:engine storage and survive reloads.

Scope Key convention Guards against
Global global:<name> whole-server floods
Per-player player:<name>:<player> one player spamming
Per-channel channel:<id> one tick system starving others

Register/update a rule (macro function):

function macroengine:systems/rate_limit/config {key:"global:my_event",limit:5,window:100}
function macroengine:systems/rate_limit/config {key:"player:shop:$(player)",limit:3,window:600}
function macroengine:systems/rate_limit/config {key:"channel:admin_systems",limit:10,window:20}

Fields: key (unique rule id), limit (max hits inside the window), window (sliding window width in ticks — 20 = 1 second). Manage with rate_limit/check, rate_limit/delete {key:"..."} and rate_limit/list.

This is one of the features that illustrate why datapacks are "hard to scale" (see §19): a few dozen lines of Java equivalent becomes hundreds of lines of mcfunction here.

6.8 Toggle system

Runtime enable/disable per module — api/toggle/<module>/true|false, inspect with api/toggle/list and api/toggle/show.

Toggleable modules: cb · perm · geo · wand · interaction · hook · experimental.

6.9 Permissions (api/perm)

Storage-backed permission model: grant / revoke mutate, has / check test (silent vs messaging), exec / run gate function execution on a permission, list / clear inspect/reset, and trigger/ wraps permission-aware /trigger flows.

6.10 Macros (api/macro)

Dispatch helpers that build macro ($(param)) calls from different value sources — the heart of the framework's name:

with_advancement · with_function · with_predicate · with_score · with_tag

6.11 Enchantments & damage types

Custom enchantments (enchantment/):

Enchantment Effect
steady_hand utility
xp_thrift XP economy
momentum_surge movement speed on boots
overload_ward protects against macroEngine's own damage types

Custom damage types: overload, purge, sanctioned — grouped under #macroengine:core in tags/damage_type/. overload_ward exists specifically so players can be shielded from the engine's own sanction mechanics. Enchanted books are craftable (recipe/momentum_surge_book.json, recipe/overload_ward_book.json).

6.12 Armor trims

(v26.4+) A fully custom trim pipeline:

  • trim_pattern/macroengine:circuit — custom pattern
  • trim_material/macroengine:overload — custom material
  • 1.21.5+ registry shape: no template_item/ingredient, only override_armor_assets
  • Apply with any vanilla smithing template + the crafted ingot (recipe/util/overload_trim_ingot.json, pattern recipe recipe/circuit_armor_trim.json)
  • Matching assets (overlay textures, colour palette, armor_trims.json atlas extension via replace:false) ship in the companion resource pack
  • Processing: systems/trim/ scans an entity's armor for the circuit+overload combination and fires a macroengine:trim_matched hook event per matching slot; on_matched_example.mcfunction is a bindable handler example.

6.13 Configuration

  • config/tick_cfg.mcfunction — idempotent tick defaults (only sets keys that are missing; safe to re-run on /reload). Score keys under #vortacraftmc.packs.macroengine.config.tick.* on the macroengine.meta scoreboard:
    • tick.rate — ticks between dispatch runs (default 1 = every tick)
    • tick.pause — 0 running / 1 paused
    • System dispatch is fixed-rate with 5 systems (time / player / queue / hud / admin), toggled via systems/flag/toggle_system — the old dynamic channel registry (tick.max_channels) was removed.
    • Policy note: tick config changes are reviewed via PR and checked by CI; runtime macro key generation is not allowed in this file.
  • setup.mcfunction / disable.mcfunction — install/removal entry points
  • core/ — internal engine (558 functions): loader, tick dispatch, unsupported gate
  • player/, world/ — per-player and per-world state

6.14 The v26.3 unsupported gate

Warning

v26.3 is archived. On every /reload it prints an unsupported warning, and the internal engine (macro:input / macro:output / macro:engine) will not initialize unless you explicitly opt in:

/data modify storage macroengine:engine config.allow_unsupported_load set value 1b

Static content (recipes, loot tables, advancements, predicates, item modifiers, enchantments) is unaffected either way. See core/internal/load/unsupported_gate.mcfunction. Development continues in v26.4 — a separate, supported pack.

6.15 Bundled content registries (detail)

  • item_modifier/ (23): breakable, custom_model_data_clear, damage_random, enchant_randomly, enchant_with_levels_5/30, glint_add/remove, hide_tooltip(_reset), lore_add_custom, lore_clear, name_reset, provide_overload_trim, rename_to_custom, repair_full, set_count_1/16/64, set_custom_model_data, strip_enchants, unbreakable, plus input/
  • predicate/ (30+): state predicates such as is_sneaking, is_sprinting, is_swimming, is_gliding, is_flying, is_burning, is_freezing, is_hungry, is_full_health, is_baby, is_daytime, is_raining, is_thundering, weather_clear, in_overworld/nether/end, in_desert_biome, in_ocean_biome, in_the_end_highlands, is_creative, is_survival, is_on_ground, is_in_water, is_holding_bow/shield/sword/trident, has_empty_mainhand/offhand, health_below_half, near_village_structure, plus core/
  • loot_table/: player/, util/
  • recipe/: circuit_armor_trim, momentum_surge_book, overload_ward_book, util/
  • dialog/: input_prompt.json

6.16 Experimental features

Gated behind api/toggle/experimental/true. Not guaranteed stable between versions. Currently included (16 functions):

Module Idea
combat_tag combat tagging
crafting_ui crafted-UI experiments
hologram hologram helpers
particle_trail particle trails
scoreboard_hud scoreboard HUD
waypoint waypoints

6.17 Cookbook

Schedule a delayed callback
function macroengine:api/cb/run_delayed   # queue a function to run later
function macroengine:api/cb/list          # inspect what's queued
Gate an action on a permission
function macroengine:api/perm/grant   # once, for the target player
function macroengine:api/perm/exec    # run gated work
Ask the player for a value (sign input + validation)
function macroengine:input/sign       # open the capture surface
function macroengine:input/validate/check  # validate before use
React to block breaks
data modify storage macroengine:input event set value "macroengine:on_break_block"
data modify storage macroengine:input func  set value "mypack:handlers/on_break"
function macroengine:systems/hook/bind with storage macroengine:input
Throttle a player-facing action
function macroengine:systems/rate_limit/config {key:"player:shop:$(player)",limit:3,window:600}
function macroengine:systems/rate_limit/check  # fails the caller when over limit

7 · macroEngine Resource Pack

Important

This resource pack is REQUIRED for macroEngine (datapack). All user-facing tellraw/title messages use translation keys in the macroengine.* namespace, and the custom sounds, death messages and trim visuals live here.

v26.4 v26.3
Folder macroEngine-Resourcepack-v26.4 macroEngine-Resourcepack-v26.3
Pack format [98, 0] v26.3-era
Status ✅ current 🗄️ archived with its datapack

pack.mcmeta description says it plainly: "macroEngine | 26.4-snapshot-1 — resource pack (REQUIRED: i18n, sounds, trim assets)".

7.1 What's inside

assets/macroengine/
├── lang/                 localized language files (macroengine.* keys)
├── sounds/               custom sound files
├── sounds.json           sound registry
└── textures/
    ├── palettes/trim/    trim colour palettes
    └── trims/entity/     armor trim overlays
        ├── humanoid/
        └── humanoid_leggings/

Plus pack.mcmeta and pack.png at the root.

7.2 Localization (i18n)

macroEngine never hard-codes chat text — every message is a macroengine.* translation key served from the lang/ files. Players see messages in their client language; other languages fall back per the rules below.

7.3 Installing

Players: place the zip (or folder) in resourcepacks/ and enable it in Options → Resource Packs.

Servers (recommended — force the pack):

# server.properties
require-resource-pack=true
resource-pack=<url to macroEngine-Resourcepack-v26.4.zip>
resource-pack-prompt=macroEngine resource pack is required

Alternatives: ship it as a world resource pack, or host the zip and let players opt in.

7.4 Without the resource pack

Feature Behaviour without the pack
tellraw / title messages raw translation keys, or English defaults where fallback is used
Custom sounds silent / vanilla fallback
Death messages raw keys
Trim visuals vanilla trims only
Join experience recurring warning on join

8 · Fabric Mods

Everything under mods/ is a Fabric mod built through the shared root Gradle build (./gradlew buildAll) — except datapack-fixer, which keeps its own standalone build. See §4.3 for the version matrix.

Mod Mod id MC Java What it does
datapack-blocker datapack-blocker 1.21.1 21 locks the world's datapacks/ folder; quarantines newcomers
datapack-fixer datapack_fixer 1.21.4 21 server-safe datapack syntax diagnostics + repairs
rtwrapper-mod rtwrapper 1.21.1 21 Fabric successor of the RTWrapper datapack
opmod-example levelop 26.3 25 /op <targets> <level> — permission-level aware op
TEMPLATE-MOD (template) 26.1.2 25 copy-paste starting point for new mods

8.1 datapack-blocker

📁 mods/datapack-blocker · MC 1.21.1 · Loom 1.15.5 · Yarn 1.21.1+build.3 · Java 21

Locks a world's datapacks/ folder instead of leaving it open to arbitrary drop-in changes.

Lifecycle:

  1. First run on a world — every top-level entry in datapacks/ (folder or .zip) is recorded as that world's allowlist. Nothing is blocked yet.
  2. Every run after — the folder is compared against the allowlist:
    • anything not allowlisted is moved to <world>/datapack_blocker/quarantine/<timestamp>/ (never deleted);
    • everything allowlisted has write permission stripped recursively.

Commands — all under /datapackblocker, op-only (permission level 4):

Command Effect
status list what's currently in quarantine
approve <name> move a quarantined pack back, allowlist it, lock it (then /reload)
unlock temporarily restore write access for maintenance
lock re-lock after maintenance

Scope and limitations — this is a tripwire for the common case (new pack dropped in, server restarts), not a hard security boundary:

  • enforcement runs at server start; a pack picked up by a live /reload mid-session is not caught until the next restart;
  • "read-only" is best-effort via File#setWritable — POSIX strips the directory write bit, Windows maps to the read-only attribute;
  • comparison is by name only, not content hashing — a pack edited before the mod's first run gets allowlisted as-is;
  • anyone with shell access to the host is out of scope by definition.

Why it exists: it complements the packs/ maintenance-mode policy — servers that want to keep running existing datapacks but stop accepting new ones without review get that boundary enforced automatically instead of relying on an operator remembering to check the folder by hand.

8.2 datapack-fixer

📁 mods/datapack-fixer · MC 1.21.4 · Loader ≥ 0.19.3 · Fabric API 0.119.4+1.21.4 · Java 21 · ⚠️ excluded from the shared Gradle build — has its own wrapper, GameTests and CI

A server-safe diagnostic mod for datapack syntax migration. It does not intercept datapack loading, patch packets, or change gameplay. On startup it reads unpacked datapacks and emits diagnostics to the log; the only file writes are the explicit operator-triggered repair, which always backs up first.

Supported diagnostics (deliberately narrow, syntax-oriented):

  • malformed JSON;
  • unbalanced quote / SNBT / item-component delimiters in .mcfunction;
  • legacy plural data directories from before 1.21;
  • minecraft:type_specific/slime → minecraft:type_specific/cube_mob (26.2);
  • minecraft:alternative → minecraft:any_of;
  • likely pre-1.21.2 recipe ingredient object syntax.

Commands (op-only, permission level 4):

/datapackfixer scan   # diagnostics only
/datapackfixer fix    # repair + automatic backup
/reload

Repairs and backups (v1.2.0): before any change, fix copies every directory datapack to world/datapack_fixer_backups/<UTC timestamp>/ and writes an audit.txt report there. It never processes ZIP/JAR datapacks. The repair allowlist covers only deterministic transformations — singular data directory names, the slime/alternative renames, and a missing 1.21.4 pack_format in otherwise valid pack.mcmeta. Invalid JSON, ambiguous recipe conversions, legacy NBT/item-component rewrites and gameplay-semantic migrations are reported but deliberately not rewritten.

Multiplayer safety: no mixins, no packets, no reload hooks, no client entrypoints. Scanning is bounded to files < 2 MB. No automatic pack.mcmeta format conversion — changing a compatibility declaration is not a syntax-only repair.

26.2 migration policy: the runnable artifact is pinned to 1.21.4 because the 26.2 official Minecraft mappings were not resolvable by Loom in this build environment. A future 26.2 release must update Minecraft, mappings, Fabric API and test APIs together after official artifacts are available.

Build & test (standalone):

cd mods/datapack-fixer
./gradlew build                      # JUnit + Fabric server GameTests
./gradlew runClientGameTest
./gradlew runProductionClientGameTest

8.3 rtwrapper-mod

📁 mods/rtwrapper-mod · MC 1.21.1 · Loom 1.15.5 · Yarn 1.21.1+build.3 · Java 21

The Fabric successor of the archived RTWrapper datapack. Same mission — execute commands described as data — implemented as a proper mod instead of a command-block pipeline. The datapack API/storage protocol is documented in packs/RTWrapper/docs/API.md (storage rtwrapper:api request + named parameters, immediate run vs queued enqueue).

8.4 opmod-example (LevelOp)

📁 mods/opmod-example · MC 26.3 · Loom 1.15.5 · no mappings (unobfuscated) · Java 25

Extends vanilla /op with an explicit permission level:

Command Behaviour
/op <targets> unchanged vanilla (level from op-permission-level)
/op <targets> <level> new — grants op at level 1–4 regardless of server default

Both require permission level 3, same as vanilla.

Tip

This subproject is the repo's reference implementation for MC 26.x mods: Loom pinned to 1.15.5, fabric.loom.disableObfuscation=true, and plain implementation dependencies (the mod* configurations don't exist with obfuscation disabled). Its README also documents what to do if a future MC drop needs a newer Loom than the rest of the monorepo — bump this subproject's plugin version independently.

8.5 TEMPLATE-MOD

📁 mods/TEMPLATE-MOD · MC 26.1.2 · Loom 1.16-SNAPSHOT · Java 25

Copy-paste starting point for new mods targeting MC 26.x:

  • splitEnvironmentSourceSets() — separate main and client source sets
  • named mod registration (template-mod) wiring both source sets
  • no mappings dependency (unobfuscated target)

8.6 verifyMod checks

./gradlew verifyMod (also part of root check) validates every fabric.mod.json under mods/ and examples/ (skipping the two settings-excluded dirs):

  • ✅ required fields present (schemaVersion, id, version, name);
  • ✅ duplicate mod id detection;
  • ⚠️ entrypoint classes exist as source files (warning);
  • ⚠️ declared mixin configs exist (warning);
  • ⚠️ root build.gradle doesn't use mavenLocal() (reproducibility smell).

Hard failure only on real errors (invalid JSON / missing required fields).


9 · GUIKit — in-game GUI editor

📁 packs/guikit-datapack · MC Java 26.3 (min_format/max_format 121) · 🔒 locked in CI

Menus are built in the world, not by writing .mcfunction files. A chest minecart is the screen. Left-click is the click. Definitions live in storage guikit:lib (saved with the world) and survive /reload.

Companions: demo pack packs/guikit-demo and the standalone JSON→GUI generator guigenmc.

9.1 What's new in v5

  • /trigger guikit.last — reopens the most recent menu you opened (survives /reload; auto-cleared if that menu is deleted).
  • /trigger guikit.close — closes your own open menu immediately (no op, no waiting for timeout). Map makers also get function guikit:api/close_all.
  • Two new guikit:cond button conditions: dimension and weather.

The cart / click / redraw engine underneath is the classic guikit runtime; authoring moved off the old #guikit:fill / #guikit:probe framework into the editor.

9.2 Install & play

Install: drop the pack in datapacks/, /reload. On first load it seeds a published Welcome menu so there's something to open.

Anyone (no operator permission):

/trigger guikit.open     # opens the list of PUBLISHED menus
/trigger guikit.last     # reopen your most recent menu
/trigger guikit.close    # close your own open menu now

Joining players are told about guikit.open once. guikit.last remembers the last menu opened through the list, a “go to another menu” button, or a preview.

9.3 Editing (operators)

/function requires permission level 2, so the editor is operator-only:

/function guikit:editor/open
/function guikit:help
  1. Menu list — emerald creates a menu, a book opens it.
  2. Editor chest — slots 0–25 are the menu. The bottom-right book is Tools (not part of the menu). Slot 26 of a 27-slot menu is edited via Tools → Edit slot 26.
  3. Hold the desired icon item, left-click a slot, pick an action in the dialog.
  4. Tools: pages, rename, container, timeout, publish/hide, preview, delete.

Preview runs the real menu; chat suggests /function guikit:editor/resume to return to the editor.

9.4 Click actions

Action Effect
Decoration icon only, not clickable
Give held item gives that item; optional fixed cost (diamond / emerald / gold / iron)
Message plain tellraw (interpret:false)
Close closes the menu
Go to page pages 0–8
Open another menu picker, no typed ids
Toggle per-player on/off, gray dye when off
Counter +1 per-player score, clamped, value printed in chat
Sound one of six built-in sounds, only the clicking player hears it
Web link clickable https link in chat; menu closes so chat is visible
Command stored command — see §9.7

9.5 Click rules

Set on the slot dialog after the action is placed; a button can carry more than one rule. Keep leaves a rule unchanged.

Rule Behaviour
Confirm second click within 2 seconds
Cooldown per-player 3 / 10 / 30 s (barrier icon while running)
Required tag vip / member / staff — granted by an operator via /tag <player> add vip (tags are never typed by players)

9.6 Button conditions (guikit:cond)

Hand-written button packs (storage guikit:btn defs) can gate a button on a condition. function guikit:cond/check reads storage guikit:cond and sets #cond guikit.tmp:

Type Keys Passes when
score obj, [min], [max] player's score is in range (unset = fail)
item_count item, [min] player carries at least min of the item (default 1)
tag tag player has the tag
dimension (v5) dimension id player is in that dimension
weather (v5) weather state current weather matches

9.7 Trust model & storage

Caution

A Command widget runs at datapack function permission (default 2), as the clicking player, for any player who can open the menu — the same trust as a command block behind a button. Do not put player-typed text in it. The command dialog rejects nothing by itself: avoid apostrophes (') in commands, or the save line will not parse.

Storage map (all world-persistent):

Storage Purpose
storage guikit:lib menu definitions + order (/data get storage guikit:lib; never data remove it — menus re-register from it via guikit:runtime/register)
storage guikit:mem small per-player memories, e.g. last.m<pid> for guikit.last
storage guikit:ed per-player editor state (p<pid>), survives close so dialogs can resume the editor
storage guikit:btn hand-written button packs (defs)
storage guikit:cond condition inputs for guikit:cond/check

Generated menu ids are visible in /data get storage guikit:lib order (e.g. m1).


10 · Utility Packs

Small, single-purpose datapacks targeting modern Minecraft (min_format/max_format [122, 1]). All are locked in CI and maintained in lock-protocol mode: bug fixes and compatibility only.

Copyright (c) 2026 Runtoolkit · MIT licensed (see each pack's LICENSE/NOTICE) · each pack carries its _vc_origin.mcfunction provenance watermark.

10.1 BorderPing

📁 packs/BorderPing · "warns players approaching the world border" · namespace borderping

Tiny tick-driven proximity detector for the world border:

data/borderping/function/
├── _vc_origin.mcfunction   # provenance watermark
├── load.mcfunction         # #minecraft:load
├── tick.mcfunction         # #minecraft:tick
└── warn.mcfunction         # proximity warning

No commands, no configuration — it hooks #minecraft:load and #minecraft:tick via the vanilla tags in data/minecraft/tags/.

10.2 DailyBonus

📁 packs/DailyBonus · "once-per-in-game-day login reward" · namespace dailybonus

Grants players a reward once per in-game day, driven by a loot table so server owners can re-roll the reward pool without touching functions: load.mcfunction · tick.mcfunction · grant.mcfunction + loot_table/.

10.3 QuickShare

📁 packs/QuickShare · "per-player item sharing helper" · namespace quickshare

Per-player item sharing between players, wired through #minecraft:load/#minecraft:tick function tags.


11 · Archived Datapacks

Warning

The packs in this section are archived: existing worlds keep working, but no new features or fixes are planned. The repo's direction is Fabric mods — see §19.1.

11.1 TunnelScript

📁 packs/TunnelScript · MC 1.19.2 (pack_format 10) · namespace ts · ships its own CHANGELOG.md, CONTRIBUTING.md, SECURITY.md

A small command-running library: instead of copy-pasting execute/function boilerplate, you hand TunnelScript a command (or a batch) and it runs them with:

  • ✅ permission gating
  • ✅ confirmation step for dangerous actions
  • ✅ safety rails: cooldowns, action cap, dry-run preview

Because 1.19.2 predates function macros (1.20.2+), there is no dynamic $function $(...) dispatch — commands are captured and run through a command-block-based runner.

Quick start: install → /reload → /function ts:version → /function ts:help.

11.2 cmdTunnel-datapack

📁 packs/cmdTunnel-datapack

Executes commands stored in storage using a temporary command-block pipeline: storage-driven execution, function-tag dispatch hooks, lightweight and fully datapack-based, designed for advanced automation. Requires operator permissions and enable-command-block=true.

11.3 inv_gui

📁 packs/inv_gui · MC 1.20.3–1.20.4 (pack_format 26) · CC0-1.0 · v1.0.0

Inventory-based GUI menu library: 27-slot menus (Chest Minecart or Ender Chest), button / normal / variable item types, click & drop event detection, listener-based callbacks, mid-session menu swap (set_menu), plus util/map + util/array helpers.

Caution

Licensing caveat: inv_gui entered the monorepo as a renamed fork of rarula/Sketch whose licensing relative to upstream was never cleared. Use is not recommended until that is resolved; it is kept for reference and possible reimplementation only. 1.21+ support was planned via the overlay system but never shipped.

11.4 LeftClickDetection

📁 packs/LeftClickDetection · MC 1.20.3+ · namespace left_click_detection

function left_click_detection:api/enable    # enable for the executing player

11.5 InteractionClickDetection

📁 packs/InteractionClickDetection · MC 1.20+

Lightweight, macro-free click detection on minecraft:interaction entities using vanilla advancements:

  • ✅ left click (player_hurt_entity)
  • ✅ right click (player_interacted_with_entity)
  • ✅ no macros, very lightweight (advancements + tag functions)
  • ✅ easy to embed into other datapacks; multiplayer-safe

11.6 RTWrapper family

Three historical snapshots of RTWrapper ("Runtoolkit Wrapper") — execute commands described as data:

Folder Era Notes
packs/RTWrapper MC 26.3 datapack + rtwrapper-fabric/ (excluded from the build) + docs/API.md
packs/RTWrapper-1.21.1 MC 1.21.1 versioned snapshot
packs/RTWrapper-v1.0.1 v1.0.1 versioned snapshot

Datapack API (26.3 build)

Namespace rtwrapper; immediate execution uses storage rtwrapper:api request + rtwrapper:api/run:

# /tp @s 0 80 0 immediately
data modify storage rtwrapper:api request set value \
  {cmd:"tp",params:{target:"@s",x:"0",y:"80",z:"0"}}
function rtwrapper:api/run

# queued / autotick execution instead
data modify storage rtwrapper:api request set value \
  {cmd:"say",params:{message:"queued hello"}}
function rtwrapper:api/enqueue
  • type is accepted as an alias for cmd.
  • Generated wrappers use meaningful command-specific parameter names (no $(tail) catch-all); parameter order is recorded per command in datapack/commands-26.3.json under command_params — e.g. tp → [target, x, y, z, rotation, facing_mode, facing_target, facing_anchor].
  • The dispatcher calls the exact <command>_<N> variant and doesn't append unused params.

Successor: mods/rtwrapper-mod — the same idea as a Fabric mod; packs/RTWrapper/rtwrapper-fabric is kept only for historical reference and excluded from the Gradle build.


12 · Examples

12.1 itemExampleMod

📁 examples/itemExampleMod · MC 26.1.2 · Loader ≥ 0.18.4 · Fabric API 0.148.2+26.1.2 · Loom 1.15.5 · Java 25 · CC0

The runnable example Fabric mod — also the template the Fabric docs point to. Highlights:

  • splitEnvironmentSourceSets() with a named mod (customcmd) wiring main + client source sets;
  • archives name custom-cmd;
  • unobfuscated target: no mappings dependency, plain implementation dependencies;
  • ships its own wrapper, .github/ and README.md (CC0 — learn from it and incorporate it in your own projects).

Build like any subproject: ./gradlew :examples:itemExampleMod:build.

12.2 template-datapack

📁 examples/template-datapack

A minimal datapack skeleton (data/, pack.mcmeta, .gitignore, CI stubs) to copy when starting a new pack. Not covered by the same security posture as mods//packs/ — it is a starting point, not a shipped artifact.


13 · Scripts and Tools

Standalone tooling under scripts/. These are not part of the Gradle build — each has its own runtime.

Note

Per SECURITY.md: treat scripts/ as lower trust by default — review before running locally.

Tool Language Purpose
dp-depman Python 3.12+ (stdlib only) datapack dependency manager
dpgen Node.js config-driven datapack generator
guigenmc Python 3.9+ JSON → GUI datapack generator (CLI + web UI)
datapack_risk_scan.py Python 3 read-only security audit of datapacks
datapack_lock Python 3 CI checker behind .datapack-lock.json

13.1 dp-depman

📁 scripts/dp-depman

Dependency management for Minecraft Java Edition datapacks: declare dependencies in datapack_depends.json, resolve from GitHub Releases or git submodules, and produce installable ZIPs — locally or in GitHub Actions.

Requirements: Python 3.12+ (stdlib only — no pip install), Git for submodule support, and a GITHUB_TOKEN env var for Releases resolution.

// datapack_depends.json
{
  "id": "my-pack",
  "version": "1.0.0",
  "dependencies": {
    "dataLib": {
      "source": "github",
      "repo": "vortacraftmc/core",
      "version": ">=26.2.0",
      "asset": "dataLib.zip"
    }
  }
}

A lockfile (datapack_depends.lock) pins resolved versions; example-pack/ and docs/ show complete usage.

13.2 dpgen

📁 scripts/dpgen · Node.js (builder.js, schema.js, templates.js)

Config-driven datapack generator for the CLI. Point it at a YAML/JSON file describing namespaces, functions, advancements, recipes, loot tables, predicates and item modifiers — it builds a ready-to-use datapack .zip. Targets modern Minecraft (26.x, min_format/max_format pack.mcmeta).

Why not a browser generator?

  • ✅ validation before build — invalid namespaces, duplicate function paths, dangling predicate refs, inconsistent min_format/max_format fail loudly at validate/build time;
  • ✅ multiple namespaces, multiple tick/load functions — no single-function ceiling; every declared tick/load function is merged into the right tag file;
  • ✅ macro function support — generates the $(param) skeleton;
  • ✅ configs are scriptable, diffable, version-controllable.
cd scripts/dpgen
npm ci
node bin/dpgen.js build path/to/config.yaml

13.3 guigenmc

📁 scripts/gui_generator · Python 3.9+ · tested in CI by test-guigenmc.yml

JSON → Minecraft GUI datapack generator with two frontends:

  • 🖥️ CLI — generate from a config file in the terminal
  • 🌐 Web UI — visual editor in your browser

Works on Linux, macOS, GitHub Codespaces and GitHub Actions. No extra packages beyond Python 3.9+.

cd scripts/gui_generator
pip install -e .

guigenmc ui                    # visual editor (browser)
guigenmc generate my_menu.json      # from JSON
guigenmc generate my_menu.json -z   # …as a .zip

Pairs naturally with GUIKit: guigenmc produces the datapack side, guikit runs menus in-world.

13.4 datapack_risk_scan.py

📁 scripts/datapack_risk_scan.py

A read-only auditing tool for datapacks. Scans .mcfunction (and function-tag .json) files for command patterns known to cause real-world problems — server/client lag, world/data corruption, griefing potential — and produces a Markdown report with:

  • file + line number
  • the offending line
  • why it's risky
  • a concrete, safer alternative snippet you can paste in instead
python3 scripts/datapack_risk_scan.py path/to/datapack --out report.md

It never modifies, blocks or disables anything — it exists to save you reading every .mcfunction by hand before merging or trusting a third-party pack.

13.5 datapack_lock

📁 scripts/datapack_lock/check_lock.py

The checker executed by the datapack-immutability.yml workflow: loads packs/.datapack-lock.json and itself from the PR's base branch, then fails the PR if it touches files under any locked: true pack. Design rationale (no pull_request_target, no paths: filter) is documented in §5.3.


14 · Merge Manifest & mergeDatapacks

The root Gradle task mergeDatapacks fuses several datapacks into one datapack — with a gated load/tick system, a kill-switch, toggleable debug and load-error checking. Its behaviour is driven by packs/merge-manifest.json.

./gradlew mergeDatapacks                 # uses packs/merge-manifest.json
./gradlew mergeDatapacks -PmergeManifest=path/to/other.json
./gradlew mergeDatapacks -PmergeReport=build/merge-report.json
./gradlew build                          # root build = merge + copy to build/dist/

14.1 Manifest schema

Only output + include are required; everything else shows its default:

{
  "output": {
    "name": "merged-datapack",
    "description": "Merged vortacraftmc datapack",
    "min_format": 121,
    "max_format": 121
  },
  "include": ["guikit-datapack", "macroEngine-Datapack-v26.4"],
  "exclude": [],
  "allowMismatchedFormats": false,
  "gatedLoad": true,
  "namespace": "vcm_core",
  "debugDefault": false,
  "killSwitch": true,
  "loadErrorHandling": true,
  "strictLoadRefs": true,
  "zip": true
}
Key Default Meaning
output.name / .description — merged pack identity; also the zip name
output.min_format / .max_format — required for format 82+ (25w31a+); pack_format is legacy only
include — packs to merge (directories under packs/)
exclude [] explicit exclusions
allowMismatchedFormats false fail when included packs declare different formats
gatedLoad true route every pack's minecraft:load/tick hooks through a generated gatekeeper; false = legacy plain union-merge of the load/tick tags
namespace vcm_core namespace for generated gatekeeper files; lowercase [a-z0-9_.-]+, never minecraft
debugDefault false initial debug-message state (runtime-toggleable)
killSwitch true also generate the global enable/disable kill-switch (needs gatedLoad)
loadErrorHandling true build-time load/tick reference validation + runtime error log + per-pack load markers
strictLoadRefs true load/tick hooks that resolve to nothing fail the build; false = warn only
zip true also write build/<output.name>.zip next to build/merged-datapack/

14.2 Gated load/tick system

With gatedLoad: true (default), each included pack's #minecraft:load and #minecraft:tick hooks are re-wired through a generated <namespace>:load / <namespace>:tick gatekeeper:

flowchart LR
    V["#minecraft:load / #minecraft:tick"] --> GK["vcm_core gatekeeper"]
    GK -->|"per-pack toggle ON"| P1[pack A load/tick]
    GK -->|"toggle OFF"| X1((skipped))
    GK --> P2[pack B load/tick]
    GK -. debug + status .-> LOG[debug log / status]
Loading

Result: per-pack toggles, centralized debug output and status, and a single place to observe what loaded.

14.3 Kill-switch & debug

Generated runtime controls (defaults killSwitch: true, debugDefault: false):

/function vcm_core:enable_all      # global kill-switch: everything on
/function vcm_core:disable_all     # everything off
/function vcm_core:debug/on        # debug messages on
/function vcm_core:debug/off
/function vcm_core:debug/toggle

14.4 Load-error handling

With loadErrorHandling: true:

  • build-time — every load/tick reference is validated; dangling refs fail the build when strictLoadRefs: true (warn otherwise);
  • runtime — api/report_error, errors, errors_clear entry points record and inspect load errors;
  • per-pack load markers feed the status view, so you can see which packs actually initialized.

14.5 Outputs

Path Content
build/merged-datapack/ exploded merged datapack
build/<output.name>.zip zipped merged datapack (when zip: true)
build/dist/ root build task copies both here so they survive clean
-PmergeReport=<path> JSON run summary (machine-readable)

Tip

Merging macroEngine with other packs? Keep the resource pack installed — merging cannot bundle resource-pack assets into a datapack.


15 · Pack Formats and Versions

15.1 Format terminology

  • pack_format — the classic single-number pack format (legacy-only for modern releases).
  • min_format / max_format — the pair-based declaration introduced for modern releases; required from format 82+ (25w31a+). Values may be plain numbers or [major, minor] pairs.
  • Datapack vs resource pack formats differ — the same MC release has different numbers for each (e.g. macroEngine v26.4: datapack [122, 0], resource pack [98, 0]).
// datapack pack.mcmeta (macroEngine v26.4)
{ "pack": { "min_format": [122, 0], "max_format": [122, 0] } }

15.2 Pack compatibility matrix

Pack Kind MC target Format
macroEngine-Datapack-v26.4 datapack 26.4-snapshot-1 [122, 0]
macroEngine-Datapack-v26.3 datapack 26.3 121
macroEngine-Resourcepack-v26.4 resource pack 26.4-snapshot-1 [98, 0]
guikit-datapack / guikit-demo datapack 26.3 121
BorderPing / DailyBonus / QuickShare datapack modern 26.x [122, 1]
RTWrapper (datapack) datapack 26.3 format 104 (as documented in its API.md)
TunnelScript datapack 1.19.2 10
cmdTunnel-datapack datapack classic —
inv_gui datapack 1.20.3–1.20.4 26
LeftClickDetection datapack 1.20.3+ —
InteractionClickDetection datapack 1.20+ —

15.3 Mod compatibility matrix

Mod MC Fabric Loader Fabric API Java Loom
datapack-blocker 1.21.1 ≥ 0.16.14 any 21 1.15.5 + Yarn
datapack-fixer 1.21.4 ≥ 0.19.3 0.119.4+1.21.4 21 standalone build
rtwrapper-mod 1.21.1 ≥ 0.16.14 any 21 1.15.5 + Yarn
opmod-example (LevelOp) 26.3 ≥ 0.19.5 26.3 line 25 1.15.5, no mappings
TEMPLATE-MOD 26.1.2 26.x line 26.x line 25 1.16-SNAPSHOT
examples/itemExampleMod 26.1.2 ≥ 0.18.4 0.148.2+26.1.2 25 1.15.5

Important

MC 26.1+ is unobfuscated. Mods targeting 26.x must not declare a mappings dependency and should set fabric.loom.disableObfuscation=true — full explanation in §4.3 and §18.

15.4 Validation in CI

  • ./gradlew checkPacks validates every pack.mcmeta, JSON file and cross-reference before anything is packaged (zipPacks depends on it).
  • ./gradlew printPackFormats prints the declared formats of every pack — handy when bumping a pack to a new MC release.
  • mergeDatapacks refuses to merge packs with mismatched formats unless allowMismatchedFormats: true (§14).

16 · Contributing

Read NOTICE.md before opening a PR. This section summarizes the mechanics.

16.1 Ground rules

Area Rule
mods/ Must build cleanly across all subprojects — a shared dependency bump can silently break a sibling mod
packs/ Not part of the Gradle build; a green buildAll says nothing about a datapack change. Maintenance mode: fixes only
scripts/ Lower trust by default — review before running
examples/ Templates/samples; not shipped, lighter security posture
cross-cutting changes If a change spans a mod and a pack, say so explicitly in the PR description — CI only covers the Gradle side

16.2 Pull requests

  1. Fork or clone, create a branch (git checkout -b fix-gui-crash). No strict naming convention — describe the change.

  2. Make your changes; keep commit messages short and descriptive.

  3. Build and lint before opening the PR:

    ./gradlew buildAll
    ./gradlew lint
  4. Open the PR against main; CI must pass before requesting review.

  5. Describe what changed and why, and whether it touches mods/, packs/, or both.

  6. Work through the pre-PR checklist (below).

Before opening a PR — checklist from NOTICE.md:

  • ./gradlew buildAll passes
  • ./gradlew lint passes
  • If you touched packs/, you've validated the pack loads correctly (Gradle passing does not cover this)
  • PR description explains what changed and why, and says whether the change touches mods, packs, or both
  • No unexplained dependencies, obfuscation, or behavior not covered by the description

16.3 The datapack lock protocol

Every existing top-level directory under packs/ is locked: true in packs/.datapack-lock.json, enforced by CI. To change a locked pack you need three PRs:

sequenceDiagram
    participant A as Author
    participant CI as CI (immutability)
    participant M as Maintainers
    A->>M: PR 1: set pack "locked": false
    M-->>A: reviewed & merged
    A->>CI: PR 2: the actual fix
    CI-->>M: passes (pack unlocked)
    M-->>A: reviewed & merged
    A->>M: PR 3: set pack "locked": true again
    M-->>A: merged — pack frozen again
Loading

Notes:

  • The lock file and the checker script are read from the base branch, so PR 1 must be merged first — you cannot unlock and fix in one PR.
  • New top-level pack directories pass through (that's how packs are added) but must be added to the lock file, locked, in a prompt follow-up PR.

16.4 Provenance watermarks

Every datapack carries _vc_origin.mcfunction under data/<namespace>/function/:

  • zipPacks treats a missing watermark as a build failure.
  • Do not remove, rename or hand-edit watermarks in packs/ in your PR.
  • Only build.gradle (via its build/packs-remap/ working copy, never packs/) and maintainer tooling are expected to touch them.
  • Conduct expectation, not a license restriction — the Unlicense still governs copies once obtained.

16.5 Code style

  • Java: clear and documented; complex logic needs intent-explaining comments.
  • Avoid unnecessary dependencies — every dependency is shared build surface for the whole monorepo.
  • Fabric mod code must remain tick-safe (project TPS guidelines).
  • Datapacks: respect namespace isolation — don't introduce function/tag names that can collide with another pack in this repo or common third-party packs.
  • Macro-heavy or command-generation changes get closer review — call them out explicitly in the PR.

16.6 What gets a PR closed

From NOTICE.md — explicitly prohibited:

  • ❌ building griefing tools, cheat clients/mods, exploit kits, or anything designed to bypass another server's protections without authorization;
  • ❌ PRs adding obfuscated code, hidden network calls, backdoors, or any behavior not clearly described in the PR (closed without further discussion, regardless of technical quality);
  • ❌ using this repo's macro/command-generation systems to inject unsafe or attacker-controlled input into commands on a target server;
  • ❌ posting working exploits in public PR descriptions — use the private process in SECURITY.md first.

Repeat or clearly malicious cases get blocked from the repo. Feature work against archived packs is also out of scope.


17 · Security

This project follows a security-first development philosophy, especially around datapack macro-injection risks and namespace isolation.

17.1 Reporting a vulnerability

Report privately — never as a public issue:

Include: affected project/path · reproduction steps or minimal example · impact (what an attacker could actually do) · Minecraft/Fabric/Loom version if relevant.

Reports are acknowledged as soon as possible, with a fix or mitigation aimed for a timeframe matching severity. Low-risk findings in archived/frozen projects may be documented rather than fixed.

17.2 Scope

Area Status
mods/ Actively maintained Fabric mods. Compiled, type-safe.
packs/ Datapacks — some actively maintained, some archived and frozen
scripts/ Helper tooling. Lower trust; review before running.
examples/ Templates and samples. Not production-intended.
archived/ Reserved for no-longer-maintained projects — reference only (currently empty)

Where practical, security-sensitive logic lives in a Fabric mod rather than a datapack.

17.3 Datapacks vs mods — real risk model

Note

"Fabric is a hacker tool" — false. Fabric is a standard mod loader in the same category as Forge/NeoForge/Quilt. Tools are neutral; judge a specific mod by its source and behavior.

Note

"Datapacks are safe, mods are unsafe" — a false framing. The one real technical difference: datapacks cannot execute arbitrary Java bytecode — declarative JSON plus constrained mcfunction, interpreted by the vanilla command engine. Mods are compiled Java running with server-process privileges. That changes the shape of the attack surface, not the safety:

  • Datapacks can still degrade or crash a server: unbounded function recursion, runaway entity/marker spawning, unbounded data storage growth — exactly the failure classes macroEngine's own cleanup work (_item_tmp/rl_work scratch-storage fixes) exists to prevent.
  • Datapacks can corrupt gameplay state (scoreboards, NBT, player data) as easily as badly written mods — both mutate the same world data.
  • "Cannot run arbitrary Java" is a ceiling on what kind of damage is possible, not a guarantee that none is.

Note

Mod safety is a function of source, not mechanism. An unsigned mod from an unmoderated site is high-risk — same as any unreviewed binary. A mod on CurseForge/Modrinth with real download counts and scrutiny has had far more eyes on it than the average privately-shared datapack. And a .zip of obfuscated mcfunction can hide destructive logic just as well.

17.4 Defensive tooling

Tool Role
datapack-blocker tripwire for unapproved datapacks dropped into a world
datapack-fixer server-safe syntax diagnostics; backups before any write
datapack_risk_scan.py read-only audit of .mcfunction risk patterns
.datapack-lock.json + immutability CI frozen packs can't be silently edited
_vc_origin.mcfunction watermarks provenance tracking for every pack
macroEngine rate limiting throttles in-engine request floods

18 · Troubleshooting

Known failure modes and their fixes, ordered by how often they bite.

18.1 "Failed to find official mojang mappings for 26.x"

A problem occurred configuring project ':mods:<name>'.
> Failed to setup Minecraft, java.lang.RuntimeException:
  Failed to find official mojang mappings for 26.3

Cause: Minecraft 26.1+ ships unobfuscated. Mojang no longer publishes official mappings for those versions, so loom.officialMojangMappings() can never resolve. This is not a Loom bug and not a network problem.

Fix (the pattern used by mods/opmod-example):

 dependencies {
     minecraft "com.mojang:minecraft:${project.minecraft_version}"
-    mappings loom.officialMojangMappings()
-    modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
-    modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
+    implementation "net.fabricmc:fabric-loader:${project.loader_version}"
+    implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
 }
# <subproject>/gradle.properties
fabric.loom.disableObfuscation=true

Warning

Do not try to fix this by changing the Loom version — it won't help. Loom 1.15.5 is the minimum version with unobfuscated-jar support (MinecraftJarProcessor.isUnobfuscated()), which is why the monorepo pins it.

Also: MC 26.x renamed several classes. If compilation then fails with cannot find symbol, check the merged jar — e.g. ResourceLocation → Identifier, LoadingOverlay.LOGO → MOJANG_STUDIOS_LOGO_LOCATION.

18.2 Invalid fabric-loom version

Plugin [id: 'fabric-loom', version: '1.17'] was not found in any of the
following sources: … could not resolve plugin artifact
'fabric-loom:fabric-loom.gradle.plugin:1.17'

Cause: Fabric publishes Loom per-patch only. A bare 1.17 has never existed on maven.fabricmc.net — the real series is 1.17.0 … 1.17.21, then 1.18.x.

Fix: pin the nearest real version, keeping consistency with sibling subprojects where possible:

-id 'fabric-loom' version '1.17'
+id 'fabric-loom' version '1.17.21'

Browse what actually exists: https://maven.fabricmc.net/fabric-loom/fabric-loom.gradle.plugin/maven-metadata.xml

18.3 Loom cache lock after a crashed build

Previous process has disowned the lock due to abrupt termination.
Found existing cache lock file (ACQUIRED_PREVIOUS_OWNER_DISOWNED),
rebuilding loom cache.

Not fatal — Loom rebuilds its cache automatically. If it keeps reappearing:

  1. Stop all Gradle daemons: ./gradlew --stop (and kill stray GradleDaemon JVMs).
  2. Delete the stale cache for that MC version: rm -rf ~/.gradle/caches/fabric-loom/<minecraft-version> (or your GRADLE_USER_HOME).
  3. Rebuild. Avoid Ctrl-C'ing Loom mid-setup; it's the usual source of the disowned lock.

18.4 Out of memory

Symptoms: OutOfMemoryError, Java heap space, GC overhead limit exceeded — typically during remapJar when several Loom subprojects share one daemon.

Fixes:

  • The root gradle.properties already sets -Xmx4G -XX:MaxMetaspaceSize=1g; bump further if you add more Loom subprojects.

  • On small machines (< 4 GB RAM), override instead:

    ./gradlew buildAll --max-workers=1 \
      -Dorg.gradle.jvmargs="-Xmx1500m -XX:MaxMetaspaceSize=512m"
  • Beware subproject-local gradle.properties jvmargs: they only apply when that subproject is built as its own root; in the monorepo the root file wins.

18.5 zipPacks refuses to run

zipPacks requires explicit confirmation …

Cause: packaging is gated on purpose. Fix: pass -PconfirmZip=yes (the sanctioned non-interactive path; CI uses it), or answer the interactive prompt. A missing _vc_origin.mcfunction watermark also fails zipPacks — restore the watermark rather than bypassing the check.

18.6 macroEngine won't initialize (v26.3)

By design — v26.3 is archived and its engine refuses to load unless you opt in:

/data modify storage macroengine:engine config.allow_unsupported_load set value 1b

Static content (recipes, loot tables, advancements, predicates, item modifiers, enchantments) works either way. The real fix: move to macroEngine v26.4 (§6).

18.7 macroEngine messages show raw keys

You're missing the companion resource pack: messages fall back to raw macroengine.* translation keys and players get a recurring join warning. Install/enforce it per §7.3.

18.8 modImplementation doesn't resolve on MC 26.x

With fabric.loom.disableObfuscation=true, Loom's RemapConfigurations.setupForSourceSet returns early and never creates the mod* configurations — modImplementation silently no-ops or fails to resolve. Use plain implementation / compileOnly / runtimeOnly (§18.1).

18.9 Companion tool: automated build doctor

Some forks of this repo ship an optional companion script (scripts/ai-fixer/fixer.py) that automates exactly the fixes above: a deterministic rule engine handles the known failure modes (mappings-for-26.x, nonexistent Loom versions, missing yarn/fabric-api/loader versions, OOM), and a local LLM (Ollama / any OpenAI-compatible server) is consulted only for anything unknown. It is dry-run by default, validates every proposed edit, and backs up files before writing. If your copy of the repo doesn't include it, the manual fixes in this section are canonical.


19 · FAQ

19.1 Why did the repo move to Fabric?

The project no longer ships or accepts new vanilla datapacks; development moved to Fabric mods (Java, Gradle). Reasons:

  • Datapacks run inside the vanilla command system — they can't execute native code or touch the filesystem/network directly, but they can still cause real problems: lag from unbounded loops, world/data corruption via data merge, griefing via entity/inventory manipulation — all hard to review at scale and easy to hide in large command trees.
  • Fabric provides compiled, versioned, statically checkable code, proper dependency management, and CI tooling (tests, static analysis, dependency scanning) that datapacks don't support.

Contributors: new features belong in a Fabric mod under mods/. To port an existing datapack, open an issue and maintainers can help convert the logic.

19.2 Aren't datapacks safer than mods?

That framing is false — see the full risk model in §17.3. The one real technical difference is that datapacks can't run arbitrary Java bytecode, which caps what kind of damage is possible — but datapacks can still lag, crash and corrupt a server through purely in-game mechanisms. Actual safety depends overwhelmingly on the trustworthiness of the source, not the format.

19.3 Aren't mods harder than datapacks?

Partly true, overstated:

  • ✅ Getting started is easier with datapacks: no language, no build chain, edit → /reload → see result.
  • ❌ Scaling is where it flips. mcfunction has no first-class functions, no real data structures beyond NBT, and control flow built from execute if/unless chains. Features that are dozens of lines of Java become hundreds of lines of mcfunction spread across many files — macroEngine's rate limiter, cooldown system and cleanup routines are the repo's own evidence.
  • ❌ Debugging: a mod stack trace tells you the failing line; a silently failing execute chain just does nothing.
  • ❌ State management is manual in mcfunction (scoreboards/storage paths), versus scoped, garbage-collected locals in Java.

Datapacks are easier to start and read small; mods scale far better once you're past the entry cost.

19.4 What does "maintenance mode" mean for packs/?

  • ✅ In scope: bug fixes, security hardening, compatibility fixes for new Minecraft versions (pack_format bumps, syntax migrations), small QoL updates to existing modules.
  • ❌ Out of scope: new modules, new systems, or feature work that expands what a pack does. If a change would need a new top-level system comparable to macroEngine's rate-limit or hidden-flag modules, it doesn't belong here.
  • Rationale: the packs (especially macroEngine) have grown large enough that further feature growth trades off against maintainability.

Applies to packs/ only — mods/, scripts/, etc. are unaffected.

19.5 Can I still submit a datapack?

Not as new functionality — see maintenance mode. Fixes are welcome but must go through the lock protocol because every pack is locked.

19.6 Why is every pack locked in CI?

Because the packs are frozen artifacts with many downstream users. Silent edits to a locked pack would change behavior for every world using it. The three-PR protocol makes every change deliberate, reviewed and auditable. New packs being added aren't blocked — only modifications to existing locked trees.

19.7 Which Loom version should my new mod use?

  • Targeting MC 1.21.x (obfuscated, Yarn): pin 1.15.5 like datapack-blocker/rtwrapper-mod.
  • Targeting MC 26.x (unobfuscated): 1.15.5 is the minimum with unobfuscated-jar support; check opmod-example/TEMPLATE-MOD for current pins, and never use a bare series number like 1.17 — only per-patch versions exist (§18.2).

19.8 What happened to runtoolkit?

The runtoolkit organization was retired in favour of vortacraftmc. Its repos are archived and point to this monorepo. The original project was runtoolkit/suite by Runtoolkit; copyright notices are preserved in each LICENSE/NOTICE (§1).

19.9 Can I use inv_gui?

Not recommended. Licensing relative to upstream (rarula/Sketch) was never cleared. Kept for reference and possible reimplementation only — see §11.3.

19.10 Where do I report security issues?

Privately — GitHub's private vulnerability reporting, never a public issue. Full policy: §17.


20 · Glossary

Term Meaning in this repo
Allowlist The set of datapacks recorded by datapack-blocker on first run; anything else is quarantined
Gatekeeper Generated <namespace>:load/tick layer that mergeDatapacks inserts between vanilla tags and each merged pack
Hook A function bound to a gameplay event via macroengine:systems/hook/bind
Kill-switch vcm_core:enable_all / disable_all — global on/off for a merged datapack
Loom Fabric's Gradle plugin; compiles, remaps and runs Minecraft mods
Macro (mcfunction) A .mcfunction file with $(param) placeholders, invoked with arguments (MC 1.20.2+)
Maintenance mode packs/ policy: fixes only, no new features
Namespace isolation Keeping each pack's function/tag names inside its own namespace to avoid collisions
Provenance watermark _vc_origin.mcfunction file identifying a pack's origin; required by zipPacks
Quarantine datapack_blocker's holding area for unapproved packs (never deleted)
Sliding window macroEngine rate-limit mechanism: max N hits within the last W ticks
Tripwire A control that detects/alerts rather than fully preventing — datapack-blocker's stated scope
Unobfuscated (MC 26.1+) Minecraft ships final class/field/method names; no Yarn/Mojang mapping layer exists
Watermark check showOriginWatermarks / checkOriginWatermarks Gradle tasks

📚 vortacraftmc/core wiki — content licensed under the Unlicense unless noted otherwise in a subproject's own LICENSE/NOTICE (some components are MIT or CC0). Original work by Runtoolkit · maintained by vortacraftmc. Repository · Issues · Report a security issue

Clone this wiki locally