├── docs
├── version.json
└── index.html
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── src
└── main
│ ├── resources
│ ├── assets
│ │ └── mcfdebugger
│ │ │ ├── icon.png
│ │ │ └── lang
│ │ │ ├── zh_cn.json
│ │ │ └── en_us.json
│ ├── mcfdebugger.mixins.json
│ └── fabric.mod.json
│ └── java
│ └── com
│ └── hb
│ └── mcfdebugger
│ ├── mixinHelpers
│ ├── HackedElement.java
│ ├── SendSyntaxError.java
│ ├── SendFunctionState.java
│ ├── ReadCommandSource.java
│ ├── SendCommandState.java
│ └── FakeCommandFunctionCreate.java
│ ├── config
│ ├── ConfigHolder.java
│ ├── LoadConfig.java
│ └── ConfigManager.java
│ ├── mixin
│ ├── CommandSourceHook.java
│ ├── SetCommandIndex.java
│ ├── ExampleMixin.java
│ ├── ServerLoad.java
│ ├── regcmd.java
│ ├── ServerCommandSourceHook.java
│ ├── FunctionCommandHook.java
│ ├── DebugHook.java
│ ├── ErrorHook.java
│ └── FunctionLoaderHook.java
│ ├── PauseWaiter.java
│ ├── SendCmdObj.java
│ ├── SimpleCmdObj.java
│ ├── DebugThread.java
│ ├── commandHelpers
│ ├── GetEntity.java
│ └── ReadScoreboard.java
│ ├── wsServer.java
│ ├── McfDebugger.java
│ ├── commands
│ ├── DebuggerConfigCommand.java
│ └── DebuggerCommand.java
│ └── wsCommandParser.java
├── settings.gradle
├── .gitignore
├── gradle.properties
├── LICENSE
├── README_zh_cn.md
├── gradlew.bat
├── README.md
├── yarn.lock
└── gradlew
/docs/version.json:
--------------------------------------------------------------------------------
1 | {
2 | "now_version": "1.0.4",
3 | "now_version_id":4
4 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeBlack/McfDebugger_Mod/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/src/main/resources/assets/mcfdebugger/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeBlack/McfDebugger_Mod/HEAD/src/main/resources/assets/mcfdebugger/icon.png
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 | Doc Test!
9 |
10 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | maven {
4 | name = 'Fabric'
5 | url = 'https://maven.fabricmc.net/'
6 | }
7 | gradlePluginPortal()
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/src/main/resources/assets/mcfdebugger/lang/zh_cn.json:
--------------------------------------------------------------------------------
1 | {
2 | "mcfdebugger.enabled": "函数调试器已启用.",
3 | "mcfdebugger.disabled": "函数调试器已禁用.",
4 | "mcfdebugger.set_port": "函数调试器的Websocket服务器端口已设置为%d.",
5 | "mcfdebugger.set_timeOut": "设置超时时间:%d秒.",
6 | "mcfdebugger.reload_command": "接收到调试器发来的重载指令."
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # gradle
2 |
3 | .gradle/
4 | build/
5 | out/
6 | classes/
7 |
8 | # eclipse
9 |
10 | *.launch
11 |
12 | # idea
13 |
14 | .idea/
15 | *.iml
16 | *.ipr
17 | *.iws
18 |
19 | # vscode
20 |
21 | .settings/
22 | .vscode/
23 | bin/
24 | .classpath
25 | .project
26 |
27 | # macos
28 |
29 | *.DS_Store
30 |
31 | # fabric
32 |
33 | run/
34 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixinHelpers/HackedElement.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixinHelpers;
2 |
3 | import net.minecraft.server.function.CommandFunction;
4 |
5 | public abstract class HackedElement implements CommandFunction.Element {
6 | public String funNamespace;
7 | public String funPath;
8 | public int cmdIndex;
9 | public boolean isLastCmd;
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/resources/assets/mcfdebugger/lang/en_us.json:
--------------------------------------------------------------------------------
1 | {
2 | "mcfdebugger.enabled": "Function debugger has been enabled.",
3 | "mcfdebugger.disabled": "Function debugger has been disabled.",
4 | "mcfdebugger.set_port": "The Websocket server port of function debugger has been set to port:%d",
5 | "mcfdebugger.set_timeOut": "Set timeout:%d s",
6 | "mcfdebugger.reload_command": "Debugger sent a reload command."
7 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Done to increase the memory available to gradle.
2 | org.gradle.jvmargs=-Xmx1G
3 |
4 | # Fabric Properties
5 | # check these on https://fabricmc.net/versions.html
6 | minecraft_version=1.17.1
7 | yarn_mappings=1.17.1+build.35
8 | loader_version=0.11.6
9 |
10 | # Dependencies
11 | fabric_version=0.37.2+1.17
12 |
13 | # Mod Properties
14 | mod_version = 1.1.1
15 | maven_group = com.aigch.hugeblack
16 | archives_base_name = mcfdebugger
17 |
18 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/config/ConfigHolder.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.config;
2 |
3 | public class ConfigHolder {
4 | public static String debuggerMode="none";
5 | public static boolean isThisModDebugging=false;
6 | public static boolean nonStopOnException = false;
7 | public static boolean executeCmdStopAtSuccess=false;
8 | public static void resetFeature(){
9 | nonStopOnException = false;
10 | isThisModDebugging=false;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/CommandSourceHook.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 |
3 | import net.minecraft.server.command.ServerCommandSource;
4 | import org.spongepowered.asm.mixin.Final;
5 | import org.spongepowered.asm.mixin.Mixin;
6 | import org.spongepowered.asm.mixin.Shadow;
7 |
8 | @Mixin(ServerCommandSource.class)
9 | public class CommandSourceHook {
10 | @Shadow @Final int level;
11 | public int fakeGetLevel() {
12 | return this.level;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/resources/mcfdebugger.mixins.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": true,
3 | "minVersion": "0.8",
4 | "package": "com.hb.mcfdebugger.mixin",
5 | "compatibilityLevel": "JAVA_8",
6 | "mixins": [
7 | "regcmd",
8 | "DebugHook",
9 | "SetCommandIndex",
10 | "FunctionLoaderHook",
11 | "ErrorHook",
12 | "ServerLoad",
13 | "FunctionCommandHook",
14 | "ServerCommandSourceHook",
15 | "CommandSourceHook"
16 | ],
17 | "client": [
18 | "ExampleMixin"
19 | ],
20 | "injectors": {
21 | "defaultRequire": 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/SetCommandIndex.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 |
3 | import com.hb.mcfdebugger.McfDebugger;
4 | import net.minecraft.server.function.CommandFunction;
5 | import org.spongepowered.asm.mixin.Mixin;
6 |
7 | @Mixin(CommandFunction.CommandElement.class)
8 | public abstract class SetCommandIndex {
9 | public String funNamespace= McfDebugger.nowCmd.funNamespace;
10 | public String funPath= McfDebugger.nowCmd.funPath;
11 | public int cmdIndex= McfDebugger.nowCmd.cmdIndex;
12 | public boolean isLastCmd=McfDebugger.nowIsLastCmd;
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/ExampleMixin.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 |
3 | import net.minecraft.client.gui.screen.TitleScreen;
4 | import org.spongepowered.asm.mixin.Mixin;
5 | import org.spongepowered.asm.mixin.injection.At;
6 | import org.spongepowered.asm.mixin.injection.Inject;
7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
8 |
9 | import static com.hb.mcfdebugger.McfDebugger.LOG;
10 |
11 | @Mixin(TitleScreen.class)
12 | public class ExampleMixin {
13 | @Inject(at = @At("HEAD"), method = "init()V")
14 | private void init(CallbackInfo info) {
15 | //LOG("This line is printed by an example mod mixin!");
16 | }
17 | }
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/PauseWaiter.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger;
2 |
3 | import com.hb.mcfdebugger.config.ConfigHolder;
4 |
5 | public class PauseWaiter {
6 | public static void WaitForNext(){
7 | DebugThread.nextStep = false;
8 | while (!DebugThread.nextStep) {
9 | try {
10 | if(DebugThread.wsserver.getConnections().size()<=0){
11 | ConfigHolder.debuggerMode="none";
12 | break;
13 | }
14 | Thread.sleep(100);
15 | } catch (InterruptedException e) {
16 | e.printStackTrace();
17 | }
18 | }
19 | DebugThread.nextStep = false;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixinHelpers/SendSyntaxError.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixinHelpers;
2 |
3 | import com.hb.mcfdebugger.DebugThread;
4 | import com.hb.mcfdebugger.McfDebugger;
5 |
6 | import java.util.LinkedHashMap;
7 | import java.util.Map;
8 |
9 | public class SendSyntaxError {
10 | public static void send(IllegalArgumentException e){
11 | Map errorMap = new LinkedHashMap<>();
12 | errorMap.put("namespace",McfDebugger.nowCmd.funNamespace);
13 | errorMap.put("path",McfDebugger.nowCmd.funPath);
14 | errorMap.put("cmdIndex", String.valueOf(McfDebugger.nowCmd.cmdIndex));
15 | errorMap.put("errorMsg", e.getMessage());
16 | DebugThread.sendObjMsgToDebugger(errorMap,"functionSyntaxError");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/ServerLoad.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 |
3 | import com.hb.mcfdebugger.McfDebugger;
4 | import com.hb.mcfdebugger.config.LoadConfig;
5 | import net.minecraft.server.MinecraftServer;
6 | import net.minecraft.util.WorldSavePath;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.injection.At;
9 | import org.spongepowered.asm.mixin.injection.Inject;
10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
11 |
12 | @Mixin(MinecraftServer.class)
13 | public class ServerLoad {
14 | @Inject(method = "loadWorld", at = @At("HEAD"))
15 | private void serverLoaded(CallbackInfo ci)
16 | {
17 | McfDebugger.mcServer=(MinecraftServer)(Object)this;
18 | LoadConfig.load();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/config/LoadConfig.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.config;
2 |
3 | import com.hb.mcfdebugger.McfDebugger;
4 | import net.minecraft.util.WorldSavePath;
5 |
6 | public class LoadConfig {
7 | public static void load(){
8 | McfDebugger.configManager=ConfigManager.getConfigManager();
9 | McfDebugger.configManager.passConfigFile(McfDebugger.mcServer.getSavePath(WorldSavePath.ROOT).resolve("mcfDebugger_config.json").toFile());
10 | McfDebugger.configManager.setupConfig();
11 | McfDebugger.configList=McfDebugger.configManager.loadConfig();
12 | if(McfDebugger.configList.get("enable")==1){
13 | McfDebugger.thread.restartWsServer(McfDebugger.configList.get("port"),McfDebugger.configList.get("timeOut"));
14 | }else{
15 | McfDebugger.thread.stopWsServer();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/SendCmdObj.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger;
2 |
3 | import org.jetbrains.annotations.Nullable;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | public class SendCmdObj{
9 | public String funNamespace;
10 | public String funPath;
11 | public String cmdContent;
12 | public Integer cmdIndex;
13 | public boolean pause;
14 | public String exception="";
15 | public Map source=new HashMap<>();
16 | public SendCmdObj(String funNamespace, String funPath, Integer cmdIndex, String cmdContent, Boolean pause, @Nullable Map source){
17 | this.funNamespace=funNamespace;
18 | this.cmdContent=cmdContent;
19 | this.funPath=funPath;
20 | this.cmdIndex=cmdIndex;
21 | this.pause=pause;
22 | if(source!=null){this.source=source;}
23 | }
24 | public SimpleCmdObj toSimple(){
25 | return new SimpleCmdObj(this.funNamespace,this.funPath,this.cmdIndex);
26 | }
27 | }
--------------------------------------------------------------------------------
/src/main/resources/fabric.mod.json:
--------------------------------------------------------------------------------
1 | {
2 | "schemaVersion": 1,
3 | "id": "mcfdebugger",
4 | "version": "${version}",
5 |
6 | "name": "Function Debugger(Mod)",
7 | "description": "A mod that can be used to debug mcfunctions. Also install the vscode part to get full experience!",
8 | "authors": [
9 | "Huge_Black"
10 | ],
11 | "contact": {
12 | "homepage": "https://space.bilibili.com/13687417",
13 | "sources": "https://github.com/hugeBlack/McfDebugger_Mod",
14 | "bilibili": "https://space.bilibili.com/13687417"
15 | },
16 |
17 | "license": "CC 1.0",
18 | "icon": "assets/mcfdebugger/icon.png",
19 |
20 | "environment": "*",
21 | "entrypoints": {
22 | "main": [
23 | "com.hb.mcfdebugger.McfDebugger"
24 | ]
25 | },
26 | "mixins": [
27 | "mcfdebugger.mixins.json"
28 | ],
29 |
30 | "depends": {
31 | "fabricloader": ">=0.11.3",
32 | "fabric": "*",
33 | "minecraft": "1.17.x",
34 | "java": ">=16"
35 | },
36 | "suggests": {
37 | "another-mod": "*"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/SimpleCmdObj.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger;
2 |
3 | public class SimpleCmdObj {
4 | public String funNamespace;
5 | public String funPath;
6 | public Integer cmdIndex;
7 | public SimpleCmdObj(String funNamespace, String funPath, Integer cmdIndex){
8 | this.funNamespace=funNamespace;
9 | this.funPath=funPath;
10 | this.cmdIndex=cmdIndex;
11 | }
12 | public SimpleCmdObj(){
13 | this.funNamespace="";
14 | this.funPath="";
15 | this.cmdIndex=0;
16 | }
17 | public void clear(){
18 | this.funNamespace="";
19 | this.funPath="";
20 | this.cmdIndex=0;
21 | }
22 | public boolean equals(SimpleCmdObj compareObj){
23 | return (this.cmdIndex==compareObj.cmdIndex&&this.funPath.equals(compareObj.funPath)&&this.funNamespace.equals(compareObj.funNamespace));
24 | }
25 | public boolean isNext(SimpleCmdObj compareObj){
26 | return (this.cmdIndex==compareObj.cmdIndex+1&&this.funPath.equals(compareObj.funPath)&&this.funNamespace.equals(compareObj.funNamespace));
27 | }
28 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020-2021 Huge_Black
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/regcmd.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 | import com.hb.mcfdebugger.commands.*;
3 | import com.mojang.brigadier.CommandDispatcher;
4 | import net.minecraft.server.command.CommandManager;
5 | import net.minecraft.server.command.ServerCommandSource;
6 | import org.spongepowered.asm.mixin.Final;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.Shadow;
9 | import org.spongepowered.asm.mixin.injection.At;
10 | import org.spongepowered.asm.mixin.injection.Inject;
11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
12 | import net.minecraft.server.command.TestCommand;
13 |
14 | @Mixin(CommandManager.class)
15 | public abstract class regcmd
16 | {
17 |
18 | @Shadow @Final private CommandDispatcher dispatcher;
19 |
20 | @Inject(method = "", at = @At("RETURN"))
21 | private void onRegister(CommandManager.RegistrationEnvironment arg, CallbackInfo ci) {
22 | DebuggerConfigCommand.register(this.dispatcher);
23 | DebuggerCommand.register(this.dispatcher);
24 | TestCommand.register(this.dispatcher);
25 |
26 | }
27 |
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/DebugThread.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger;
2 |
3 | import java.io.IOException;
4 | import java.net.UnknownHostException;
5 |
6 | import static com.hb.mcfdebugger.McfDebugger.LOG;
7 |
8 | public class DebugThread extends Thread {
9 | public static Boolean nextStep = false;
10 | public static wsServer wsserver;
11 |
12 | @Override
13 | public void run() {
14 | super.run();
15 | LOG("debugThreadStarted!");
16 |
17 |
18 | }
19 | public void restartWsServer(int port ,int timeOut){
20 | try {
21 | this.stopWsServer();
22 | wsserver = wsServer.startWs(port);
23 | wsserver.setConnectionLostTimeout(timeOut);
24 | } catch (UnknownHostException e) {
25 | e.printStackTrace();
26 | }
27 | }
28 | public void stopWsServer(){
29 | if(wsserver!=null){
30 | try {
31 | wsserver.stop();
32 | } catch (IOException e) {
33 | e.printStackTrace();
34 | } catch (InterruptedException e) {
35 | e.printStackTrace();
36 | }
37 | }
38 |
39 | }
40 | public static void sendObjMsgToDebugger(Object obj, String msgType) {
41 | if(wsserver!=null){
42 | wsServer.MsgObj msgObj = new wsServer.MsgObj(msgType, obj);
43 | wsserver.sendObj(msgObj);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixinHelpers/SendFunctionState.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixinHelpers;
2 |
3 | import com.hb.mcfdebugger.DebugThread;
4 | import com.hb.mcfdebugger.McfDebugger;
5 | import net.minecraft.command.CommandSource;
6 | import net.minecraft.server.function.CommandFunction;
7 | import net.minecraft.server.function.FunctionLoader;
8 | import net.minecraft.util.Identifier;
9 |
10 | import java.util.LinkedList;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | public class SendFunctionState {
15 | public static void send(FunctionLoader f) {
16 | Map funMap = f.getFunctions();
17 | List a = funObjParse(funMap);
18 | DebugThread.sendObjMsgToDebugger(a, "functionList");
19 | }
20 |
21 | public static List funObjParse(Map cmdMap) {
22 |
23 | List functionArray = new LinkedList<>();
24 | for (Map.Entry entry : cmdMap.entrySet()) {
25 | McfDebugger.HbCmdObj cmdObj = new McfDebugger.HbCmdObj();
26 | cmdObj.funName = String.valueOf(entry.getKey());
27 | for (CommandFunction.Element singleCmd : entry.getValue().getElements()) {
28 | cmdObj.commands.add(singleCmd.toString());
29 | }
30 | functionArray.add(cmdObj);
31 | }
32 | //McfDebugger.lastFunctionMap = cmdMap;
33 | return functionArray;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixinHelpers/ReadCommandSource.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixinHelpers;
2 |
3 | import com.hb.mcfdebugger.McfDebugger;
4 | import net.minecraft.server.command.ServerCommandSource;
5 |
6 | import java.lang.reflect.Method;
7 | import java.util.LinkedHashMap;
8 | import java.util.Map;
9 |
10 | public class ReadCommandSource {
11 | public static Map read(ServerCommandSource source){
12 | Map sourceMap =new LinkedHashMap<>();
13 | if(source.getEntity()!=null){
14 | sourceMap.put("entityName",source.getEntity().getEntityName());
15 | sourceMap.put("entityUuid",source.getEntity().getUuidAsString());
16 | }else{
17 | sourceMap.put("entityName","None(Server)");
18 | sourceMap.put("entityUuid","None");
19 | }
20 | sourceMap.put("pos" ,source.getPosition().toString());
21 | sourceMap.put("rotation","("+source.getRotation().y+", "+source.getRotation().x+")");
22 | sourceMap.put("world",source.getWorld().getRegistryKey().getValue().toString());
23 | try {
24 | Method levelMethod = source.getClass().getDeclaredMethod("fakeGetLevel");
25 | sourceMap.put("level", String.valueOf(levelMethod.invoke(source)));
26 | } catch (ReflectiveOperationException e) {
27 | sourceMap.put("level","Error");
28 | }
29 | sourceMap.put("commandsLeftToMaxChainLength", String.valueOf(McfDebugger.commandsLeftToMaxChainLength));
30 | return sourceMap;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/commandHelpers/GetEntity.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.commandHelpers;
2 |
3 | import com.hb.mcfdebugger.DebugThread;
4 | import com.mojang.brigadier.context.CommandContext;
5 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
6 | import net.minecraft.command.argument.EntityArgumentType;
7 | import net.minecraft.entity.Entity;
8 | import net.minecraft.server.command.ServerCommandSource;
9 |
10 | import java.util.*;
11 |
12 | public class GetEntity {
13 | public static void get(CommandContext cmd) throws CommandSyntaxException{
14 | List entityList = new LinkedList<>();
15 | Iterator var2 =EntityArgumentType.getOptionalEntities(cmd,"targets").iterator();
16 | while(var2.hasNext()){
17 | Entity entity =(Entity)var2.next();
18 | SendEntityObj sendEntityObj = new SendEntityObj();
19 | sendEntityObj.name=entity.getEntityName();
20 | sendEntityObj.uuid=entity.getUuidAsString();
21 | sendEntityObj.type=entity.getType().toString();
22 | sendEntityObj.detail.put("tags",entity.getScoreboardTags());
23 | sendEntityObj.detail.put("pos",entity.getPos().toString());
24 | sendEntityObj.detail.put("rotation","("+entity.getRotationClient().y+", "+entity.getRotationClient().x+")");
25 | entityList.add(sendEntityObj);
26 | }
27 | DebugThread.sendObjMsgToDebugger(entityList,"getEntityResult");
28 | }
29 | public static class SendEntityObj{
30 | public String name;
31 | public String uuid;
32 | public String type;
33 | public Map detail =new LinkedHashMap<>();
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/ServerCommandSourceHook.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 |
3 | import com.hb.mcfdebugger.DebugThread;
4 | import com.hb.mcfdebugger.McfDebugger;
5 | import com.hb.mcfdebugger.SendCmdObj;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import net.minecraft.server.command.ServerCommandSource;
8 | import net.minecraft.text.Text;
9 | import org.spongepowered.asm.mixin.Mixin;
10 | import org.spongepowered.asm.mixin.injection.At;
11 | import org.spongepowered.asm.mixin.injection.Inject;
12 | import com.hb.mcfdebugger.commands.DebuggerCommand;
13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
14 |
15 | @Mixin(ServerCommandSource.class)
16 | public class ServerCommandSourceHook {
17 | @Inject(method = "sendFeedback", at = @At("RETURN"))
18 | public void sendFeedback(Text message, boolean broadcastToOps, CallbackInfo ci) throws CommandSyntaxException {
19 | if (McfDebugger.lastCmdObj!=null && McfDebugger.lastCmdObj.toSimple().isNext(McfDebugger.nowLoudCmd)) {
20 | McfDebugger.hbPair send=new McfDebugger.hbPair("output",message.getString());
21 | DebugThread.sendObjMsgToDebugger(send,"loudResult");
22 | McfDebugger.nowLoudCmd.clear();
23 | throw DebuggerCommand.LOGGER_HIT_EXCEPTION.create();
24 | }
25 | if (McfDebugger.lastCmdObj!=null && McfDebugger.lastCmdObj.toSimple().isNext(McfDebugger.nowLogCmd)) {
26 |
27 | McfDebugger.hbPair send=new McfDebugger.hbPair("output",new McfDebugger.hbPair(message.getString(),McfDebugger.lastCmdObj));
28 | DebugThread.sendObjMsgToDebugger(send,"logResult");
29 | McfDebugger.nowLogCmd.clear();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/README_zh_cn.md:
--------------------------------------------------------------------------------
1 | # Minecraft函数调试器
2 |
3 | 
4 |
5 | 语言:
6 | [English](https://github.com/hugeBlack/McfDebugger_Mod/blob/master/README.md) \ 简体中文
7 |
8 | *(如果你只是想下载模组,请移步右边的[Release](https://github.com/hugeBlack/McfDebugger_Mod/releases)板块)*
9 |
10 | ## 简介
11 |
12 | 你还在为写函数的时候哪个指令没有执行而不知所措吗?
13 | 你还在为调试而各种/say吗
14 | 你还在为不知道哪个实体执行了function而一头雾水吗(跑
15 |
16 | Minecraft Function Debugger (Mod),简称 McFD,中文名「函数调试器(模组部分)」是一个能够为 Minecraft Java版的函数提供调试支持的Mod,你可以使用它像调试其他语言一样调试mcfunction
17 |
18 | 虽然您可以在有Websocket知识,Json读写能力的基础上仅使用本模组实现调试功能
19 |
20 | 我还是建议您务必配套使用 [对应的Vscode插件](https://github.com/hugeBlack/McfDebugger_Extension) 来获得最佳体验
21 |
22 | ## 修改
23 |
24 | * 对游戏性没有任何修改,主要对函数有关的方法进行了Overwrite,虽然已经尽可能地进行最少的修改,但可能对游戏的行为产生影响。
25 | * 本模组通过Websocket与Vscode插件通信
26 |
27 | ## 指令
28 |
29 | 配置指令: /mcfDebuggerConfig 需要4级权限
30 |
31 | * /mcfDebuggerConfig port <端口:整数> 立即修改端口并重启内置的Websocket服务器,默认1453
32 | * /mcfDebuggerConfig enable 立即启用/禁用内置的Websocket服务器,默认true
33 | * /mcfDebuggerConfig timeOut <秒:整数> 设置连接超时的时间,不宜太长,默认5
34 | * 每个世界不共享配置文件
35 |
36 | 调试器指令:/debuggerCmd
37 |
38 | * 用于实现调试器功能,没有明显效果,不会消耗MaxChainLength
39 |
40 | ## 使用
41 |
42 | 具体使用方式请移步 [Vscode插件](https://github.com/hugeBlack/McfDebugger_Extension) 部分.
43 |
44 | ## 免责声明
45 |
46 | VSCode插件部分只会读取你的数据包,因此你的数据包是安全的。然而,在某些极端情况下,模组部分可能会因为某些原因损坏你的存档,尽管经经过了些许测试,但是这种情况仍有可能发生。
47 | 并且,由于使用Webocket通信,你的设备可能被恶意入侵。
48 | 遗憾的是,我们并不能在这些情况中提供任何帮助。
49 | 所以请请随时备份您宝贵的存档并请自行配置防火墙来保证您的设备的安全。
50 |
51 | ## Q&A
52 |
53 | 1. Q:为什么使用Fabric而不是Forge之类的?
54 | A:因为Fabric光速支持快照等版本而FML更新慢。
55 | 2. Q:为什么游戏关闭不了?
56 | A:检查一下你的调试器VSCode部分是不是正在暂停状态,否则超时时间一过就会自动关闭,**切记不要去杀进程,可能会导致存档损坏**
57 | 3. Q:为什么提示文字显示不正常?
58 | A:请安装[Fabric-Api](https://www.curseforge.com/minecraft/mc-mods/fabric-api)!
59 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/FunctionCommandHook.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 |
3 | import com.hb.mcfdebugger.McfDebugger;
4 | import net.minecraft.server.command.FunctionCommand;
5 | import net.minecraft.server.command.ServerCommandSource;
6 | import net.minecraft.server.function.CommandFunction;
7 | import net.minecraft.text.TranslatableText;
8 | import org.spongepowered.asm.mixin.Mixin;
9 | import org.spongepowered.asm.mixin.Overwrite;
10 |
11 | import java.util.Collection;
12 | import java.util.Iterator;
13 |
14 | @Mixin(FunctionCommand.class)
15 | public class FunctionCommandHook {
16 | @Overwrite
17 | private static int execute(ServerCommandSource source, Collection functions) {
18 | int i = 0;
19 | String cmdList = "";
20 | CommandFunction commandFunction;
21 | McfDebugger.lastCallCmdObj = McfDebugger.lastCmdObj==null?null:McfDebugger.lastCmdObj;
22 | McfDebugger.tagFunctionLeft.add(functions.size());
23 | for (Iterator var3 = functions.iterator(); var3.hasNext(); i += source.getServer().getCommandFunctionManager().execute(commandFunction, source.withSilent().withMaxLevel(2))) {
24 |
25 | commandFunction = (CommandFunction) var3.next();
26 | //modified
27 | cmdList += commandFunction.getId().toString() + (var3.hasNext() ? "," : "");
28 | if(!var3.hasNext()){
29 | McfDebugger.hbPair p = new McfDebugger.hbPair(cmdList,McfDebugger.lastCallCmdObj);
30 | McfDebugger.stackList.add(p);
31 | }
32 | //modified
33 | }
34 |
35 | if (functions.size() == 1) {
36 | source.sendFeedback(new TranslatableText("commands.function.success.single", new Object[]{i, ((CommandFunction) functions.iterator().next()).getId()}), true);
37 | } else {
38 | source.sendFeedback(new TranslatableText("commands.function.success.multiple", new Object[]{i, functions.size()}), true);
39 | }
40 | //modified
41 | McfDebugger.lastCallCmdObj=null;
42 | McfDebugger.lastCmdObj = null;
43 | //modified
44 | return i;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/wsServer.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger;
2 | import com.google.gson.Gson;
3 | import org.java_websocket.WebSocket;
4 | import org.java_websocket.handshake.ClientHandshake;
5 | import org.java_websocket.server.WebSocketServer;
6 |
7 | import java.net.InetSocketAddress;
8 | import java.net.UnknownHostException;
9 | import static com.hb.mcfdebugger.McfDebugger.LOG;
10 |
11 | public class wsServer extends WebSocketServer {
12 |
13 | public wsServer(int port) throws UnknownHostException {
14 | super(new InetSocketAddress(port));
15 | LOG("websocket Server start at port:"+port);
16 | }
17 |
18 | @Override
19 | public void onOpen(WebSocket conn, ClientHandshake clientHandshake) {
20 | LOG("new connection ===" + conn.getRemoteSocketAddress().getAddress().getHostAddress());
21 | }
22 |
23 | @Override
24 | public void onClose(WebSocket conn, int code, String reason, boolean remote) {
25 |
26 | }
27 |
28 | @Override
29 | public void onMessage(WebSocket conn, String message) {
30 | LOG("you have a new message: "+ message);
31 | //向客户端发送消息
32 | wsCommandParser.DebugHandler(message);
33 | //conn.send(message);
34 | }
35 |
36 | @Override
37 | public void onError(WebSocket conn, Exception e) {
38 | //e.printStackTrace();
39 | if( conn != null ) {
40 | //some errors like port binding failed may not be assignable to a specific websocket
41 | }
42 | }
43 |
44 | @Override
45 | public void onStart() {
46 | LOG("Ws Started!");
47 | }
48 |
49 | public static wsServer startWs(int port) throws UnknownHostException {
50 | wsServer s = new wsServer(port);
51 | s.start();
52 | return s;
53 | }
54 |
55 | public void sendObj(MsgObj msgObj){
56 | Gson gson=new Gson();
57 | String backMsg=gson.toJson(msgObj);
58 | this.broadcast(backMsg);
59 |
60 | }
61 | public static class MsgObj{
62 | public String msgType;
63 | public Object bodyObj;
64 | public MsgObj(String msgType,Object bodyObj){
65 | this.msgType=msgType;
66 | this.bodyObj=bodyObj;
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/McfDebugger.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger;
2 |
3 | import com.hb.mcfdebugger.config.ConfigHolder;
4 | import com.hb.mcfdebugger.config.ConfigManager;
5 | import net.fabricmc.api.ModInitializer;
6 | import net.minecraft.command.CommandSource;
7 | import net.minecraft.server.MinecraftServer;
8 | import net.minecraft.server.function.CommandFunction;
9 | import net.minecraft.server.function.FunctionLoader;
10 | import net.minecraft.util.Identifier;
11 | import net.minecraft.util.WorldSavePath;
12 |
13 | import java.util.*;
14 |
15 | public class McfDebugger implements ModInitializer {
16 | public static boolean isThisModDebugging=false;
17 |
18 | public static class HbCmdObj{
19 | public String funName;
20 | public List commands;
21 | public HbCmdObj() {
22 | this.funName="";
23 | this.commands=new LinkedList<>();
24 | }
25 | }
26 |
27 | public static SimpleCmdObj nowCmd = new SimpleCmdObj();
28 | public static boolean nowIsLastCmd=false;
29 |
30 | public static SendCmdObj lastCmdObj;
31 | public static MinecraftServer mcServer;
32 |
33 | public static int nowCommandCount=0;
34 | public static int commandsLeftToMaxChainLength=0;
35 |
36 | public static SimpleCmdObj nowMuteCmd = new SimpleCmdObj();
37 | public static SimpleCmdObj nowLoudCmd = new SimpleCmdObj();
38 | public static SimpleCmdObj nowLogCmd = new SimpleCmdObj();
39 |
40 | public static List stackList= new LinkedList<>();
41 | public static List tagFunctionLeft= new LinkedList<>();
42 | public static SendCmdObj lastCallCmdObj=null;
43 | public static class hbPair{
44 | public String key;
45 | public Object value;
46 | public hbPair(String key,Object value){
47 | this.key=key;
48 | this.value=value;
49 | }
50 | }
51 |
52 | public static ConfigManager configManager=ConfigManager.getConfigManager();
53 | public static LinkedHashMap configList=new LinkedHashMap<>();
54 |
55 | public static DebugThread thread = new DebugThread();
56 |
57 | @Override
58 | public void onInitialize() {
59 | LOG("Hello Fabric world!");
60 | thread.start();
61 |
62 | }
63 | public static void LOG(Object msgObj){
64 | if(ConfigHolder.isThisModDebugging){
65 | System.out.println(msgObj.toString());
66 | }
67 | }
68 |
69 | public static boolean howeverStop = false;
70 |
71 | public static boolean stepOut = false;
72 | public static boolean stepIn = false;
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/DebugHook.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 |
3 | import java.lang.reflect.Field;
4 | import java.util.ArrayDeque;
5 | import java.util.Deque;
6 |
7 | import com.hb.mcfdebugger.*;
8 | import com.hb.mcfdebugger.mixinHelpers.SendCommandState;
9 | import com.mojang.brigadier.ParseResults;
10 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
11 | import net.minecraft.server.command.ServerCommandSource;
12 | import net.minecraft.server.function.CommandFunction;
13 | import net.minecraft.server.function.CommandFunctionManager;
14 |
15 | import org.jetbrains.annotations.Nullable;
16 | import org.spongepowered.asm.mixin.Final;
17 | import org.spongepowered.asm.mixin.Mixin;
18 | import org.spongepowered.asm.mixin.Overwrite;
19 | import org.spongepowered.asm.mixin.Shadow;
20 |
21 | @Mixin(CommandFunction.CommandElement.class)
22 | public abstract class DebugHook implements CommandFunction.Element{
23 | CommandFunction.Element element=(CommandFunction.Element)this;
24 | @Shadow @Final ParseResults parsed;
25 | @Shadow
26 | abstract int execute(CommandFunctionManager manager, ServerCommandSource source) throws CommandSyntaxException;
27 | @Overwrite
28 | public void execute (CommandFunctionManager manager, ServerCommandSource source, Deque entries, int maxChainLength, int depth, @Nullable CommandFunctionManager.Tracer tracer) throws CommandSyntaxException {
29 | SendCommandState.send(element,source);
30 | boolean isLastCmd=false;
31 | try {
32 | Field funNamespaceField = element.getClass().getDeclaredField("isLastCmd");
33 | isLastCmd= (Boolean) funNamespaceField.get(element);
34 | } catch (ReflectiveOperationException e) { }
35 | if(isLastCmd) {
36 | int i =McfDebugger.tagFunctionLeft.size()-1;
37 | if(i>=0){
38 | if(McfDebugger.tagFunctionLeft.get(i)<=1){
39 | McfDebugger.stackList.remove(McfDebugger.stackList.size() - 1);
40 | McfDebugger.tagFunctionLeft.remove(i);
41 | }else{
42 | McfDebugger.tagFunctionLeft.set(i,McfDebugger.tagFunctionLeft.get(i)-1);
43 | }
44 | }
45 | }
46 | //origin
47 | if (tracer != null) {
48 | String string = this.parsed.getReader().getString();
49 | tracer.traceCommandStart(depth, string);
50 | int i = this.execute(manager, source);
51 | tracer.traceCommandEnd(depth, string, i);
52 | } else {
53 | this.execute(manager, source);
54 | }
55 | //origin
56 |
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixinHelpers/SendCommandState.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixinHelpers;
2 |
3 | import com.hb.mcfdebugger.*;
4 | import com.hb.mcfdebugger.config.ConfigHolder;
5 | import net.minecraft.command.argument.Vec3ArgumentType;
6 | import net.minecraft.entity.Entity;
7 | import net.minecraft.server.command.ServerCommandSource;
8 | import net.minecraft.server.function.CommandFunction;
9 | import net.minecraft.util.math.Vec2f;
10 | import net.minecraft.util.math.Vec3d;
11 | import net.minecraft.world.World;
12 |
13 | import java.lang.reflect.Field;
14 | import java.lang.reflect.Method;
15 | import java.util.LinkedHashMap;
16 | import java.util.Map;
17 |
18 | public class SendCommandState {
19 | public static void send(CommandFunction.Element element, ServerCommandSource source){
20 | if(!ConfigHolder.debuggerMode.equals("none")) {
21 | String funNamespace = null;
22 | String funPath = null;
23 | Integer cmdIndex = -1;
24 | try {
25 | Field funNamespaceField = element.getClass().getDeclaredField("funNamespace");
26 | funNamespace = (String) funNamespaceField.get(element);
27 | } catch (ReflectiveOperationException e) {
28 | }
29 | try {
30 | Field funPathField = element.getClass().getDeclaredField("funPath");
31 | funPath = (String) funPathField.get(element);
32 | } catch (ReflectiveOperationException e) {
33 | }
34 | try {
35 | Field cmdIndexField = element.getClass().getDeclaredField("cmdIndex");
36 | cmdIndex = (Integer) cmdIndexField.get(element);
37 | } catch (ReflectiveOperationException e) {
38 | }
39 |
40 | if(ConfigHolder.debuggerMode.equals("byStep")|| (cmdIndex==1 && McfDebugger.stepIn) ||wsCommandParser.isInPauseList(funNamespace,funPath,cmdIndex)){
41 | McfDebugger.stepIn=false;
42 | SendCmdObj sendCmdObj = new SendCmdObj(funNamespace, funPath, cmdIndex, element.toString(),true,ReadCommandSource.read(source));
43 | McfDebugger.lastCmdObj=sendCmdObj;
44 | DebugThread.sendObjMsgToDebugger(McfDebugger.stackList,"stackReport");
45 | DebugThread.sendObjMsgToDebugger(sendCmdObj,"commandReport");
46 | PauseWaiter.WaitForNext();
47 | }else{
48 | SendCmdObj sendCmdObj = new SendCmdObj(funNamespace, funPath, cmdIndex, element.toString(),false,null);
49 | McfDebugger.lastCmdObj=sendCmdObj;
50 | DebugThread.sendObjMsgToDebugger(sendCmdObj,"commandReport");
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/config/ConfigManager.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.config;
2 | import com.google.gson.Gson;
3 |
4 | import java.io.*;
5 | import java.util.Iterator;
6 | import java.util.LinkedHashMap;
7 | import java.util.Map;
8 |
9 | import static com.hb.mcfdebugger.McfDebugger.LOG;
10 |
11 | final public class ConfigManager {
12 | private static ConfigManager cm;
13 | private File configFile;
14 | private Gson gson;
15 | private LinkedHashMap configList;
16 |
17 | public static ConfigManager getConfigManager(){
18 | if (cm == null){
19 | cm = new ConfigManager();
20 | }
21 | return cm;
22 | }
23 |
24 | private ConfigManager(){
25 | initConfigList();
26 | gson = new Gson();
27 | }
28 |
29 | private void initConfigList(){
30 | configList = setupRulesMap();
31 | }
32 |
33 | public LinkedHashMap setupRulesMap(){
34 | LinkedHashMap m = new LinkedHashMap<>();
35 | m.put("port", 1453);
36 | m.put("timeOut", 5);
37 | m.put("enable", 1);
38 | return m;
39 | }
40 |
41 | public void passConfigFile(File f){
42 | this.configFile = f;
43 | }
44 |
45 | public void setupConfig(){
46 | loadConfig();
47 | LOG("Config Loaded");
48 | }
49 |
50 | public LinkedHashMap loadConfig(){
51 | if (this.configFile.exists()){
52 | try (FileReader reader = new FileReader(this.configFile)){
53 | Iterator m =gson.fromJson(reader,new LinkedHashMap().getClass()).entrySet().iterator();
54 | while(m.hasNext()){
55 | Map.Entry entry = (Map.Entry)m.next();
56 | this.configList.put(entry.getKey().toString(),((Double)entry.getValue()).intValue());
57 | }
58 | } catch (IOException e) {
59 | LOG("Failed to parse config");
60 | throw new RuntimeException("Could not parse config", e);
61 | }
62 | } else {
63 | initConfigList();
64 | writeConfig();
65 | }
66 |
67 | return configList;
68 | }
69 |
70 | public void writeConfig(){
71 | File dir = configFile.getParentFile();
72 |
73 | if (!dir.exists()) {
74 | if (!dir.mkdirs()) {
75 | LOG("Failed to create the parent directory");
76 | throw new RuntimeException("Failed to create the parent directory");
77 | }
78 | } else if (!dir.isDirectory()) {
79 | LOG("Failed to create config file");
80 | throw new RuntimeException("The parent is not a directory");
81 | }
82 |
83 | try (FileWriter writer = new FileWriter(configFile)) {
84 | gson.toJson(configList, writer);
85 | } catch (IOException e) {
86 | LOG("Failed to save config");
87 | throw new RuntimeException("Could not save config file", e);
88 | }
89 | }
90 |
91 |
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Minecraft Function Debugger
2 |
3 | 
4 |
5 | Languages:
6 | English \ [简体中文](https://github.com/hugeBlack/McfDebugger_Mod/blob/master/README_zh_cn.md)
7 |
8 | *( If you only want to download this mod, please see the [Release](https://github.com/hugeBlack/McfDebugger_Mod/releases) section on the right )*
9 |
10 | ## Intoduction
11 |
12 | Minecraft Function Debugger (Mod Part), McFD dor short, , McFD for short, is a vscode extension that provides support for debugging Minecraft functions. You can use it to debug mcfunctions like debugging other languages.
13 |
14 | Although you can use this mod only with sufficient knowledge of Websocket and Json, I still suggest that you use the [corresponding VSCode extension](https://github.com/hugeBlack/McfDebugger_Extension) to get full experience.
15 |
16 | ## Modification
17 |
18 | * It made no change to gaming features. However, it overwrites some of the methods of Function system. Although we tried our best to make as minior changes as possible, it may change the behaviour of the game in some aspect.
19 | * This mod uses Websocket to communicate with the VSCode extension.
20 |
21 | ## Commands
22 |
23 | ### Configuration command
24 |
25 | /mcfDebuggerConfig
26 |
27 | * /mcfDebuggerConfig port
28 | Change the port of Websocket Server inside and restart it (if enabled). 1453 by default.
29 | * /mcfDebuggerConfig enable
30 | Enable/disable the Websocket Server. True by default.
31 | * /mcfDebuggerConfig timeOut
32 | Set the time out. It should not be too large. 5 by default.
33 | * Configurations are not shared among worlds.
34 | * Require permission level 4.
35 |
36 | ### Debugger Command:/debuggerCmd
37 |
38 | * It is used by the debugger to implement certain features. It has no output and don't cost MaxChainLength.
39 | * Require permission level 2.
40 |
41 | ## Usage
42 |
43 | Please see the [Vscode Extension](https://github.com/hugeBlack/McfDebugger_Extension) part for usage.
44 |
45 | ## Disclaimer
46 |
47 | The VSCode Extension part reads your datapack only, so your datapack is safe definitely. However, the mod part may damage your save. Despite some tests, it could happen under extreme circumstances.
48 |
49 | Also, since it communicate with the game with Websocket your device may be attacked by ill-intentioned people.
50 |
51 | Unfortunately, we can't provide help in these cases. So I strongly recommend that you **should backup** your awesome world. AndP lease config your Firewall to defend your devide from potential attacks.
52 |
53 | ## Q&A
54 |
55 | 1. Q: Why using Fabric instead of Forge?
56 | A:Because Fabric supports Snapshots quickly while Forge don't.
57 | 2. Q: Why I can't stop my game?
58 | A:Check if the game is paused by a exception in VSCode. If it isn't, wait for the timeout and the game will quit automatically (that's why you should set a short timeout!). **NEVER shut down the game in that state with task manager or other means** because it may damage your save!
59 | 3. Q:Why translable texts were not displayed correctly?
60 | A:Please Install [Fabric-Api](https://www.curseforge.com/minecraft/mc-mods/fabric-api)!
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/ErrorHook.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 |
3 | import com.hb.mcfdebugger.*;
4 | import com.hb.mcfdebugger.config.ConfigHolder;
5 | import com.hb.mcfdebugger.mixinHelpers.ReadCommandSource;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import net.minecraft.server.command.ServerCommandSource;
8 | import net.minecraft.server.function.CommandFunction;
9 | import net.minecraft.server.function.CommandFunctionManager;
10 | import org.jetbrains.annotations.Nullable;
11 | import org.spongepowered.asm.mixin.Final;
12 | import org.spongepowered.asm.mixin.Mixin;
13 | import org.spongepowered.asm.mixin.Overwrite;
14 | import org.spongepowered.asm.mixin.Shadow;
15 |
16 | import java.lang.reflect.Field;
17 | import java.lang.reflect.Method;
18 | import java.util.ArrayDeque;
19 | import java.util.Deque;
20 | import java.util.LinkedHashMap;
21 | import java.util.Map;
22 |
23 | @Mixin(CommandFunctionManager.Entry.class)
24 | public class ErrorHook {
25 | @Shadow @Final ServerCommandSource source;
26 | @Shadow @Final int depth;
27 | @Shadow @Final CommandFunction.Element element;
28 | @Overwrite
29 | public void execute(CommandFunctionManager manager, Deque entries, int maxChainLength, @Nullable CommandFunctionManager.Tracer tracer) {
30 | try {
31 | this.element.execute(manager, this.source, entries, maxChainLength, this.depth, tracer);
32 | } catch (CommandSyntaxException var6) {
33 | if (tracer != null) {
34 | tracer.traceError(this.depth, var6.getRawMessage().getString());
35 | }
36 | sendError(var6);
37 | } catch (Exception var7) {
38 | if (tracer != null) {
39 | tracer.traceError(this.depth, var7.getMessage());
40 | }
41 | sendError(var7);
42 | }
43 | if (McfDebugger.lastCmdObj!=null && McfDebugger.lastCmdObj.toSimple().isNext(McfDebugger.nowMuteCmd)) {
44 | McfDebugger.nowMuteCmd.clear();
45 | }
46 | }
47 | public void sendError(Exception exception) {
48 | if (!ConfigHolder.debuggerMode.equals("none")) {
49 | String exceptionMsg = exception.toString();
50 | if (exceptionMsg != "") {
51 | if (McfDebugger.lastCmdObj!=null && !McfDebugger.lastCmdObj.toSimple().isNext(McfDebugger.nowMuteCmd)) {
52 | int mode=ConfigHolder.nonStopOnException?1:0;
53 | McfDebugger.lastCmdObj.exception=exceptionMsg;
54 | McfDebugger.lastCmdObj.pause=true;
55 | SendCmdObj sendCmdObj = new SendCmdObj(McfDebugger.lastCmdObj.funNamespace, McfDebugger.lastCmdObj.funPath, McfDebugger.lastCmdObj.cmdIndex, element.toString(),true, ReadCommandSource.read(source));
56 | sendCmdObj.exception=exceptionMsg;
57 | if(mode==0||McfDebugger.howeverStop){
58 | McfDebugger.howeverStop=false;
59 | DebugThread.sendObjMsgToDebugger(McfDebugger.stackList,"stackReport");
60 | DebugThread.sendObjMsgToDebugger(sendCmdObj,"errorCommandReport");
61 | PauseWaiter.WaitForNext();
62 | }else if (mode==1){
63 | DebugThread.sendObjMsgToDebugger(sendCmdObj,"nonStopErrorCommandReport");
64 | }
65 | }
66 | }
67 | }
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixinHelpers/FakeCommandFunctionCreate.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixinHelpers;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.hb.mcfdebugger.McfDebugger;
5 | import com.hb.mcfdebugger.SimpleCmdObj;
6 | import com.mojang.brigadier.CommandDispatcher;
7 | import com.mojang.brigadier.ParseResults;
8 | import com.mojang.brigadier.StringReader;
9 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
10 | import net.minecraft.server.command.CommandManager;
11 | import net.minecraft.server.command.ServerCommandSource;
12 | import net.minecraft.server.function.CommandFunction;
13 | import net.minecraft.util.Identifier;
14 |
15 | import java.util.LinkedHashMap;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | public class FakeCommandFunctionCreate {
20 | public static CommandFunction create(Identifier id, CommandDispatcher commandDispatcher, ServerCommandSource serverCommandSource, List list) {
21 | List list2 = Lists.newArrayListWithCapacity(list.size());
22 |
23 | for(int i = 0; i < list.size(); ++i) {
24 | int j = i + 1;
25 | //modified
26 | McfDebugger.nowCmd=new SimpleCmdObj(id.getNamespace(),id.getPath(),i);
27 | McfDebugger.nowIsLastCmd=(i == list.size()-1);
28 | //modified
29 | String string = ((String)list.get(i)).trim();
30 | StringReader stringReader = new StringReader(string);
31 | if (stringReader.canRead() && (stringReader.peek() != '#'|| string.startsWith("#@"))) {
32 | if (stringReader.peek() == '/') {
33 | stringReader.skip();
34 | if (stringReader.peek() == '/') {
35 | IllegalArgumentException e= new IllegalArgumentException("Unknown or invalid command '" + string + "' on line " + j + " (if you intended to make a comment, use '#' not '//')");
36 | SendSyntaxError.send(e);
37 | throw e;
38 | }
39 |
40 | String string2 = stringReader.readUnquotedString();
41 | IllegalArgumentException e = new IllegalArgumentException("Unknown or invalid command '" + string + "' on line " + j + " (did you mean '" + string2 + "'? Do not use a preceding forwards slash.)");
42 | SendSyntaxError.send(e);
43 | throw e;
44 | }
45 |
46 | try {
47 | //modified
48 | ParseResults parseResults;
49 |
50 | if(!string.startsWith("#@")){
51 | parseResults = commandDispatcher.parse(stringReader, serverCommandSource);
52 | }else{
53 | parseResults = commandDispatcher.parse(new StringReader("debuggerCmd "+string.substring(2)), serverCommandSource);
54 | } if (parseResults.getReader().canRead()) {
55 | throw CommandManager.getException(parseResults);
56 | }
57 |
58 | list2.add(new CommandFunction.CommandElement(parseResults));
59 | } catch (CommandSyntaxException var10) {
60 | IllegalArgumentException e = new IllegalArgumentException("Whilst parsing command on line " + j + ": " + var10.getMessage());
61 | SendSyntaxError.send(e);
62 | throw e;
63 | }
64 | }
65 | }
66 | return new CommandFunction(id, (CommandFunction.Element[])list2.toArray(new CommandFunction.Element[0]));
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/commandHelpers/ReadScoreboard.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.commandHelpers;
2 | import com.hb.mcfdebugger.DebugThread;
3 | import com.hb.mcfdebugger.McfDebugger;
4 | import com.mojang.brigadier.context.CommandContext;
5 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
6 | import net.minecraft.command.argument.ScoreHolderArgumentType;
7 | import net.minecraft.command.argument.ScoreboardObjectiveArgumentType;
8 | import net.minecraft.scoreboard.ScoreboardObjective;
9 | import net.minecraft.scoreboard.ScoreboardPlayerScore;
10 | import net.minecraft.scoreboard.ServerScoreboard;
11 |
12 | import java.util.*;
13 |
14 | public class ReadScoreboard {
15 | public static void parseAllScoreboard()throws Error{
16 |
17 | Collection objectiveList = McfDebugger.mcServer.getScoreboard().getObjectives();
18 | List sendObjectiveList=new LinkedList<>();
19 | for(ScoreboardObjective nowObjective:objectiveList){
20 | SendObjective sendObjective=new SendObjective(nowObjective);
21 | sendObjectiveList.add(sendObjective);
22 | }
23 | DebugThread.sendObjMsgToDebugger(sendObjectiveList,"scoreboardList");
24 | }
25 | public static void parseScoreboardByEntity(CommandContext commandContext) throws CommandSyntaxException {
26 | ServerScoreboard objectives = McfDebugger.mcServer.getScoreboard();
27 | Collection entities=ScoreHolderArgumentType.getScoreboardScoreHolders(commandContext, "targets");
28 | entities.forEach((String entity)->{
29 | Map playerScores=objectives.getPlayerObjectives(entity);
30 | PlayerScorePair playerScorePair=new PlayerScorePair(entity,playerScores);
31 | DebugThread.sendObjMsgToDebugger(playerScorePair,"getScoresResultByEntity");
32 |
33 | });
34 | }
35 | public static void parseScoreboardByObjective(CommandContext commandContext) throws CommandSyntaxException {
36 | ServerScoreboard objectives = McfDebugger.mcServer.getScoreboard();
37 | ScoreboardObjective objective= ScoreboardObjectiveArgumentType.getObjective(commandContext,"objective");
38 | Collection scores=objectives.getAllPlayerScores(objective);
39 | ObjectiveScorePair objectiveScorePair = new ObjectiveScorePair(objective.getName(),scores);
40 | DebugThread.sendObjMsgToDebugger(objectiveScorePair,"getScoresResultByObjective");
41 |
42 | }
43 |
44 | public static class SendObjective{
45 | public Map playerScores=new HashMap();
46 | public String name;
47 | public String criterion;
48 | public String disPlayName;
49 | public SendObjective(ScoreboardObjective mcObjective){
50 | this.name=mcObjective.getName();
51 | this.criterion=mcObjective.getCriterion().getName();
52 | this.disPlayName=mcObjective.getDisplayName().getString();
53 | for(ScoreboardPlayerScore playerScore:mcObjective.getScoreboard().getAllPlayerScores(mcObjective)){
54 | this.playerScores.put(playerScore.getPlayerName(),playerScore.getScore());
55 | }
56 | }
57 | }
58 | public static class PlayerScorePair{
59 | public String playerName;
60 | public Map playerScore=new LinkedHashMap<>();
61 | public PlayerScorePair(String playerName,Map playerScore){
62 | this.playerName=playerName;
63 | playerScore.forEach((ScoreboardObjective objective,ScoreboardPlayerScore score)->{
64 | this.playerScore.put(objective.getName(),score.getScore());
65 | });
66 | }
67 | }
68 | public static class ObjectiveScorePair{
69 | public String objectiveName;
70 | public Map objectiveScore=new LinkedHashMap<>();
71 | public ObjectiveScorePair(String objectiveName,Collection playerScore){
72 | this.objectiveName=objectiveName;
73 | playerScore.forEach((ScoreboardPlayerScore score)->{
74 | this.objectiveScore.put(score.getPlayerName(),score.getScore());
75 | });
76 | }
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/commands/DebuggerConfigCommand.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.commands;
2 |
3 | import com.hb.mcfdebugger.DebugThread;
4 | import com.hb.mcfdebugger.McfDebugger;
5 | import com.mojang.brigadier.CommandDispatcher;
6 | import com.mojang.brigadier.arguments.BoolArgumentType;
7 | import com.mojang.brigadier.arguments.IntegerArgumentType;
8 | import com.mojang.brigadier.builder.LiteralArgumentBuilder;
9 | import com.mojang.brigadier.context.CommandContext;
10 | import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
11 | import net.minecraft.server.command.CommandManager;
12 | import net.minecraft.server.command.ServerCommandSource;
13 | import net.minecraft.text.TranslatableText;
14 |
15 | import static com.mojang.brigadier.arguments.IntegerArgumentType.*;
16 |
17 | public class DebuggerConfigCommand {
18 | public static final SimpleCommandExceptionType INVALID_ARGUMENT = new SimpleCommandExceptionType(new TranslatableText("mcfdebugger.invalidArgument"));
19 |
20 | public static void register(CommandDispatcher dispatcher) {
21 | LiteralArgumentBuilder literalArgumentBuilder = CommandManager.literal("mcfDebuggerConfig").
22 | requires(source -> source.hasPermissionLevel(4))
23 | .then(CommandManager.literal("enable")
24 | .then(CommandManager.argument("enable?", BoolArgumentType.bool())
25 | .executes((CommandContext cmd) -> {
26 | boolean isEnable = BoolArgumentType.getBool(cmd, "enable?");
27 | McfDebugger.configList.put("enable", isEnable ? 1 : 0);
28 | McfDebugger.configManager.writeConfig();
29 | if (isEnable) {
30 | cmd.getSource().sendFeedback(new TranslatableText("mcfdebugger.enabled"), true);
31 | McfDebugger.thread.restartWsServer(McfDebugger.configList.get("port"), McfDebugger.configList.get("timeOut"));
32 | } else {
33 | cmd.getSource().sendFeedback(new TranslatableText("mcfdebugger.disabled"), true);
34 | McfDebugger.thread.stopWsServer();
35 |
36 | }
37 | return 1;
38 | }
39 | )
40 | )
41 | )
42 | .then(CommandManager.literal("port")
43 | .then(CommandManager.argument("port", integer())
44 | .executes(cmd -> {
45 | if (IntegerArgumentType.getInteger(cmd, "port") < 65536 && IntegerArgumentType.getInteger(cmd, "port") > 0) {
46 | McfDebugger.configList.put("port", IntegerArgumentType.getInteger(cmd, "port"));
47 | McfDebugger.configManager.writeConfig();
48 | cmd.getSource().sendFeedback(new TranslatableText("mcfdebugger.set_port", IntegerArgumentType.getInteger(cmd, "port")), true);
49 | McfDebugger.thread.restartWsServer(McfDebugger.configList.get("port"), McfDebugger.configList.get("timeOut"));
50 | return 1;
51 | }
52 | throw INVALID_ARGUMENT.create();
53 | }
54 | )
55 | )
56 | )
57 | .then(CommandManager.literal("timeOut")
58 | .then(CommandManager.argument("timeOut", integer())
59 | .executes(cmd -> {
60 | if (IntegerArgumentType.getInteger(cmd, "timeOut") > 0) {
61 | McfDebugger.configList.put("enable", IntegerArgumentType.getInteger(cmd, "timeOut"));
62 | McfDebugger.configManager.writeConfig();
63 | cmd.getSource().sendFeedback(new TranslatableText("mcfdebugger.set_time_out", IntegerArgumentType.getInteger(cmd, "timeOut")), true);
64 | DebugThread.wsserver.setConnectionLostTimeout(IntegerArgumentType.getInteger(cmd, "timeOut"));
65 | return 1;
66 | }
67 | throw INVALID_ARGUMENT.create();
68 | }
69 | )
70 | )
71 | );
72 | dispatcher.register(literalArgumentBuilder);
73 | }
74 |
75 | public static int getNum(int num) {
76 | return num;
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@types/node@*":
6 | version "14.14.25"
7 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.25.tgz#15967a7b577ff81383f9b888aa6705d43fbbae93"
8 | integrity sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ==
9 |
10 | "@types/ws@^7.4.0":
11 | version "7.4.0"
12 | resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.0.tgz#499690ea08736e05a8186113dac37769ab251a0e"
13 | integrity sha512-Y29uQ3Uy+58bZrFLhX36hcI3Np37nqWE7ky5tjiDoy1GDZnIwVxS0CgF+s+1bXMzjKBFy+fqaRfb708iNzdinw==
14 | dependencies:
15 | "@types/node" "*"
16 |
17 | bufferutil@^4.0.1, bufferutil@^4.0.3:
18 | version "4.0.3"
19 | resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.3.tgz#66724b756bed23cd7c28c4d306d7994f9943cc6b"
20 | integrity sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw==
21 | dependencies:
22 | node-gyp-build "^4.2.0"
23 |
24 | d@1, d@^1.0.1:
25 | version "1.0.1"
26 | resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
27 | integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
28 | dependencies:
29 | es5-ext "^0.10.50"
30 | type "^1.0.1"
31 |
32 | debug@^2.2.0:
33 | version "2.6.9"
34 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
35 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
36 | dependencies:
37 | ms "2.0.0"
38 |
39 | es5-ext@^0.10.35, es5-ext@^0.10.50:
40 | version "0.10.53"
41 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
42 | integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
43 | dependencies:
44 | es6-iterator "~2.0.3"
45 | es6-symbol "~3.1.3"
46 | next-tick "~1.0.0"
47 |
48 | es6-iterator@~2.0.3:
49 | version "2.0.3"
50 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
51 | integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
52 | dependencies:
53 | d "1"
54 | es5-ext "^0.10.35"
55 | es6-symbol "^3.1.1"
56 |
57 | es6-symbol@^3.1.1, es6-symbol@~3.1.3:
58 | version "3.1.3"
59 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
60 | integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
61 | dependencies:
62 | d "^1.0.1"
63 | ext "^1.1.2"
64 |
65 | ext@^1.1.2:
66 | version "1.4.0"
67 | resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244"
68 | integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==
69 | dependencies:
70 | type "^2.0.0"
71 |
72 | is-typedarray@^1.0.0:
73 | version "1.0.0"
74 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
75 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
76 |
77 | ms@2.0.0:
78 | version "2.0.0"
79 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
80 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
81 |
82 | next-tick@~1.0.0:
83 | version "1.0.0"
84 | resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
85 | integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
86 |
87 | node-gyp-build@^4.2.0:
88 | version "4.2.3"
89 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739"
90 | integrity sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==
91 |
92 | type@^1.0.1:
93 | version "1.2.0"
94 | resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
95 | integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
96 |
97 | type@^2.0.0:
98 | version "2.1.0"
99 | resolved "https://registry.yarnpkg.com/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f"
100 | integrity sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==
101 |
102 | typedarray-to-buffer@^3.1.5:
103 | version "3.1.5"
104 | resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
105 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
106 | dependencies:
107 | is-typedarray "^1.0.0"
108 |
109 | utf-8-validate@^5.0.2, utf-8-validate@^5.0.4:
110 | version "5.0.4"
111 | resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.4.tgz#72a1735983ddf7a05a43a9c6b67c5ce1c910f9b8"
112 | integrity sha512-MEF05cPSq3AwJ2C7B7sHAA6i53vONoZbMGX8My5auEVm6W+dJ2Jd/TZPyGJ5CH42V2XtbI5FD28HeHeqlPzZ3Q==
113 | dependencies:
114 | node-gyp-build "^4.2.0"
115 |
116 | websocket@^1.0.33:
117 | version "1.0.33"
118 | resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.33.tgz#407f763fc58e74a3fa41ca3ae5d78d3f5e3b82a5"
119 | integrity sha512-XwNqM2rN5eh3G2CUQE3OHZj+0xfdH42+OFK6LdC2yqiC0YU8e5UK0nYre220T0IyyN031V/XOvtHvXozvJYFWA==
120 | dependencies:
121 | bufferutil "^4.0.1"
122 | debug "^2.2.0"
123 | es5-ext "^0.10.50"
124 | typedarray-to-buffer "^3.1.5"
125 | utf-8-validate "^5.0.2"
126 | yaeti "^0.0.6"
127 |
128 | ws@^7.4.3:
129 | version "7.4.3"
130 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.3.tgz#1f9643de34a543b8edb124bdcbc457ae55a6e5cd"
131 | integrity sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==
132 |
133 | yaeti@^0.0.6:
134 | version "0.0.6"
135 | resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577"
136 | integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=
137 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MSYS* | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/commands/DebuggerCommand.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.commands;
2 |
3 | import com.hb.mcfdebugger.commandHelpers.GetEntity;
4 | import com.hb.mcfdebugger.McfDebugger;
5 | import com.hb.mcfdebugger.commandHelpers.ReadScoreboard;
6 | import com.hb.mcfdebugger.config.ConfigHolder;
7 | import com.mojang.brigadier.CommandDispatcher;
8 | import com.mojang.brigadier.builder.LiteralArgumentBuilder;
9 | import com.mojang.brigadier.context.CommandContext;
10 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
11 | import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
12 | import net.minecraft.command.argument.*;
13 | import net.minecraft.server.command.CommandManager;
14 | import net.minecraft.server.command.ServerCommandSource;
15 | import net.minecraft.text.TranslatableText;
16 | import net.minecraft.util.math.BlockPos;
17 | import net.minecraft.util.math.Vec2f;
18 | import net.minecraft.world.chunk.Chunk;
19 | import net.minecraft.world.chunk.ChunkStatus;
20 |
21 | public class DebuggerCommand {
22 | public static final SimpleCommandExceptionType LOGGER_HIT_EXCEPTION = new SimpleCommandExceptionType(new TranslatableText("MCFDEBUGGER: Logger hit."));
23 | public static final SimpleCommandExceptionType CONSOLE_LOG_HIT_EXCEPTION = new SimpleCommandExceptionType(new TranslatableText("MCFDEBUGGER: Logger hit."));
24 |
25 | public static void register(CommandDispatcher dispatcher) {
26 | LiteralArgumentBuilder literalArgumentBuilder = CommandManager.literal("debuggerCmd").
27 | requires(source -> source.hasPermissionLevel(2))
28 | .then(CommandManager.literal("mute").executes((CommandContext cmd) -> {
29 | McfDebugger.nowCommandCount--;
30 | return DebuggerCommand.mute(cmd);
31 | }))
32 | .then(CommandManager.literal("getScoreboard")
33 | .then(CommandManager.literal("byEntity")
34 | .then(CommandManager.argument("targets", ScoreHolderArgumentType.scoreHolder()).suggests(ScoreHolderArgumentType.SUGGESTION_PROVIDER)
35 | .executes((CommandContext cmd) -> {
36 | McfDebugger.nowCommandCount--;
37 | return DebuggerCommand.execute_getScoreByEntity(cmd);
38 |
39 | }
40 | )
41 | )
42 | )
43 | .then(CommandManager.literal("byObjective")
44 | .then(CommandManager.argument("objective", ScoreboardObjectiveArgumentType.scoreboardObjective())
45 | .executes((CommandContext cmd) -> {
46 | McfDebugger.nowCommandCount--;
47 | return DebuggerCommand.execute_getScoreByObjective(cmd);
48 | }
49 | )
50 | )
51 | )
52 | )
53 | .then(CommandManager.literal("getEntity")
54 | .then(CommandManager.argument("targets", EntityArgumentType.entities())
55 | .executes((CommandContext cmd) -> {
56 | McfDebugger.nowCommandCount--;
57 | return DebuggerCommand.getEntity(cmd);
58 | }
59 | )
60 | )
61 |
62 | )
63 | .then(CommandManager.literal("loud")
64 | .executes((CommandContext cmd) -> {
65 | McfDebugger.nowCommandCount--;
66 | return DebuggerCommand.loud(cmd);
67 | }
68 | )
69 |
70 | )
71 | .then(CommandManager.literal("log")
72 | .executes((CommandContext cmd) -> {
73 | McfDebugger.nowCommandCount--;
74 | return DebuggerCommand.log(cmd);
75 | }
76 | )
77 |
78 | )
79 | ;
80 | dispatcher.register(literalArgumentBuilder);
81 | }
82 |
83 | public static int execute_getScoreByEntity(CommandContext cmd) throws CommandSyntaxException {
84 | if (!ConfigHolder.debuggerMode.equals("none")) {
85 | ReadScoreboard.parseScoreboardByEntity(cmd);
86 | McfDebugger.howeverStop=true;
87 | throw LOGGER_HIT_EXCEPTION.create();
88 | } else {
89 | return 1;
90 | }
91 |
92 | }
93 |
94 | public static int execute_getScoreByObjective(CommandContext cmd) throws CommandSyntaxException {
95 | if (!ConfigHolder.debuggerMode.equals("none")) {
96 | ReadScoreboard.parseScoreboardByObjective(cmd);
97 | McfDebugger.howeverStop=true;
98 | throw LOGGER_HIT_EXCEPTION.create();
99 | } else {
100 | return 1;
101 | }
102 | }
103 |
104 | public static int getEntity(CommandContext cmd) throws CommandSyntaxException {
105 | if (!ConfigHolder.debuggerMode.equals("none")) {
106 | GetEntity.get(cmd);
107 | McfDebugger.howeverStop=true;
108 | throw LOGGER_HIT_EXCEPTION.create();
109 | } else {
110 | return 1;
111 | }
112 | }
113 |
114 | public static int loud(CommandContext cmd) throws CommandSyntaxException {
115 | if (!ConfigHolder.debuggerMode.equals("none")) {
116 | McfDebugger.nowLoudCmd=McfDebugger.lastCmdObj.toSimple();
117 | }
118 | return 1;
119 | }
120 |
121 | public static int log(CommandContext cmd) throws CommandSyntaxException {
122 | if (!ConfigHolder.debuggerMode.equals("none")) {
123 | McfDebugger.nowLogCmd=McfDebugger.lastCmdObj.toSimple();
124 | }
125 | return 1;
126 | }
127 |
128 | public static int mute(CommandContext cmd) throws CommandSyntaxException {
129 | if (!ConfigHolder.debuggerMode.equals("none")) {
130 | McfDebugger.nowMuteCmd=McfDebugger.lastCmdObj.toSimple();
131 | }
132 | return 1;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/com/hb/mcfdebugger/mixin/FunctionLoaderHook.java:
--------------------------------------------------------------------------------
1 | package com.hb.mcfdebugger.mixin;
2 |
3 | import com.google.common.collect.ImmutableMap;
4 | import com.google.common.collect.Maps;
5 | import com.mojang.brigadier.CommandDispatcher;
6 | import com.mojang.datafixers.util.Pair;
7 | import net.minecraft.entity.Entity;
8 | import net.minecraft.resource.Resource;
9 | import net.minecraft.resource.ResourceManager;
10 | import net.minecraft.resource.ResourceReloader;
11 | import net.minecraft.server.MinecraftServer;
12 | import net.minecraft.server.command.CommandOutput;
13 | import net.minecraft.server.command.ServerCommandSource;
14 | import net.minecraft.server.function.CommandFunction;
15 | import net.minecraft.server.function.FunctionLoader;
16 | import net.minecraft.server.world.ServerWorld;
17 | import net.minecraft.tag.Tag;
18 | import net.minecraft.tag.TagGroup;
19 | import net.minecraft.tag.TagGroupLoader;
20 | import net.minecraft.text.LiteralText;
21 | import net.minecraft.util.Identifier;
22 | import net.minecraft.util.math.Vec2f;
23 | import net.minecraft.util.math.Vec3d;
24 | import net.minecraft.util.profiler.Profiler;
25 | import org.apache.commons.io.IOUtils;
26 | import org.apache.logging.log4j.LogManager;
27 | import org.apache.logging.log4j.Logger;
28 | import org.spongepowered.asm.mixin.Final;
29 | import org.spongepowered.asm.mixin.Mixin;
30 | import org.spongepowered.asm.mixin.Overwrite;
31 | import org.spongepowered.asm.mixin.Shadow;
32 |
33 | import java.io.IOException;
34 | import java.nio.charset.StandardCharsets;
35 | import java.util.*;
36 | import java.util.concurrent.CompletableFuture;
37 | import java.util.concurrent.CompletionException;
38 | import java.util.concurrent.Executor;
39 | import com.hb.mcfdebugger.mixinHelpers.FakeCommandFunctionCreate;
40 |
41 | @Mixin(FunctionLoader.class)
42 | public abstract class FunctionLoaderHook implements ResourceReloader {
43 | @Shadow @Final TagGroupLoader tagLoader;
44 | @Shadow abstract Optional get(Identifier id);
45 | private static final int PATH_PREFIX_LENGTH = "functions/".length();
46 | private static final int PATH_SUFFIX_LENGTH = ".mcfunction".length();
47 | @Shadow @Final CommandDispatcher commandDispatcher;
48 | private static final Logger LOGGER= LogManager.getLogger();
49 | @Shadow volatile Map functions;
50 | @Shadow volatile TagGroup tags;
51 | @Shadow @Final int level;
52 |
53 | @Overwrite
54 | public CompletableFuture reload(ResourceReloader.Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor) {
55 | CompletableFuture