Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@

"mounts": [
"source=gradle-cache,target=/root/.gradle,type=volume"
]
],
"onCreateCommand": "setup.sh"
}
7 changes: 7 additions & 0 deletions .devcontainer/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
echo "Starting..."
cd /workspaces/RTWrapper
sudo apt update
sdk install java 21.0.2-tem
sdk use java 21.0.2-tem
chmod +x gradlew
./gradlew vscode
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,12 @@ run-*/
# OS
.DS_Store
Thumbs.db

# Minecraft / Datapack files
!Datapack/
!datapack/RTWrapper-Datapack/
!datapack/commands-26.2.json
!src/main/java/com/runtoolkit/rtwrapper/run/
!src/main/resources/data/*/function/**/run/
!scripts/run/
!gradle/wrapper/gradle-wrapper.jar
237 changes: 96 additions & 141 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,184 +1,136 @@
# RTWrapper

RTWrapper is a Fabric mod + standalone datapack for Java Edition 26.2. The mod embeds the same datapack data tree, while `datapack/RTWrapper-Datapack/` can be zipped and installed separately.
RTWrapper is a Fabric mod + standalone datapack for Minecraft Java Edition 26.2. The mod embeds the same datapack data tree, while `datapack/RTWrapper-Datapack/` can be zipped and installed separately.

## Requirements

| Component | Version |
| --- | --- |
| Minecraft | 26.2 ("Chaos Cubed") |
| Java | 25 (JDK 25 toolchain required) |
| Fabric Loader | matches `fabric.mod.json` — verify against `build/libs` manifest before release |
| Fabric API | matches `fabric.mod.json` |
| Minecraft | 26.2 |
| Java | 25 |
| Fabric Loader | see `fabric.mod.json` |
| Fabric API | see `gradle.properties` |
| Gradle | 9.5+ |
| Pack format | see `pack.mcmeta` in the datapack root — bump this in lockstep with `PACK_FORMAT` in `scripts/generate_wrappers.py` |

RTWrapper is built and tested against 26.2 only. It has not been validated against 26.1 or 26.3 — see "Updating command wrappers" below before attempting cross-version use.

Optional-but-managed dependency: [StringLib](https://github.com/CMDred/StringLib). RTWrapper's selector-detection helpers and dependency manager probe `stringlib:util/find`; install StringLib if you want those helpers and a clean dependency status.

## Layout

```text
src/main/ Fabric mod skeleton, Mojang official names
datapack/RTWrapper-Datapack/ Standalone datapack root
datapack/commands-26.2.json Command wrapper manifest + command parameter names
docs/API.md API/storage protocol
scripts/validate_datapack.py Datapack/static wrapper validator
src/gametest/ Fabric server GameTests
```
| Optional dependency | [StringLib](https://github.com/CMDred/StringLib) for CRE player-name selector validation |

## Installation

### As a Fabric mod
### Fabric mod

1. Install Fabric Loader for Minecraft 26.2.
2. Install Fabric API matching your Loader version.
3. Download or build `rtwrapper-<version>.jar` (see Build below).
4. Drop the jar into your `mods/` folder.
5. Launch the game or server. The mod embeds its datapack automatically — no separate install step needed.
6. In-world, run `/reload` once to ensure the embedded datapack functions are registered, then verify with:
1. Build or download `rtwrapper-<version>.jar`.
2. Put it in `mods/` with Fabric API.
3. Run `/reload` once after the server starts.
4. Check status:

```mcfunction
function runtoolkit:api/status
```
```mcfunction
function runtoolkit:api/status
```

### As a standalone datapack (no mod)
### Standalone datapack

1. Download or build `RTWrapper-Datapack-<version>.zip` (see Build below).
2. Place the zip into your world's `datapacks/` folder (`<world>/datapacks/RTWrapper-Datapack-<version>.zip`), or into `datapacks/` under your server root for a server.
3. If the world is already running, run `/reload`. Otherwise this loads automatically on world start.
4. Confirm the datapack is active — check **Advancements > Runtoolkit** in-game, or run:
1. Put `RTWrapper-Datapack-<version>.zip` in `<world>/datapacks/`.
2. Optional but recommended: put StringLib in the same datapacks folder.
3. Run:

```mcfunction
function runtoolkit:api/status
```
```mcfunction
reload
function runtoolkit:api/status
```

Do not install both the mod and the standalone datapack zip on the same instance — they embed the same `rtwrapper:` and `runtoolkit:` namespaces and will conflict on `/reload` (duplicate function/advancement registration). Pick one.
Do not install both the mod and standalone datapack at the same time; both provide the same namespaces.

## Datapack API quick start
## Basic request API

Generated command wrappers use meaningful command-specific parameter names. There is no generated catch-all or generic numeric parameter API.

Provide the named parameters in the order listed for that command in `datapack/commands-26.2.json`. The dispatcher calls the exact `<command>_<N>` variant and does not append unused params.

```mcfunction
# /tp @s 0 80 0 via queued handler
data modify storage rtwrapper:api request set value {cmd:"tp",params:{target:"@s",x:"0",y:"80",z:"0"}}
# /tp @s 0 80 0
data modify storage rtwrapper:api request set value {cmd:"tp",params:{target:"@s",x:"0",y:"80",z:"0"},runSafeMode:1b}
function rtwrapper:api/run

# /give @s minecraft:stone 1 via direct API
# /give @s minecraft:stone 1
data modify storage rtwrapper:api request set value {cmd:"give",params:{target:"@s",item:"minecraft:stone",count:"1"},runSafeMode:1b}
function rtwrapper:api/run

# direct command API
data modify storage rtwrapper:api params set value {target:"@s",item:"minecraft:stone",count:"1"}
function rtwrapper:api/commands/give

# /scoreboard players set #smoke rtw.test 1
data modify storage rtwrapper:api request set value {cmd:"scoreboard",params:{category:"players",action:"set",subject:"#smoke",objective:"rtw.test",value:"1"}}
function rtwrapper:api/run
```

## In-game trigger UI (testMode)
Parameter order and names are in `datapack/commands-26.2.json` under `command_params`.

RTWrapper creates these objectives on load:
## runSafeMode

```mcfunction
scoreboard objectives add rtw.temp dummy
scoreboard objectives add RTWrapper trigger
```
Single request `runSafeMode` defaults to `0b`.

`rtw.temp` is used by temporary UI/trigger systems: `1` means accepted/success, `0` means canceled/error. In-game trigger UI is gated behind the `rtwrapper.testMode` tag. Enable it per player:
- `runSafeMode:0b`: immediate full queue drain.
- `runSafeMode:1b`: safe one-step execution via `run_next`.

```mcfunction
function rtwrapper:api/testmode/on
```
Prefer `runSafeMode:1b` for player/user-generated requests.

Then use:
## Batch requests

```mcfunction
trigger RTWrapper set 1 # Open RTWrapper dialog
trigger RTWrapper set 2 # Run current rtwrapper:api request via rtwrapper:api/run
trigger RTWrapper set 3 # List command wrappers in chat
trigger RTWrapper set 4 # Open runtoolkit:dpman
```

Disable test mode:
Use `rtwrapper:api/run_many` for conditional multi-request execution.

```mcfunction
function rtwrapper:api/testmode/off
data modify storage rtwrapper:api batch set value {runSafeMode:1b,requests:[{req:{cmd:"give",params:{target:"@s",item:"minecraft:stone",count:"1"}},args:[{type:"score",name:"#allow",objective:"myScore",value:"1"}]},{req:{cmd:"function",params:{function_id:"my_pack:do_thing"}},args:[{type:"predicate",id:"my_pack:my_predicate"}]}]}
function rtwrapper:api/run_many
```

Named convenience wrapper example:
Each item is:

```mcfunction
# $give $(target) $(item)$(components) $(count)
data modify storage rtwrapper:api params set value {target:"@s",item:"minecraft:stone",components:"",count:"1"}
function rtwrapper:api/commands/give_item
```snbt
{req:{...normal RTWrapper request...},args:[...conditions...]}
```

### `run` vs `enqueue` / autotick

Two distinct execution paths exist — they are not interchangeable:
Supported conditions:

- **`rtwrapper:api/run`** executes the request in `rtwrapper:api request` immediately and drains the queue synchronously in the current tick. Use this for one-off calls where you need the result before your function continues.
- **`rtwrapper:api/enqueue`** pushes the request onto a queue. With `rtwrapper:api/autotick/on`, the queue is processed one action per tick. Use this when issuing many commands in a burst where spreading load across ticks avoids a single-tick lag spike.
```snbt
{type:"predicate",id:"my_pack:my_predicate"}
{type:"score",name:"#allow",objective:"myScore",value:"1"}
{type:"score",name:"#allow",score:"myScore",value:"1"}
```

Autotick usage:
## Queue / autotick

```mcfunction
function rtwrapper:api/autotick/on

data modify storage rtwrapper:api request set value {cmd:"say",params:{message:"queued hello"}}
data modify storage rtwrapper:api request set value {cmd:"say",params:{message:"queued hello"},runSafeMode:1b}
function rtwrapper:api/enqueue
```

Autotick processes one queued action per tick. Use `function rtwrapper:api/run` only for immediate full queue drain.

See [`docs/API.md`](docs/API.md) for the full protocol and debug/silent controls.

## Runtoolkit manager / loaded-pack discovery

RTWrapper installs the shared `runtoolkit` namespace so Runtoolkit packs can be managed globally:
## Core selector detection

```text
data/runtoolkit/function/
data/runtoolkit/tags/function/
data/runtoolkit/advancement/root.json
data/runtoolkit/advancement/packs/rtwrapper.json
```

After `/reload`, players get a visible **Advancements > Runtoolkit** tab via the `minecraft:tick` advancement trigger. This is intentionally not revoked, so it can be used as a stable visual list of loaded Runtoolkit datapacks without reading a long `/datapack list` output.

Dynamic list/status:
Selector detection lives in `core:selector/detect`.

```mcfunction
function runtoolkit:api/status
function runtoolkit:api/list
function runtoolkit:api/dump_registry
data modify storage core:selector input.value set value "@s"
function core:selector/detect
data get storage core:selector result
```

Manager controls for one pack:
Allowed:

```mcfunction
data modify storage runtoolkit:api request set value {id:"rtwrapper"}
function runtoolkit:api/disable
- player names, validated with StringLib as no `@` and length 3..16
- `@s`
- restricted `@a[limit=1]` / nearest variants
- restricted `@e[type=player,limit=1]` / nearest variants

data modify storage runtoolkit:api request set value {id:"rtwrapper"}
function runtoolkit:api/enable

data modify storage runtoolkit:api request set value {id:"rtwrapper"}
function runtoolkit:api/reload
```
Rejected:

Bulk manager hooks:
- `@p`
- `@r`
- unrestricted `@a`
- unrestricted or non-player `@e`

```mcfunction
function runtoolkit:api/disable_all
function runtoolkit:api/enable_all
function runtoolkit:api/reload_all
```
The detector reads storage first and returns fail when `storage core:selector input.value` is missing.

This manager does not call vanilla `/datapack disable|enable`; it controls Runtoolkit-managed registration/load/tick hooks. Functions still exist when a pack is manager-disabled, but the global manager stops running that pack's managed hooks.
## Runtoolkit manager

Other Runtoolkit projects can join the system by adding functions to these tags:
RTWrapper installs the shared `runtoolkit` namespace and manager tags:

```text
#runtoolkit:register
Expand All @@ -190,19 +142,31 @@ Other Runtoolkit projects can join the system by adding functions to these tags:
#runtoolkit:reload
```

## `commands-26.2.json`
Useful commands:

This file is the single source of truth for what `generate_wrappers.py` emits:
```mcfunction
function runtoolkit:api/list
function runtoolkit:api/status
function runtoolkit:api/dump_registry
function runtoolkit:dpman
```

- Top-level command lists define supported vanilla commands (`tp`, `give`, `scoreboard`, etc.).
- `command_params` lists ordered meaningful parameter names for each command.
- Named convenience wrappers (like `give_item`) are generated alongside the vanilla command wrappers.
Manager enable/disable/reload controls Runtoolkit hooks, not vanilla `/datapack enable|disable`:

If you add or change a command's parameters, edit `scripts/generate_wrappers.py` first, regenerate, then validate. Hand-editing generated function files under `data/rtwrapper/function/api/commands/` directly will be overwritten on next generation.
```mcfunction
data modify storage runtoolkit:api request set value {id:"rtwrapper"}
function runtoolkit:api/disable

## Build
data modify storage runtoolkit:api request set value {id:"rtwrapper"}
function runtoolkit:api/enable

data modify storage runtoolkit:api request set value {id:"rtwrapper"}
function runtoolkit:api/reload
```

Minecraft 26.2 targets Java 25. Use a JDK 25 toolchain and Gradle 9.5+. For 26.1+ Fabric, the build uses `net.fabricmc.fabric-loom` with Mojang official names directly, so there is intentionally no `mappings loom.officialMojangMappings()` dependency.
There is no RTWrapper dialog UI, no `rtwrapper.testMode` tag, and no `RTWrapper` trigger objective.

## Build

```bash
python3 scripts/validate_datapack.py
Expand All @@ -211,33 +175,24 @@ python3 scripts/validate_datapack.py

Build outputs:

- Fabric mod jar: `build/libs/rtwrapper-<version>.jar`
- Standalone datapack zip: `build/libs/RTWrapper-Datapack-<version>.zip`

The `build` task also runs server GameTests through Fabric API's GameTest integration. These spin up a headless test server as part of the Gradle build and fail the build on test failure. To run only the GameTests without a full build, use:

```bash
./gradlew runGametest
```
- `build/libs/rtwrapper-<version>.jar`
- `build/libs/RTWrapper-Datapack-<version>.zip`

## Updating command wrappers for 26.3+
## Updating command wrappers

1. Update `COMMANDS` / `DEBUG_COMMANDS` and `COMMAND_PARAMS` in `scripts/generate_wrappers.py`.
2. Update `minecraft_version`, `fabric_version`, and possibly `PACK_FORMAT`.
3. Run:
1. Edit `COMMANDS`, `DEBUG_COMMANDS`, and `COMMAND_PARAMS` in `scripts/generate_wrappers.py`.
2. Run:

```bash
python3 scripts/generate_wrappers.py
python3 scripts/validate_datapack.py
./gradlew build
```

Bumping `PACK_FORMAT` without updating every consuming datapack (including any `runtoolkit:` namespace dependents) can break `/reload` behavior on older packs. Verify with `function runtoolkit:api/status` after any pack format bump; don't assume silence means success.

## License

MIT. See [`LICENSE`](LICENSE).

## Safety

RTWrapper intentionally exposes privileged macro-command execution for trusted datapacks/admins. Do not copy untrusted player-controlled text into `rtwrapper:api request` or `rtwrapper:api params`.
RTWrapper exposes privileged macro-command execution for trusted datapacks/admins. Do not copy untrusted player-controlled text into `rtwrapper:api request` or `rtwrapper:api params`.
Loading