Skip to content

Update datapack initialization to use scheduled function calls#18

Closed
SpyC0der77 wants to merge 1 commit into
mainfrom
update-mod
Closed

Update datapack initialization to use scheduled function calls#18
SpyC0der77 wants to merge 1 commit into
mainfrom
update-mod

Conversation

@SpyC0der77

@SpyC0der77 SpyC0der77 commented Jun 11, 2026

Copy link
Copy Markdown
Owner
  • Modified the datapack.init template in multiple version files to replace direct function calls with scheduled function calls, enhancing the initialization process for better timing control.
  • This change applies to versions 1.21.2 through 1.21.11 and 26.1, ensuring consistency across all supported versions.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added /mcs command suite for pack management: enable/disable packs and hot-reload, create packs (global or local scopes), reload packs, and list pack status.
    • Introduced global and world-scoped datapacks with independent configuration and hot-reload control per pack.
    • Added persistent configuration file for Python command path and hot-reload settings.
  • Bug Fixes

    • Fixed initialization timing: datapack initialization functions now execute after a 20-tick delay to ensure proper setup sequencing.
  • Improvements

    • Enhanced hot-reload system with per-pack configuration and selective enforcement.
    • Improved pack discovery and management across multiple pack sources.

- Modified the `datapack.init` template in multiple version files to replace direct function calls with scheduled function calls, enhancing the initialization process for better timing control.
- This change applies to versions 1.21.2 through 1.21.11 and 26.1, ensuring consistency across all supported versions.
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds support for global (server-wide) packs alongside world-specific packs, refactors configuration management into a persistent system, and introduces a comprehensive command infrastructure across all supported platforms (Fabric, Forge, NeoForge).

Changes

Global and World Pack Scoping with Configuration Management

