From 7c5a35d8fbecb865e40af07857be010bcf1a9893 Mon Sep 17 00:00:00 2001 From: Legends11 <235496468+tickwarden@users.noreply.github.com> Date: Mon, 10 Aug 2026 12:29:55 +0300 Subject: [PATCH] Delete rtwrapper-fabric directory --- rtwrapper-fabric/README.md | 61 ----- rtwrapper-fabric/build.gradle | 35 --- rtwrapper-fabric/gradle.properties | 7 - .../gradle/wrapper/gradle-wrapper.properties | 7 - rtwrapper-fabric/gradlew | 248 ------------------ rtwrapper-fabric/gradlew.bat | 93 ------- rtwrapper-fabric/settings.gradle | 9 - .../com/runtoolkit/rtwrapper/RTWrapper.java | 31 --- .../rtwrapper/api/RTDispatchResult.java | 52 ---- .../runtoolkit/rtwrapper/api/RTRequest.java | 56 ---- .../rtwrapper/api/RTWrapperAPI.java | 136 ---------- .../rtwrapper/command/RTCommand.java | 139 ---------- .../rtwrapper/command/RTWrapperCommand.java | 78 ------ .../src/main/resources/fabric.mod.json | 18 -- 14 files changed, 970 deletions(-) delete mode 100644 rtwrapper-fabric/README.md delete mode 100644 rtwrapper-fabric/build.gradle delete mode 100644 rtwrapper-fabric/gradle.properties delete mode 100644 rtwrapper-fabric/gradle/wrapper/gradle-wrapper.properties delete mode 100755 rtwrapper-fabric/gradlew delete mode 100644 rtwrapper-fabric/gradlew.bat delete mode 100644 rtwrapper-fabric/settings.gradle delete mode 100644 rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/RTWrapper.java delete mode 100644 rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTDispatchResult.java delete mode 100644 rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTRequest.java delete mode 100644 rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTWrapperAPI.java delete mode 100644 rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/command/RTCommand.java delete mode 100644 rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/command/RTWrapperCommand.java delete mode 100644 rtwrapper-fabric/src/main/resources/fabric.mod.json diff --git a/rtwrapper-fabric/README.md b/rtwrapper-fabric/README.md deleted file mode 100644 index e83c8fc..0000000 --- a/rtwrapper-fabric/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# RTWrapper (Fabric) - -`runtoolkit/RTWrapper` datapack'inin native Fabric mod (1.21.1, Yarn) karşılığı. -Aynı protokolü (adlandırılmış komut + parametre listesi → gerçek vanilla komutu) -uygular, ancak datapack'teki temel güvenlik açığı burada yapısal olarak kapatılmıştır. - -## Datapack'te ne vardı, burada ne değişti - -| Konu | Datapack | Bu mod | -|---|---|---| -| Komut çözümleme | `$function rtwrapper:core/wrappers/internal/$(cmd)` — herhangi bir string doğrudan function path'ine macro olarak enjekte ediliyordu | `RTCommand.fromLiteral(String)` — kapalı enum, bilinmeyen literal `null` döner, hiçbir zaman koda çözümlenmez | -| Yetki kontrolü | Yok. `rtwrapper:api request` NBT storage'ına yazabilen herkes (herhangi bir datapack, komut bloğu, `/data modify`) `op`/`ban`/`kick`/`whitelist`/`transfer` tetikleyebiliyordu | `RTWrapperAPI.execute()` her çağrıda gerçek bir `ServerCommandSource` ister ve `command.minPermissionLevel()`'e göre `source.hasPermissionLevel()` kontrolü yapar. Admin komutları sabit olarak level 4 | -| Giriş yüzeyi | Paylaşımlı, herkesin yazabildiği NBT storage (ambient authority) | Sadece Java metod çağrısı; forge edilemeyen bir `ServerCommandSource` gerektirir | -| Kuyruk | Sınırsız NBT listesi (`rtwrapper:runtime queue`) | Bellek içi, 256 istekle sınırlı `Deque`, tick başına bir kez boşaltılır | -| Hata ayrımı | Tek tip "bad_cmd" hatası | `UNKNOWN_COMMAND` / `PERMISSION_DENIED` / `COMMAND_FAILED` ayrı ayrı | - -## Kullanım - -### Oyuncu/komut kaynağı olarak -``` -/rtwrapper run tp @s 0 100 0 -/rtwrapper run op SomePlayer # level 2 oyuncu bile bunu tetikleyemez, OP level 4 ister -``` - -### Başka bir mod'dan (Java API) -```java -RTDispatchResult result = RTWrapperAPI.execute( - RTCommand.TP, - List.of("@s", "0", "100", "0"), - someServerCommandSource // gerçek, forge edilemeyen bir source olmalı -); - -if (!result.isSuccess()) { - // PERMISSION_DENIED / UNKNOWN_COMMAND / COMMAND_FAILED ayrımı burada -} -``` - -Caller kendi `ServerCommandSource`'unu üretmekten sorumludur (örn. bir oyuncunun -gerçek source'u, ya da bilinçli olarak `server.getCommandSource()` gibi -level-4 bir konsol kaynağı). API, bu source'un gerçekliğini varsaymaz — -sadece taşıdığı permission level'e göre karar verir. - -## Kapsam notu - -`RTCommand` enum'ı datapack'teki wrapper setinin (~70 komut, tp/say/effect gibi -düşük riskli olanlardan op/ban/whitelist/transfer gibi yönetimsel olanlara kadar) -bire bir karşılığıdır. Yeni bir komut eklemek, enum'a bir satır eklemek ve -gerekiyorsa `minPermissionLevel`'i belirlemek kadar basittir — ama bu bilinçli -bir kod değişikliği gerektirir, hiçbir zaman çalışma anında bir string'den -otomatik türetilmez. - -## Bilinen sınırlamalar - -- `buildCommandString` argümanları boşlukla birleştirip Brigadier'e ham string - olarak veriyor; bu, vanilla `/execute run ` zincirlerinin çalışma şeklinin - aynısı, ancak argüman içinde boşluk geçen (örn. serbest metin `/say` argümanı) - durumlar için `List args` sırasının çağıran tarafından doğru - kurulması gerekir. İleri seviye bir sürümde bu, Brigadier'in kendi - `ArgumentType` sistemine (örn. `MessageArgumentType`) taşınabilir. -- Queue şu an FIFO ve öncelik ayrımı yok; datapack'teki `queue[0]` mantığının - basit karşılığı. diff --git a/rtwrapper-fabric/build.gradle b/rtwrapper-fabric/build.gradle deleted file mode 100644 index 18e61b9..0000000 --- a/rtwrapper-fabric/build.gradle +++ /dev/null @@ -1,35 +0,0 @@ -plugins { - id 'fabric-loom' version '1.10.4' - id 'maven-publish' -} - -version = project.mod_version -group = project.maven_group - -repositories { - mavenCentral() -} - -dependencies { - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" -} - -processResources { - inputs.property "version", project.version - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -java { - withSourcesJar() - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 -} - -tasks.withType(JavaCompile).configureEach { - options.encoding = "UTF-8" -} diff --git a/rtwrapper-fabric/gradle.properties b/rtwrapper-fabric/gradle.properties deleted file mode 100644 index 015a298..0000000 --- a/rtwrapper-fabric/gradle.properties +++ /dev/null @@ -1,7 +0,0 @@ -minecraft_version=1.21.1 -yarn_mappings=1.21.1+build.3 -loader_version=0.16.14 -fabric_version=0.116.4+1.21.1 -mod_version=1.0.0 -maven_group=com.runtoolkit -archives_base_name=rtwrapper diff --git a/rtwrapper-fabric/gradle/wrapper/gradle-wrapper.properties b/rtwrapper-fabric/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index dbc3ce4..0000000 --- a/rtwrapper-fabric/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/rtwrapper-fabric/gradlew b/rtwrapper-fabric/gradlew deleted file mode 100755 index 0262dcb..0000000 --- a/rtwrapper-fabric/gradlew +++ /dev/null @@ -1,248 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/rtwrapper-fabric/gradlew.bat b/rtwrapper-fabric/gradlew.bat deleted file mode 100644 index e509b2d..0000000 --- a/rtwrapper-fabric/gradlew.bat +++ /dev/null @@ -1,93 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/rtwrapper-fabric/settings.gradle b/rtwrapper-fabric/settings.gradle deleted file mode 100644 index 31dfed8..0000000 --- a/rtwrapper-fabric/settings.gradle +++ /dev/null @@ -1,9 +0,0 @@ -pluginManagement { - repositories { - maven { url 'https://maven.fabricmc.net/' } - mavenCentral() - gradlePluginPortal() - } -} - -rootProject.name = 'rtwrapper' diff --git a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/RTWrapper.java b/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/RTWrapper.java deleted file mode 100644 index 3ca2876..0000000 --- a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/RTWrapper.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.runtoolkit.rtwrapper; - -import com.runtoolkit.rtwrapper.api.RTWrapperAPI; -import com.runtoolkit.rtwrapper.command.RTWrapperCommand; -import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RTWrapper implements ModInitializer { - - public static final String MOD_ID = "rtwrapper"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - - @Override - public void onInitialize() { - CommandRegistrationCallback.EVENT.register( - (dispatcher, registryAccess, environment) -> RTWrapperCommand.register(dispatcher)); - - // Queue is only drained once per server tick, and draining is a - // plain list iteration over whatever was enqueued that tick — no - // polling, no per-request scheduling, no busy-wait. This keeps - // the mod well inside the TPS 18-19 floor requirement even if a - // caller enqueues the full 256-request cap in one go. - ServerTickEvents.END_SERVER_TICK.register(server -> RTWrapperAPI.runQueued()); - - LOGGER.info("RTWrapper loaded (native allowlist dispatch, {} commands registered)", - com.runtoolkit.rtwrapper.command.RTCommand.values().length); - } -} diff --git a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTDispatchResult.java b/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTDispatchResult.java deleted file mode 100644 index 0e3e3a2..0000000 --- a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTDispatchResult.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.runtoolkit.rtwrapper.api; - -/** - * Outcome of a dispatch attempt. Distinguishes the two failure modes that - * the datapack silently conflated: - * - PERMISSION_DENIED: the source didn't have enough permission level. - * - COMMAND_FAILED: Brigadier itself rejected/failed the built command. - * The datapack's error_bad_cmd handler couldn't tell these apart because - * it only ever saw a raw macro-dispatch failure. - */ -public final class RTDispatchResult { - - public enum Status { SUCCESS, PERMISSION_DENIED, UNKNOWN_COMMAND, COMMAND_FAILED } - - private final Status status; - private final String message; - - private RTDispatchResult(Status status, String message) { - this.status = status; - this.message = message; - } - - public static RTDispatchResult success() { - return new RTDispatchResult(Status.SUCCESS, null); - } - - public static RTDispatchResult permissionDenied(int required, int actual) { - return new RTDispatchResult(Status.PERMISSION_DENIED, - "Requires permission level " + required + ", source has " + actual); - } - - public static RTDispatchResult unknownCommand(String literal) { - return new RTDispatchResult(Status.UNKNOWN_COMMAND, - "'" + literal + "' is not in the RTWrapper command allowlist"); - } - - public static RTDispatchResult commandFailed(String message) { - return new RTDispatchResult(Status.COMMAND_FAILED, message); - } - - public Status status() { - return status; - } - - public String message() { - return message; - } - - public boolean isSuccess() { - return status == Status.SUCCESS; - } -} diff --git a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTRequest.java b/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTRequest.java deleted file mode 100644 index f1002c6..0000000 --- a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTRequest.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.runtoolkit.rtwrapper.api; - -import com.runtoolkit.rtwrapper.command.RTCommand; -import net.minecraft.server.command.ServerCommandSource; - -import java.util.List; -import java.util.Objects; - -/** - * A single command request. - * - * Deliberately immutable and requiring a real ServerCommandSource at - * construction time. This is the structural fix for the datapack's core - * flaw: there, a request was just NBT written into rtwrapper:api storage, - * with no origin/authority attached to it at all — any datapack, command - * block, or /data modify from any player could write {cmd:"op", ...} and - * the wrapper would run it. - * - * Here, you cannot build an RTRequest without a ServerCommandSource. That - * source carries the actual permission level of whoever/whatever is - * asking. There is no "trust the string" path. - */ -public final class RTRequest { - - private final RTCommand command; - private final List args; - private final ServerCommandSource source; - - private RTRequest(RTCommand command, List args, ServerCommandSource source) { - this.command = Objects.requireNonNull(command, "command"); - this.args = List.copyOf(args); - this.source = Objects.requireNonNull(source, "source"); - } - - /** - * Build a request from a known RTCommand. This is the path other mods - * should use — it forces callers to have already resolved a literal - * through RTCommand.fromLiteral() (or reference the enum directly), - * so an unrecognized command literal can never reach this class. - */ - public static RTRequest of(RTCommand command, List args, ServerCommandSource source) { - return new RTRequest(command, args, source); - } - - public RTCommand command() { - return command; - } - - public List args() { - return args; - } - - public ServerCommandSource source() { - return source; - } -} diff --git a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTWrapperAPI.java b/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTWrapperAPI.java deleted file mode 100644 index 917709b..0000000 --- a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/api/RTWrapperAPI.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.runtoolkit.rtwrapper.api; - -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.runtoolkit.rtwrapper.command.RTCommand; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.command.ServerCommandSource; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.List; - -/** - * Public API surface other mods use instead of writing to shared NBT storage. - * - * Design decisions that map directly onto the datapack's actual problems: - * - * 1. allowlist: RTCommand is a closed enum (see RTCommand.java). There is - * no string-to-function-path resolution anywhere in this class. - * - * 2. permission: every request carries a real ServerCommandSource. Before - * building/running anything, execute() checks - * source.hasPermissionLevel(command.minPermissionLevel()). For admin - * commands (op/ban/kick/whitelist/transfer/...) that's level 4 — a - * console or a permission-4 source, not "whatever wrote to storage". - * - * 3. no ambient authority: unlike the datapack, there is no shared mutable - * storage another mod/datapack can poke to trigger a command. The only - * way in is this method call, and it requires a real source object you - * can't forge from a command block or /data modify. - * - * 4. queue is in-memory and per-tick bounded, not unbounded NBT — avoids - * the TOCTOU window the datapack had between "queue written" and - * "queue read/executed" a tick later, since here dispatch happens - * synchronously in the caller's own call, no cross-tick handoff needed - * unless the caller explicitly enqueues. - */ -public final class RTWrapperAPI { - - private RTWrapperAPI() {} - - // Bounded queue for callers that want fire-and-forget batching via - // enqueue()/runQueued(). Deliberately capped — the datapack's - // rtwrapper:runtime queue was an unbounded NBT list any source could - // grow arbitrarily. - private static final int MAX_QUEUE_SIZE = 256; - private static final Deque QUEUE = new ArrayDeque<>(); - - /** - * Execute a single request immediately, synchronously. - * This is the primary entry point. - */ - public static RTDispatchResult execute(RTRequest request) { - RTCommand command = request.command(); - ServerCommandSource source = request.source(); - - int required = command.minPermissionLevel(); - if (!source.hasPermissionLevel(required)) { - return RTDispatchResult.permissionDenied(required, effectivePermissionLevel(source)); - } - - String fullCommand = buildCommandString(command, request.args()); - MinecraftServer server = source.getServer(); - - try { - int result = server.getCommandManager().getDispatcher().execute(fullCommand, source); - if (result <= 0) { - return RTDispatchResult.commandFailed("Command returned non-positive result: " + fullCommand); - } - return RTDispatchResult.success(); - } catch (CommandSyntaxException e) { - return RTDispatchResult.commandFailed(e.getMessage()); - } - } - - /** - * Convenience overload: resolve a literal against the allowlist first. - * Unknown literals are rejected here, before an RTRequest ever exists. - */ - public static RTDispatchResult execute(String cmdLiteral, List args, ServerCommandSource source) { - RTCommand command = RTCommand.fromLiteral(cmdLiteral); - if (command == null) { - return RTDispatchResult.unknownCommand(cmdLiteral); - } - return execute(RTRequest.of(command, args, source)); - } - - /** - * Queue a request for later batch execution (e.g. from runQueued(), - * called once per tick by the mod's own tick handler). Bounded to - * prevent unbounded growth. - */ - public static boolean enqueue(RTRequest request) { - synchronized (QUEUE) { - if (QUEUE.size() >= MAX_QUEUE_SIZE) { - return false; - } - QUEUE.add(request); - return true; - } - } - - /** - * Drain and execute everything currently queued. Returns per-request - * results in submission order. - */ - public static List runQueued() { - List batch; - synchronized (QUEUE) { - batch = new ArrayList<>(QUEUE); - QUEUE.clear(); - } - List results = new ArrayList<>(batch.size()); - for (RTRequest r : batch) { - results.add(execute(r)); - } - return results; - } - - private static String buildCommandString(RTCommand command, List args) { - StringBuilder sb = new StringBuilder(command.literal()); - for (String arg : args) { - sb.append(' ').append(arg); - } - return sb.toString(); - } - - private static int effectivePermissionLevel(ServerCommandSource source) { - for (int level = 4; level >= 0; level--) { - if (source.hasPermissionLevel(level)) { - return level; - } - } - return 0; - } -} diff --git a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/command/RTCommand.java b/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/command/RTCommand.java deleted file mode 100644 index 574cbed..0000000 --- a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/command/RTCommand.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.runtoolkit.rtwrapper.command; - -import java.util.HashMap; -import java.util.Map; - -/** - * Fixed, compile-time allowlist of every command RTWrapper is permitted to dispatch. - * - * This is the single most important difference from the datapack version. - * The datapack did: - * - * $function rtwrapper:core/wrappers/internal/$(cmd) - * - * ...which resolves an arbitrary string straight into a function call with - * no allowlist and no permission check. Any datapack/command block able to - * write into rtwrapper:api storage could trigger ANY wrapper, including - * ban/op/kick/whitelist/transfer. - * - * Here, `cmd` from an incoming request is looked up against this enum. - * If it doesn't match a known entry, the request is rejected before any - * Brigadier command is ever built or dispatched — there is no code path - * from "unrecognized string" to "command execution". - * - * minPermissionLevel encodes what RTWrapper.execute(...) will itself - * enforce, in addition to whatever the source's own permission level is. - * Administrative commands are pinned to level 2 (op) regardless of what - * the caller passes in. - */ -public enum RTCommand { - - // --- Non-administrative / low-risk commands --- - TP("tp", 0), - TELEPORT("teleport", 0), - SAY("say", 0), - TELL("tell", 0), - MSG("msg", 0), - ME("me", 0), - TELLRAW("tellraw", 0), - TITLE("title", 0), - EFFECT("effect", 0), - GIVE("give", 0), - CLEAR("clear", 0), - XP("xp", 0), - EXPERIENCE("experience", 0), - GAMEMODE("gamemode", 2), - WEATHER("weather", 2), - TIME("time", 2), - DIFFICULTY("difficulty", 2), - SUMMON("summon", 2), - KILL("kill", 2), - SETBLOCK("setblock", 2), - FILL("fill", 2), - CLONE("clone", 2), - SCOREBOARD("scoreboard", 2), - TAG("tag", 2), - TEAM("team", 2), - GAMERULE("gamerule", 2), - SCHEDULE("schedule", 2), - FUNCTION("function", 2), - TRIGGER("trigger", 0), - DATA("data", 2), - EXECUTE("execute", 2), - BOSSBAR("bossbar", 2), - PARTICLE("particle", 2), - PLAYSOUND("playsound", 2), - STOPSOUND("stopsound", 2), - FORCELOAD("forceload", 2), - WORLDBORDER("worldborder", 2), - SPREADPLAYERS("spreadplayers", 2), - SPAWNPOINT("spawnpoint", 2), - SETWORLDSPAWN("setworldspawn", 2), - ADVANCEMENT("advancement", 2), - RECIPE("recipe", 2), - ENCHANT("enchant", 2), - ATTRIBUTE("attribute", 2), - DAMAGE("damage", 2), - LOOT("loot", 2), - ITEM("item", 2), - RIDE("ride", 2), - PLACE("place", 2), - ROTATE("rotate", 2), - LOCATE("locate", 0), - SEED("seed", 0), - LIST("list", 0), - - // --- Administrative / high-risk commands — locked to permission level 4 --- - OP("op", 4), - DEOP("deop", 4), - BAN("ban", 4), - BAN_IP("ban-ip", 4), - PARDON("pardon", 4), - PARDON_IP("pardon-ip", 4), - KICK("kick", 4), - WHITELIST("whitelist", 4), - TRANSFER("transfer", 4), - STOP("stop", 4), - SAVE_ALL("save-all", 4), - SAVE_OFF("save-off", 4), - SAVE_ON("save-on", 4), - RELOAD("reload", 4), - DATAPACK("datapack", 4), - SETIDLETIMEOUT("setidletimeout", 4), - DEBUGCONFIG("debugconfig", 4), - PUBLISH("publish", 4), - UNPUBLISH("unpublish", 4); - - private final String literal; - private final int minPermissionLevel; - - RTCommand(String literal, int minPermissionLevel) { - this.literal = literal; - this.minPermissionLevel = minPermissionLevel; - } - - public String literal() { - return literal; - } - - public int minPermissionLevel() { - return minPermissionLevel; - } - - private static final Map BY_LITERAL = new HashMap<>(); - static { - for (RTCommand c : values()) { - BY_LITERAL.put(c.literal, c); - } - } - - /** - * The only entry point from an untrusted string to an RTCommand. - * Returns null (never throws, never resolves) if the string isn't a - * known literal. Callers MUST treat null as "reject the request". - */ - public static RTCommand fromLiteral(String literal) { - if (literal == null) return null; - return BY_LITERAL.get(literal); - } -} diff --git a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/command/RTWrapperCommand.java b/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/command/RTWrapperCommand.java deleted file mode 100644 index 4d7869a..0000000 --- a/rtwrapper-fabric/src/main/java/com/runtoolkit/rtwrapper/command/RTWrapperCommand.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.runtoolkit.rtwrapper.command; - -import com.mojang.brigadier.CommandDispatcher; -import com.runtoolkit.rtwrapper.api.RTDispatchResult; -import com.runtoolkit.rtwrapper.api.RTRequest; -import com.runtoolkit.rtwrapper.api.RTWrapperAPI; -import com.mojang.brigadier.arguments.StringArgumentType; -import net.minecraft.server.command.CommandManager; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.Text; - -import java.util.Arrays; -import java.util.List; - -/** - * /rtwrapper run [args...] - * - * Command-source entry point. The base command itself requires permission - * level 2 (matches vanilla's own convention for most admin-adjacent - * commands), and RTWrapperAPI.execute() applies the *per-command* level on - * top of that — so a level-2 op typing "/rtwrapper run op Steve" still - * gets rejected because OP requires level 4. - */ -public final class RTWrapperCommand { - - private RTWrapperCommand() {} - - public static void register(CommandDispatcher dispatcher) { - dispatcher.register( - CommandManager.literal("rtwrapper") - .requires(source -> source.hasPermissionLevel(2)) - .then(CommandManager.literal("run") - .then(CommandManager.argument("cmd", StringArgumentType.word()) - .then(CommandManager.argument("args", StringArgumentType.greedyString()) - .executes(ctx -> runWithArgs( - ctx.getSource(), - StringArgumentType.getString(ctx, "cmd"), - StringArgumentType.getString(ctx, "args"))) - ) - .executes(ctx -> runWithArgs( - ctx.getSource(), - StringArgumentType.getString(ctx, "cmd"), - "")) - ) - ) - ); - } - - private static int runWithArgs(ServerCommandSource source, String cmdLiteral, String rawArgs) { - List args = rawArgs.isBlank() - ? List.of() - : Arrays.asList(rawArgs.split(" +")); - - RTDispatchResult result = RTWrapperAPI.execute(cmdLiteral, args, source); - - switch (result.status()) { - case SUCCESS -> { - source.sendFeedback(() -> Text.literal("[RTWrapper] OK: " + cmdLiteral), false); - return 1; - } - case UNKNOWN_COMMAND -> { - source.sendError(Text.literal("[RTWrapper] Unknown or disallowed command: " + cmdLiteral)); - return 0; - } - case PERMISSION_DENIED -> { - source.sendError(Text.literal("[RTWrapper] Permission denied: " + result.message())); - return 0; - } - case COMMAND_FAILED -> { - source.sendError(Text.literal("[RTWrapper] Command failed: " + result.message())); - return 0; - } - default -> { - return 0; - } - } - } -} diff --git a/rtwrapper-fabric/src/main/resources/fabric.mod.json b/rtwrapper-fabric/src/main/resources/fabric.mod.json deleted file mode 100644 index 1271777..0000000 --- a/rtwrapper-fabric/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "id": "rtwrapper", - "version": "${version}", - "name": "RTWrapper", - "description": "Queued, permission-checked native command dispatch API for other mods/datapacks. Fabric reimplementation of the runtoolkit RTWrapper datapack protocol.", - "authors": ["runtoolkit"], - "license": "MIT", - "environment": "server", - "entrypoints": { - "main": ["com.runtoolkit.rtwrapper.RTWrapper"] - }, - "depends": { - "fabricloader": ">=0.16", - "fabric-api": "*", - "minecraft": "~1.21.1" - } -}