Layer / File(s) Summary
Pack scoping foundation
mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPackSource.java, mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPackEntry.java, mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPaths.java
New McsPackSource enum distinguishes WORLD from GLOBAL packs; McsPackEntry record associates pack folders with sources; McsPaths helpers enable multi-root pack discovery and source-aware datapack naming.
Configuration system
mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCompilerConfig.java (deleted), mod/common/src/main/java/dev/spyc0der/minecraftscript/McsModConfig.java
McsCompilerConfig removed; McsModConfig record replaces it with Python command resolution, global/per-pack hot-reload toggles, and pack enablement state, plus load()/save() for persistent configuration.
Server access extension
mod/common/src/main/java/dev/spyc0der/minecraftscript/McsServerAccess.java
Interface extended with serverDirectory() and executeStartupReload() to support startup initialization and global config directory resolution.
Pack manager refactoring
mod/common/src/main/java/dev/spyc0der/minecraftscript/McsWorldPackManager.java
Constructor now accepts McsModConfig; manager separates worldMcsRoot and globalMcsRoot, discovers McsPackEntry objects across both roots, conditionally compiles/deletes packs based on enablement and hot-reload settings, and exposes command APIs (setHotReloading, setPackEnabled, reload, listPacks).
Runtime state management
mod/common/src/main/java/dev/spyc0der/minecraftscript/McsModRuntime.java
Loads McsModConfig at startup; tracks active McsWorldPackManager and McsServerAccess; exposes packManager() and serverAccess() accessors; centralizes hot-reload state via applyHotReloadState(); calls executeStartupReload() instead of conditional reload.
Pack watcher updates
mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPackWatcher.java
Tracks multiple watchedRoots and registers recursive watchers; resolves pack entries before scheduling refresh; filters by enabled and hot-reload settings; ignores config file changes.
Command infrastructure
mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCommandResult.java, mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCommandService.java
McsCommandResult record encapsulates outcomes (success/message) with factory and acknowledgement methods; McsCommandService wraps pack manager and server operations for command execution.
Starter pack utilities
mod/common/src/main/java/dev/spyc0der/minecraftscript/McsStarterPack.java
Adds STARTER_NAME, packSource() method, text-literal escaping, and isValidPackName() validation.
Compiler migration
mod/common/src/main/java/dev/spyc0der/minecraftscript/ProcessMcsCompiler.java
Updated to use McsModConfig instead of McsCompilerConfig.
Fabric integration
mod/platform/fabric/src/main/java/dev/spyc0der/minecraftscript/fabric/McsFabricMod.java, mod/platform/fabric/src/mc_*/java/dev/spyc0der/minecraftscript/fabric/FabricServerAccess.java, mod/platform/fabric/src/mc_*/java/dev/spyc0der/minecraftscript/fabric/McsFabricCommands.java
Mod initialization registers commands; FabricServerAccess (all MC versions) adds serverDirectory() and refactors reload via thread-aware helper; McsFabricCommands wires Brigadier command tree with pack management subcommands.
Forge integration
mod/platform/forge/src/*/java/dev/spyc0der/minecraftscript/forge/McsForgeMod.java, mod/platform/forge/src/mc_*/java/dev/spyc0der/minecraftscript/forge/ForgeServerAccess.java, mod/platform/forge/src/mc_*/java/dev/spyc0der/minecraftscript/forge/McsForgeCommands.java
Event handler registers commands on RegisterCommandsEvent; ForgeServerAccess (all versions) adds serverDirectory() and thread-aware reload; McsForgeCommands registers /mcs command hierarchy.
NeoForge integration
mod/platform/neoforge/src/*/java/dev/spyc0der/minecraftscript/neoforge/McsNeoForgeMod.java, mod/platform/neoforge/src/mc_*/java/dev/spyc0der/minecraftscript/neoforge/NeoForgeServerAccess.java, mod/platform/neoforge/src/mc_*/java/dev/spyc0der/minecraftscript/neoforge/McsNeoForgeCommands.java
Event bus listener registers commands; NeoForgeServerAccess (all versions) adds serverDirectory() and thread-aware reload; McsNeoForgeCommands wires /mcs command tree.
Datapack initialization timing
minecraft_script/versions/*.json
All template versions (1.21.11, 1.21.2, 1.21.4, 1.21.5, 1.21.6, 1.21.7-8, 1.21.9-10, 26.1) updated to schedule init function after 20 ticks instead of executing immediately.
Test coverage
mod/common/src/test/java/dev/spyc0der/minecraftscript/McsModConfigTest.java, mod/common/src/test/java/dev/spyc0der/minecraftscript/McsStarterPackTest.java, mod/common/src/test/java/dev/spyc0der/minecraftscript/McsWorldPackManagerTest.java
Tests validate config persistence, starter pack generation, and global/world pack discovery and compilation workflows.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • SpyC0der77/Minecraft-Script#17: Both PRs refactor core mod runtime, pack manager, and watcher components to support new pack management workflows and configuration persistence.

Poem

🐰 A rabbit hops through global packs so grand,
World packs beside them, perfectly planned!
Commands now whisper across every mod frame,
Config persists—remember each pack's name! 📦✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Update datapack initialization to use scheduled function calls' is clear, concise, and directly describes the primary change across multiple version files where direct function calls were replaced with scheduled calls.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch update-mod

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

13 issues found across 46 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="minecraft_script/versions/1.21.4.json">

<violation number="1" location="minecraft_script/versions/1.21.4.json:6">
P2: Delaying `user_functions/init` by 20 ticks allows `main` to run before initialization, changing load/tick ordering and risking uninitialized runtime state.</violation>
</file>

<file name="minecraft_script/versions/1.21.11.json">

<violation number="1" location="minecraft_script/versions/1.21.11.json:6">
P2: Scheduling `user_functions/init` 20 ticks later allows `main` to run before initialization completes, introducing an init/main ordering race.</violation>
</file>

<file name="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsModConfig.java">

<violation number="1" location="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsModConfig.java:120">
P2: Record fields are backed by mutable `Set` instances, allowing external mutation of config state after construction.</violation>
</file>

<file name="minecraft_script/versions/26.1.json">

<violation number="1" location="minecraft_script/versions/26.1.json:6">
P1: Delaying `user_functions/init` by 20 ticks allows `main` to run before initialization, causing startup-order regressions.</violation>
</file>

<file name="minecraft_script/versions/1.21.9-10.json">

<violation number="1" location="minecraft_script/versions/1.21.9-10.json:6">
P2: Delaying `user_functions/init` by 20 ticks can run `main` before initialization is complete, breaking prior load-before-tick ordering.</violation>
</file>

<file name="minecraft_script/versions/1.21.6.json">

<violation number="1" location="minecraft_script/versions/1.21.6.json:6">
P2: Deferring `user_functions/init` by 20 ticks can make `main` run before initialization, causing early-tick logic to execute with uninitialized state.</violation>
</file>

<file name="minecraft_script/versions/1.21.5.json">

<violation number="1" location="minecraft_script/versions/1.21.5.json:6">
P1: Delaying `user_functions/init` by 20 ticks allows `main` to run before initialization, creating a startup ordering bug.</violation>
</file>

<file name="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPackWatcher.java">

<violation number="1" location="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPackWatcher.java:145">
P1: Early-returning when `findPackEntry` is empty prevents cleanup on pack deletion, leaving stale generated datapacks.</violation>
</file>

<file name="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCommandService.java">

<violation number="1" location="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCommandService.java:45">
P2: `setPackEnabled` reloads the server even for successful no-op results (already enabled/disabled), causing unnecessary reloads.</violation>
</file>

<file name="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPaths.java">

<violation number="1" location="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPaths.java:74">
P2: Global datapack naming can collide with world pack names (e.g., world `global_x` vs global `x`), causing overwrite/delete of the wrong generated datapack.</violation>
</file>

<file name="mod/platform/fabric/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/fabric/McsFabricCommands.java">

<violation number="1" location="mod/platform/fabric/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/fabric/McsFabricCommands.java:28">
P1: Permission requirement was lowered from owner-level (4) to admin-level (3), exposing mcs management commands to lower-privileged operators.</violation>
</file>

<file name="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsWorldPackManager.java">

<violation number="1" location="mod/common/src/main/java/dev/spyc0der/minecraftscript/McsWorldPackManager.java:160">
P2: `refreshPack(Path)` ignores the provided folder path and looks up by pack name only, which can refresh the wrong pack when world/global names collide.</violation>
</file>

<file name="minecraft_script/versions/1.21.2.json">

<violation number="1" location="minecraft_script/versions/1.21.2.json:6">
P1: Delaying `user_functions/init` by 20 ticks allows `main` to run before initialization, creating an init-order race after reload.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

"pack.mcmeta": "{\n \"pack\": {\n \"min_format\": [{{formatMinMajor}}, {{formatMinMinor}}],\n \"max_format\": [{{formatMaxMajor}}, {{formatMaxMinor}}],\n \"description\": \"{{packDescription}}\"\n }\n}",
"datapack.init.header": "################################################################\n# #\n# default init.mcfunction file generated by Minecraft-Script #\n# #\n################################################################\n",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Delaying user_functions/init by 20 ticks allows main to run before initialization, causing startup-order regressions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At minecraft_script/versions/26.1.json, line 6:

<comment>Delaying `user_functions/init` by 20 ticks allows `main` to run before initialization, causing startup-order regressions.</comment>

<file context>
@@ -3,7 +3,7 @@
     "pack.mcmeta": "{\n    \"pack\": {\n        \"min_format\": [{{formatMinMajor}}, {{formatMinMinor}}],\n        \"max_format\": [{{formatMaxMajor}}, {{formatMaxMinor}}],\n        \"description\": \"{{packDescription}}\"\n    }\n}",
     "datapack.init.header": "################################################################\n#                                                              #\n#  default init.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
-    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
+    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
     "datapack.main.header": "################################################################\n#                                                              #\n#  default main.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
     "datapack.main": "function {{datapack_id}}:user_functions/main",
</file context>
Suggested change
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
Fix with cubic

"pack.mcmeta": "{\n \"pack\": {\n \"pack_format\": {{pack_format}},\n \"supported_formats\": [71, 71],\n \"description\": \"{{packDescription}}\"\n }\n}",
"datapack.init.header": "################################################################\n# #\n# default init.mcfunction file generated by Minecraft-Script #\n# #\n################################################################\n",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Delaying user_functions/init by 20 ticks allows main to run before initialization, creating a startup ordering bug.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At minecraft_script/versions/1.21.5.json, line 6:

<comment>Delaying `user_functions/init` by 20 ticks allows `main` to run before initialization, creating a startup ordering bug.</comment>

<file context>
@@ -3,7 +3,7 @@
     "pack.mcmeta": "{\n    \"pack\": {\n        \"pack_format\": {{pack_format}},\n        \"supported_formats\": [71, 71],\n        \"description\": \"{{packDescription}}\"\n    }\n}",
     "datapack.init.header": "################################################################\n#                                                              #\n#  default init.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
-    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
+    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
     "datapack.main.header": "################################################################\n#                                                              #\n#  default main.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
     "datapack.main": "function {{datapack_id}}:user_functions/main",
</file context>
Suggested change
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
Fix with cubic

Comment on lines +145 to +149
if (entry.isEmpty()
|| !packManager.isPackEnabled(entry.get())
|| !packManager.isHotReloadEnabledForPack(entry.get())) {
return;
}

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Early-returning when findPackEntry is empty prevents cleanup on pack deletion, leaving stale generated datapacks.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPackWatcher.java, line 145:

<comment>Early-returning when `findPackEntry` is empty prevents cleanup on pack deletion, leaving stale generated datapacks.</comment>

<file context>
@@ -136,6 +140,18 @@ private void scheduleFullScan() {
         Path normalized = packFolder.toAbsolutePath().normalize();
+        try {
+            Optional<McsPackEntry> entry = packManager.findPackEntry(packFolder.getFileName().toString());
+            if (entry.isEmpty()
+                    || !packManager.isPackEnabled(entry.get())
+                    || !packManager.isHotReloadEnabledForPack(entry.get())) {
</file context>
Suggested change
if (entry.isEmpty()
|| !packManager.isPackEnabled(entry.get())
|| !packManager.isHotReloadEnabledForPack(entry.get())) {
return;
}
if (entry.isPresent()
&& (!packManager.isPackEnabled(entry.get())
|| !packManager.isHotReloadEnabledForPack(entry.get()))) {
return;
}
Fix with cubic


public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
dispatcher.register(Commands.literal("mcs")
.requires(Commands.hasPermission(Commands.LEVEL_ADMINS))

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Permission requirement was lowered from owner-level (4) to admin-level (3), exposing mcs management commands to lower-privileged operators.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mod/platform/fabric/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/fabric/McsFabricCommands.java, line 28:

<comment>Permission requirement was lowered from owner-level (4) to admin-level (3), exposing mcs management commands to lower-privileged operators.</comment>

<file context>
@@ -0,0 +1,113 @@
+
+    public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
+        dispatcher.register(Commands.literal("mcs")
+                .requires(Commands.hasPermission(Commands.LEVEL_ADMINS))
+                .then(Commands.literal("hotreloading")
+                        .then(Commands.literal("enable")
</file context>
Suggested change
.requires(Commands.hasPermission(Commands.LEVEL_ADMINS))
.requires(Commands.hasPermission(Commands.LEVEL_OWNERS))
Fix with cubic

"pack.mcmeta": "{\n \"pack\": {\n \"pack_format\": {{pack_format}},\n \"supported_formats\": [48, 57],\n \"description\": \"{{packDescription}}\"\n }\n}",
"datapack.init.header": "################################################################\n# #\n# default init.mcfunction file generated by Minecraft-Script #\n# #\n################################################################\n",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Delaying user_functions/init by 20 ticks allows main to run before initialization, creating an init-order race after reload.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At minecraft_script/versions/1.21.2.json, line 6:

<comment>Delaying `user_functions/init` by 20 ticks allows `main` to run before initialization, creating an init-order race after reload.</comment>

<file context>
@@ -3,7 +3,7 @@
     "pack.mcmeta": "{\n    \"pack\": {\n        \"pack_format\": {{pack_format}},\n        \"supported_formats\": [48, 57],\n        \"description\": \"{{packDescription}}\"\n    }\n}",
     "datapack.init.header": "################################################################\n#                                                              #\n#  default init.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
-    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
+    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
     "datapack.main.header": "################################################################\n#                                                              #\n#  default main.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
     "datapack.main": "function {{datapack_id}}:user_functions/main",
</file context>
Suggested change
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
Fix with cubic

"pack.mcmeta": "{\n \"pack\": {\n \"min_format\": [{{formatMinMajor}}, {{formatMinMinor}}],\n \"max_format\": [{{formatMaxMajor}}, {{formatMaxMinor}}],\n \"description\": \"{{packDescription}}\"\n }\n}",
"datapack.init.header": "################################################################\n# #\n# default init.mcfunction file generated by Minecraft-Script #\n# #\n################################################################\n",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Delaying user_functions/init by 20 ticks can run main before initialization is complete, breaking prior load-before-tick ordering.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At minecraft_script/versions/1.21.9-10.json, line 6:

<comment>Delaying `user_functions/init` by 20 ticks can run `main` before initialization is complete, breaking prior load-before-tick ordering.</comment>

<file context>
@@ -3,7 +3,7 @@
     "pack.mcmeta": "{\n    \"pack\": {\n        \"min_format\": [{{formatMinMajor}}, {{formatMinMinor}}],\n        \"max_format\": [{{formatMaxMajor}}, {{formatMaxMinor}}],\n        \"description\": \"{{packDescription}}\"\n    }\n}",
     "datapack.init.header": "################################################################\n#                                                              #\n#  default init.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
-    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
+    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
     "datapack.main.header": "################################################################\n#                                                              #\n#  default main.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
     "datapack.main": "function {{datapack_id}}:user_functions/main",
</file context>
Suggested change
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
Fix with cubic

"pack.mcmeta": "{\n \"pack\": {\n \"pack_format\": {{pack_format}},\n \"supported_formats\": [80, 80],\n \"description\": \"{{packDescription}}\"\n }\n}",
"datapack.init.header": "################################################################\n# #\n# default init.mcfunction file generated by Minecraft-Script #\n# #\n################################################################\n",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Deferring user_functions/init by 20 ticks can make main run before initialization, causing early-tick logic to execute with uninitialized state.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At minecraft_script/versions/1.21.6.json, line 6:

<comment>Deferring `user_functions/init` by 20 ticks can make `main` run before initialization, causing early-tick logic to execute with uninitialized state.</comment>

<file context>
@@ -3,7 +3,7 @@
     "pack.mcmeta": "{\n    \"pack\": {\n        \"pack_format\": {{pack_format}},\n        \"supported_formats\": [80, 80],\n        \"description\": \"{{packDescription}}\"\n    }\n}",
     "datapack.init.header": "################################################################\n#                                                              #\n#  default init.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
-    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
+    "datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
     "datapack.main.header": "################################################################\n#                                                              #\n#  default main.mcfunction file generated by Minecraft-Script  #\n#                                                              #\n################################################################\n",
     "datapack.main": "function {{datapack_id}}:user_functions/main",
</file context>
Suggested change
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nschedule function {{datapack_id}}:user_functions/init 20t",
"datapack.init": "scoreboard objectives add mcs_math dummy \"Minecraft-Script Math\"\nscoreboard objectives add mcs_click {{clickScoreboardCriterion}} \"Minecraft-Script Click\"\n\nfunction {{datapack_id}}:user_functions/init",
Fix with cubic

return McsCommandResult.error("Minecraft Script is not active on this server.");
}
try {
McsCommandResult result = packManager.setPackEnabled(packName, enabled);

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: setPackEnabled reloads the server even for successful no-op results (already enabled/disabled), causing unnecessary reloads.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCommandService.java, line 45:

<comment>`setPackEnabled` reloads the server even for successful no-op results (already enabled/disabled), causing unnecessary reloads.</comment>

<file context>
@@ -0,0 +1,115 @@
+            return McsCommandResult.error("Minecraft Script is not active on this server.");
+        }
+        try {
+            McsCommandResult result = packManager.setPackEnabled(packName, enabled);
+            if (result.success()) {
+                serverAccess.executeReload();
</file context>
Fix with cubic

public static String generatedDatapackName(Path packFolder, McsPackSource source) {
String sanitized = sanitizePackFolderName(packFolder.getFileName().toString());
if (source == McsPackSource.GLOBAL) {
return GENERATED_PREFIX + "global_" + sanitized;

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Global datapack naming can collide with world pack names (e.g., world global_x vs global x), causing overwrite/delete of the wrong generated datapack.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPaths.java, line 74:

<comment>Global datapack naming can collide with world pack names (e.g., world `global_x` vs global `x`), causing overwrite/delete of the wrong generated datapack.</comment>

<file context>
@@ -42,6 +65,18 @@ public static String sanitizePackFolderName(String folderName) {
+    public static String generatedDatapackName(Path packFolder, McsPackSource source) {
+        String sanitized = sanitizePackFolderName(packFolder.getFileName().toString());
+        if (source == McsPackSource.GLOBAL) {
+            return GENERATED_PREFIX + "global_" + sanitized;
+        }
+        return GENERATED_PREFIX + sanitized;
</file context>
Suggested change
return GENERATED_PREFIX + "global_" + sanitized;
return GENERATED_PREFIX + "global__" + sanitized;
Fix with cubic

public boolean refreshPack(Path packFolder) {
Path packFile = packFolder.resolve(McsPaths.PACK_FILE);
try {
Optional<McsPackEntry> entry = findPackEntry(packFolder.getFileName().toString());

@cubic-dev-ai cubic-dev-ai Bot Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: refreshPack(Path) ignores the provided folder path and looks up by pack name only, which can refresh the wrong pack when world/global names collide.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mod/common/src/main/java/dev/spyc0der/minecraftscript/McsWorldPackManager.java, line 160:

<comment>`refreshPack(Path)` ignores the provided folder path and looks up by pack name only, which can refresh the wrong pack when world/global names collide.</comment>

<file context>
@@ -75,15 +156,45 @@ public void notifyPackChangePending(Path packFolder) {
     public boolean refreshPack(Path packFolder) {
-        Path packFile = packFolder.resolve(McsPaths.PACK_FILE);
+        try {
+            Optional<McsPackEntry> entry = findPackEntry(packFolder.getFileName().toString());
+            if (entry.isEmpty()) {
+                return deleteGeneratedPack(packFolder, resolvePackSource(packFolder));
</file context>
Suggested change
Optional<McsPackEntry> entry = findPackEntry(packFolder.getFileName().toString());
Optional<McsPackEntry> entry = discoverPackEntries().stream()
.filter(candidate -> candidate.packFolder().toAbsolutePath().normalize()
.equals(packFolder.toAbsolutePath().normalize()))
.findFirst();
Fix with cubic

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
mod/common/src/main/java/dev/spyc0der/minecraftscript/McsStarterPack.java (2)

29-31: 💤 Low value

Consider adding a comment explaining the escape order.

The method correctly escapes backslashes before quotes, which is essential to avoid double-escaping. While the implementation is correct, a brief comment would help future maintainers understand why order matters.

📝 Suggested comment
 public static String escapeForTextLiteral(String value) {
+    // Backslashes must be escaped first to avoid double-escaping quotes
     return value.replace("\\", "\\\\").replace("\"", "\\\"");
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mod/common/src/main/java/dev/spyc0der/minecraftscript/McsStarterPack.java`
around lines 29 - 31, Add a brief comment above the
McsStarterPack.escapeForTextLiteral method explaining that backslashes are
escaped first to prevent newly introduced backslashes from being re-escaped when
quotes are processed (i.e., ".replace("\\", "\\\\") before .replace("\"",
"\\\"") ensures correct escaping), so future maintainers understand the required
order and rationale.

33-49: 💤 Low value

Consider adding filename length validation.

The method validates forbidden characters and reserved names, but doesn't check for filename length limits. Most filesystems support up to 255 bytes, but very long pack names could theoretically fail during file creation. While unlikely in practice, adding a length check would make the validation more robust.

🛡️ Suggested length check
 public static boolean isValidPackName(String packName) {
     if (packName == null || packName.isBlank()) {
         return false;
     }
     if (packName.equals(".") || packName.equals("..")) {
         return false;
     }
+    if (packName.length() > 200) {  // Leave margin below filesystem limit
+        return false;
+    }
     for (int index = 0; index < packName.length(); index++) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mod/common/src/main/java/dev/spyc0der/minecraftscript/McsStarterPack.java`
around lines 33 - 49, The isValidPackName method currently checks null/blank,
reserved names, and forbidden characters but lacks a filename-length guard;
update isValidPackName to reject names exceeding typical filesystem limits by
returning false when the UTF-8 byte length of packName (use
packName.getBytes(StandardCharsets.UTF_8).length) is greater than 255 (or choose
a configurable MAX_NAME_BYTES constant), and ensure to import
java.nio.charset.StandardCharsets and introduce a MAX_NAME_BYTES constant used
in the check so very long names are rejected early.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mod/common/src/main/java/dev/spyc0der/minecraftscript/McsModConfig.java`:
- Around line 32-33: The record McsModConfig currently assigns mutable
LinkedHashSet instances returned by normalizePackSet to its fields
hotReloadDisabledPacks and disabledPacks (and similar assignments later in the
class), exposing them via accessors; instead, wrap the normalized sets with an
unmodifiable wrapper before storing to prevent external mutation—i.e., replace
direct assignments like hotReloadDisabledPacks = normalizePackSet(...) and
disabledPacks = normalizePackSet(...) (and the other similar assignments around
the other constructors/initializers) with assignments that create and store
Collections.unmodifiableSet(new LinkedHashSet<>(normalizePackSet(...))) (or
equivalent) so callers receive immutable views while preserving iteration order.
- Around line 39-43: The config file read in McsModConfig currently swallows
IOException when loading properties (the try-with-resources around
properties.load(reader)), which hides corrupted/unreadable configs; change this
to either rethrow the IOException (or wrap in a RuntimeException) or at minimum
log the error via the module's logger before continuing so startup can surface
failures—locate the Files.isRegularFile(configFile) block in McsModConfig and
replace the empty catch of IOException with code that logs the exception
(including message and stack trace) and/or rethrows it to trigger the startup
error path.

In
`@mod/platform/forge/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/forge/McsForgeCommands.java`:
- Line 28: The Forge command registration in McsForgeCommands uses
.requires(Commands.hasPermission(Commands.LEVEL_ADMINS)) which diverges from
other variants; change the requirement to the same predicate used in mc_1_21_9
and mc_legacy by replacing it with a lambda that checks the numeric permission
(source -> source.hasPermission(4)) on the command builder used when registering
the /mcs admin command tree (locate the CommandDispatcher/
LiteralArgumentBuilder creation in McsForgeCommands and update the .requires
call).

---

Nitpick comments:
In `@mod/common/src/main/java/dev/spyc0der/minecraftscript/McsStarterPack.java`:
- Around line 29-31: Add a brief comment above the
McsStarterPack.escapeForTextLiteral method explaining that backslashes are
escaped first to prevent newly introduced backslashes from being re-escaped when
quotes are processed (i.e., ".replace("\\", "\\\\") before .replace("\"",
"\\\"") ensures correct escaping), so future maintainers understand the required
order and rationale.
- Around line 33-49: The isValidPackName method currently checks null/blank,
reserved names, and forbidden characters but lacks a filename-length guard;
update isValidPackName to reject names exceeding typical filesystem limits by
returning false when the UTF-8 byte length of packName (use
packName.getBytes(StandardCharsets.UTF_8).length) is greater than 255 (or choose
a configurable MAX_NAME_BYTES constant), and ensure to import
java.nio.charset.StandardCharsets and introduce a MAX_NAME_BYTES constant used
in the check so very long names are rejected early.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d6e83708-20bd-4914-a098-5fb67ad11ebc

📥 Commits

Reviewing files that changed from the base of the PR and between e060d4d and f26920f.

📒 Files selected for processing (46)
  • minecraft_script/versions/1.21.11.json
  • minecraft_script/versions/1.21.2.json
  • minecraft_script/versions/1.21.4.json
  • minecraft_script/versions/1.21.5.json
  • minecraft_script/versions/1.21.6.json
  • minecraft_script/versions/1.21.7-8.json
  • minecraft_script/versions/1.21.9-10.json
  • minecraft_script/versions/26.1.json
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCommandResult.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCommandService.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCompilerConfig.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsModConfig.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsModRuntime.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPackEntry.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPackSource.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPackWatcher.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsPaths.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsServerAccess.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsStarterPack.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsWorldPackManager.java
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/ProcessMcsCompiler.java
  • mod/common/src/test/java/dev/spyc0der/minecraftscript/McsModConfigTest.java
  • mod/common/src/test/java/dev/spyc0der/minecraftscript/McsStarterPackTest.java
  • mod/common/src/test/java/dev/spyc0der/minecraftscript/McsWorldPackManagerTest.java
  • mod/platform/fabric/src/main/java/dev/spyc0der/minecraftscript/fabric/McsFabricMod.java
  • mod/platform/fabric/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/fabric/FabricServerAccess.java
  • mod/platform/fabric/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/fabric/McsFabricCommands.java
  • mod/platform/fabric/src/mc_1_21_9/java/dev/spyc0der/minecraftscript/fabric/FabricServerAccess.java
  • mod/platform/fabric/src/mc_1_21_9/java/dev/spyc0der/minecraftscript/fabric/McsFabricCommands.java
  • mod/platform/fabric/src/mc_legacy/java/dev/spyc0der/minecraftscript/fabric/FabricServerAccess.java
  • mod/platform/fabric/src/mc_legacy/java/dev/spyc0der/minecraftscript/fabric/McsFabricCommands.java
  • mod/platform/forge/src/forge_legacy/java/dev/spyc0der/minecraftscript/forge/McsForgeMod.java
  • mod/platform/forge/src/forge_modern/java/dev/spyc0der/minecraftscript/forge/McsForgeMod.java
  • mod/platform/forge/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/forge/ForgeServerAccess.java
  • mod/platform/forge/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/forge/McsForgeCommands.java
  • mod/platform/forge/src/mc_1_21_9/java/dev/spyc0der/minecraftscript/forge/ForgeServerAccess.java
  • mod/platform/forge/src/mc_1_21_9/java/dev/spyc0der/minecraftscript/forge/McsForgeCommands.java
  • mod/platform/forge/src/mc_legacy/java/dev/spyc0der/minecraftscript/forge/ForgeServerAccess.java
  • mod/platform/forge/src/mc_legacy/java/dev/spyc0der/minecraftscript/forge/McsForgeCommands.java
  • mod/platform/neoforge/src/main/java/dev/spyc0der/minecraftscript/neoforge/McsNeoForgeMod.java
  • mod/platform/neoforge/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/neoforge/McsNeoForgeCommands.java
  • mod/platform/neoforge/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/neoforge/NeoForgeServerAccess.java
  • mod/platform/neoforge/src/mc_1_21_9/java/dev/spyc0der/minecraftscript/neoforge/McsNeoForgeCommands.java
  • mod/platform/neoforge/src/mc_1_21_9/java/dev/spyc0der/minecraftscript/neoforge/NeoForgeServerAccess.java
  • mod/platform/neoforge/src/mc_legacy/java/dev/spyc0der/minecraftscript/neoforge/McsNeoForgeCommands.java
  • mod/platform/neoforge/src/mc_legacy/java/dev/spyc0der/minecraftscript/neoforge/NeoForgeServerAccess.java
💤 Files with no reviewable changes (1)
  • mod/common/src/main/java/dev/spyc0der/minecraftscript/McsCompilerConfig.java

Comment on lines +32 to +33
hotReloadDisabledPacks = normalizePackSet(hotReloadDisabledPacks);
disabledPacks = normalizePackSet(disabledPacks);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Seal Set fields against external mutation.

hotReloadDisabledPacks/disabledPacks are stored as mutable LinkedHashSets and exposed via record accessors, so callers can mutate config state after creation. Wrap normalized/parsed sets with unmodifiable copies before storing.

Proposed fix
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.LinkedHashSet;
@@
     private static Set<String> normalizePackSet(Set<String> packNames) {
         if (packNames == null || packNames.isEmpty()) {
             return Set.of();
         }
-        return packNames.stream()
+        Set<String> normalized = packNames.stream()
                 .map(McsModConfig::normalizePackName)
                 .filter(name -> !name.isBlank())
                 .collect(Collectors.toCollection(LinkedHashSet::new));
+        return Collections.unmodifiableSet(normalized);
     }
@@
     private static Set<String> parsePackSet(String value) {
         if (value == null || value.isBlank()) {
             return Set.of();
         }
-        return Arrays.stream(value.split(","))
+        Set<String> parsed = Arrays.stream(value.split(","))
                 .map(McsModConfig::normalizePackName)
                 .filter(name -> !name.isBlank())
                 .collect(Collectors.toCollection(LinkedHashSet::new));
+        return Collections.unmodifiableSet(parsed);
     }

Also applies to: 113-121, 130-138

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mod/common/src/main/java/dev/spyc0der/minecraftscript/McsModConfig.java`
around lines 32 - 33, The record McsModConfig currently assigns mutable
LinkedHashSet instances returned by normalizePackSet to its fields
hotReloadDisabledPacks and disabledPacks (and similar assignments later in the
class), exposing them via accessors; instead, wrap the normalized sets with an
unmodifiable wrapper before storing to prevent external mutation—i.e., replace
direct assignments like hotReloadDisabledPacks = normalizePackSet(...) and
disabledPacks = normalizePackSet(...) (and the other similar assignments around
the other constructors/initializers) with assignments that create and store
Collections.unmodifiableSet(new LinkedHashSet<>(normalizePackSet(...))) (or
equivalent) so callers receive immutable views while preserving iteration order.

Comment on lines +39 to +43
if (Files.isRegularFile(configFile)) {
try (Reader reader = Files.newBufferedReader(configFile)) {
properties.load(reader);
} catch (IOException ignored) {
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Do not silently ignore config read failures.

On Line 42, IOException is swallowed; that hides corrupted/unreadable config and prevents the startup error path from surfacing the issue. Propagate (or at least log) the exception so operator-facing diagnostics work.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mod/common/src/main/java/dev/spyc0der/minecraftscript/McsModConfig.java`
around lines 39 - 43, The config file read in McsModConfig currently swallows
IOException when loading properties (the try-with-resources around
properties.load(reader)), which hides corrupted/unreadable configs; change this
to either rethrow the IOException (or wrap in a RuntimeException) or at minimum
log the error via the module's logger before continuing so startup can surface
failures—locate the Files.isRegularFile(configFile) block in McsModConfig and
replace the empty catch of IOException with code that logs the exception
(including message and stack trace) and/or rethrows it to trigger the startup
error path.


public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
dispatcher.register(Commands.literal("mcs")
.requires(Commands.hasPermission(Commands.LEVEL_ADMINS))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify Forge command permission gates are consistent across versioned command registrars.
fd McsForgeCommands.java mod/platform/forge/src -tf | sort | while read -r file; do
  echo "== $file =="
  rg -n '\.requires\(' "$file"
done

Repository: SpyC0der77/Minecraft-Script

Length of output: 579


Align Forge command authorization across variants.

In McsForgeCommands.java line 28, mc_1_21_11 uses .requires(Commands.hasPermission(Commands.LEVEL_ADMINS)), while mc_1_21_9 and mc_legacy use .requires(source -> source.hasPermission(4)), creating version-dependent admin access control for the same /mcs admin command tree.

Suggested minimal alignment (match the other variants)
-                .requires(Commands.hasPermission(Commands.LEVEL_ADMINS))
+                .requires(source -> source.hasPermission(4))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@mod/platform/forge/src/mc_1_21_11/java/dev/spyc0der/minecraftscript/forge/McsForgeCommands.java`
at line 28, The Forge command registration in McsForgeCommands uses
.requires(Commands.hasPermission(Commands.LEVEL_ADMINS)) which diverges from
other variants; change the requirement to the same predicate used in mc_1_21_9
and mc_legacy by replacing it with a lambda that checks the numeric permission
(source -> source.hasPermission(4)) on the command builder used when registering
the /mcs admin command tree (locate the CommandDispatcher/
LiteralArgumentBuilder creation in McsForgeCommands and update the .requires
call).

@SpyC0der77 SpyC0der77 closed this Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant