Skip to content

Commit cae2b7c

Browse files
committed
version 0.1
1 parent 0d6a0c7 commit cae2b7c

12 files changed

Lines changed: 261 additions & 180 deletions

File tree

.kotlin/sessions/kotlin-compiler-10911146763476343489.salive

Whitespace-only changes.

build.gradle

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
plugins {
22
id 'fabric-loom' version '1.7-SNAPSHOT'
33
id 'maven-publish'
4-
id "org.jetbrains.kotlin.jvm" version "2.0.0"
54
}
65

76
version = project.mod_version
@@ -54,12 +53,6 @@ tasks.withType(JavaCompile).configureEach {
5453
it.options.release = 21
5554
}
5655

57-
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
58-
kotlinOptions {
59-
jvmTarget = 21
60-
}
61-
}
62-
6356
java {
6457
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
6558
// if it is present.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package top.mcfpp.mod.breakpoint;
2+
3+
import net.fabricmc.api.ClientModInitializer;
4+
5+
public class DatapackBreakpointClient implements ClientModInitializer {
6+
@Override
7+
public void onInitializeClient() {
8+
// This entrypoint is suitable for setting up client-specific logic, such as rendering.
9+
}
10+
}

src/client/kotlin/top/mcfpp/mod/breakpoint/DatapackBreakpointClient.kt

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package top.mcfpp.mod.breakpoint;
2+
3+
import net.fabricmc.api.ModInitializer;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
import top.mcfpp.mod.breakpoint.command.BreakPointCommand;
7+
8+
public class DatapackBreakpoint implements ModInitializer {
9+
private static final Logger logger = LoggerFactory.getLogger("datapack-breakpoint");
10+
11+
@Override
12+
public void onInitialize() {
13+
BreakPointCommand.onInitialize();
14+
}
15+
16+
public static Logger getLogger(){
17+
return logger;
18+
}
19+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package top.mcfpp.mod.breakpoint.command;
2+
3+
import com.google.common.collect.Queues;
4+
import com.mojang.brigadier.CommandDispatcher;
5+
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
6+
import net.minecraft.command.CommandExecutionContext;
7+
import net.minecraft.command.CommandRegistryAccess;
8+
import net.minecraft.server.command.CommandManager.RegistrationEnvironment;
9+
import net.minecraft.server.command.CommandManager;
10+
import net.minecraft.server.command.ServerCommandSource;
11+
import net.minecraft.text.Text;
12+
import org.spongepowered.asm.launch.MixinBootstrap;
13+
import top.mcfpp.mod.breakpoint.DatapackBreakpoint;
14+
import java.util.Deque;
15+
import java.util.Locale;
16+
17+
public class BreakPointCommand {
18+
19+
public static boolean isDebugCommand = false;
20+
public static boolean isDebugging = false;
21+
public static int moveSteps = 0;
22+
public static final Deque<CommandExecutionContext<?>> storedCommandExecutionContext = Queues.newArrayDeque();
23+
private static final org.slf4j.Logger LOGGER = DatapackBreakpoint.getLogger();
24+
25+
public static void onInitialize() {
26+
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
27+
dispatcher.register(CommandManager.literal("breakpoint")
28+
.requires(source -> source.hasPermissionLevel(2))
29+
.executes(context -> {
30+
context.getSource().sendFeedback(() -> Text.literal("已触发断点"), false);
31+
breakPoint(context.getSource());
32+
return 1;
33+
})
34+
.then(CommandManager.literal("step")
35+
.executes(context -> {
36+
context.getSource().sendFeedback(() -> Text.literal("已触发单步"), false);
37+
step(1, context.getSource());
38+
return 1;
39+
})
40+
)
41+
.then(CommandManager.literal("move")
42+
.executes(context -> {
43+
context.getSource().sendFeedback(() -> Text.literal("已恢复断点"), false);
44+
moveOn(context.getSource());
45+
return 1;
46+
})
47+
)
48+
);
49+
});
50+
}
51+
52+
private static void breakPoint(ServerCommandSource source) {
53+
source.getServer().getTickManager().setFrozen(true);
54+
isDebugging = true;
55+
}
56+
57+
private static void step(int steps, ServerCommandSource source) {
58+
if (!isDebugging) {
59+
source.sendError(Text.literal("只能在断点模式下使用step指令"));
60+
return;
61+
}
62+
isDebugCommand = true;
63+
moveSteps = steps;
64+
CommandExecutionContext<?> context = null;
65+
try {
66+
while (moveSteps > 0) {
67+
context = storedCommandExecutionContext.peekFirst();
68+
if (context != null) {
69+
LOGGER.info("before mod invokes run()");
70+
var cls = context.getClass();
71+
var method = cls.getDeclaredMethod("onStep");
72+
method.setAccessible(true);
73+
method.invoke(context);
74+
if (moveSteps != 0) {
75+
storedCommandExecutionContext.pollFirst().close();
76+
}
77+
} else {
78+
source.sendFeedback(() -> Text.literal("当前刻已执行完毕,退出调试模式"), false);
79+
moveOn(source);
80+
}
81+
}
82+
} catch (Exception e) {
83+
LOGGER.error(e.getMessage());
84+
} finally {
85+
isDebugCommand = false;
86+
if (context != null) {
87+
try {
88+
context.close();
89+
} catch (Exception e) {
90+
LOGGER.error(e.getMessage());
91+
}
92+
}
93+
}
94+
}
95+
96+
private static void moveOn(ServerCommandSource source) {
97+
source.getServer().getTickManager().setFrozen(false);
98+
isDebugging = false;
99+
moveSteps = 0;
100+
for (CommandExecutionContext<?> context : storedCommandExecutionContext) {
101+
try {
102+
context.run();
103+
context.close();
104+
} catch (Exception e) {
105+
LOGGER.error(e.getMessage());
106+
}
107+
}
108+
}
109+
}

src/main/java/top/mcfpp/mod/breakpoint/mixin/CommandExecutionContextMixin.java

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@
44
import net.minecraft.command.*;
55
import net.minecraft.server.function.Tracer;
66
import net.minecraft.util.profiler.Profiler;
7+
import org.jetbrains.annotations.NotNull;
78
import org.slf4j.Logger;
9+
import org.spongepowered.asm.mixin.Final;
810
import org.spongepowered.asm.mixin.Mixin;
911
import org.spongepowered.asm.mixin.Shadow;
1012
import org.spongepowered.asm.mixin.Unique;
1113
import org.spongepowered.asm.mixin.injection.At;
1214
import org.spongepowered.asm.mixin.injection.Inject;
1315
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
1416
import top.mcfpp.mod.breakpoint.DatapackBreakpoint;
17+
import top.mcfpp.mod.breakpoint.command.BreakPointCommand;
1518

19+
import java.lang.reflect.Field;
1620
import java.util.Deque;
1721
import java.util.List;
22+
import java.util.Objects;
1823

1924
import static top.mcfpp.mod.breakpoint.command.BreakPointCommand.*;
2025

@@ -24,25 +29,25 @@ abstract public class CommandExecutionContextMixin<T> {
2429
@Unique
2530
private final Deque<CommandQueueEntry<T>> storedCommandQueue = Queues.newArrayDeque();
2631

27-
@Shadow private static int MAX_COMMAND_QUEUE_LENGTH;
28-
@Shadow private static Logger LOGGER;
29-
@Shadow private int maxCommandChainLength;
30-
@Shadow private int forkLimit;
31-
@Shadow private Profiler profiler;
32+
@Shadow @Final private static int MAX_COMMAND_QUEUE_LENGTH;
33+
@Shadow @Final private static Logger LOGGER;
34+
@Shadow @Final private int maxCommandChainLength;
35+
@Shadow @Final private int forkLimit;
36+
@Shadow @Final private Profiler profiler;
3237
@Shadow private Tracer tracer;
3338
@Shadow private int commandsRemaining;
3439
@Shadow private boolean queueOverflowed;
35-
@Shadow private Deque<CommandQueueEntry<T>> commandQueue;
36-
@Shadow private List<CommandQueueEntry<T>> pendingCommands;
40+
@Shadow @Final private Deque<CommandQueueEntry<T>> commandQueue;
41+
@Shadow @Final private List<CommandQueueEntry<T>> pendingCommands;
3742
@Shadow private int currentDepth;
38-
@Shadow abstract void queuePendingCommands();
43+
@Shadow protected abstract void queuePendingCommands();
3944

4045
@Shadow public abstract void enqueueCommand(CommandQueueEntry<T> entry);
4146

4247
@Inject(method = "run()V", at = @At("HEAD"), cancellable = true)
4348
private void onRun(CallbackInfo ci){
4449

45-
final var THIS = (CommandExecutionContext<?>) (Object) this;
50+
final var THIS = (CommandExecutionContext<T>) (Object) this;
4651

4752
this.queuePendingCommands();
4853

@@ -53,26 +58,26 @@ private void onRun(CallbackInfo ci){
5358
}
5459

5560
CommandQueueEntry<T> commandQueueEntry = this.commandQueue.pollFirst();
61+
5662
if (commandQueueEntry == null) {
5763
ci.cancel();
5864
return;
5965
}
6066

61-
if(INSTANCE.isDebugging() && commandQueueEntry.frame().depth() != 0 && INSTANCE.getMoveSteps() == 0) {
62-
//在函数中执行的,把所有命令暂存
63-
if(INSTANCE.getStoredCommandExecutionContext().peekFirst() != THIS) {
64-
INSTANCE.getStoredCommandExecutionContext().addFirst(THIS);
67+
LOGGER.info("Method run()V is injected!");
68+
69+
if(isDebugging && commandQueueEntry.frame().depth() != 0 && moveSteps == 0) {
70+
//在函数中执行的,把命令暂存
71+
commandQueue.addFirst(commandQueueEntry);
72+
if(storedCommandExecutionContext.peekFirst() != THIS) {
73+
storedCommandExecutionContext.addFirst(THIS);
6574
}
6675
ci.cancel();
6776
return;
6877
}
6978

70-
if(commandQueueEntry.action() instanceof FixedCommandAction<?>){
71-
INSTANCE.setMoveSteps(INSTANCE.getMoveSteps() - 1);
72-
}
73-
7479
this.currentDepth = commandQueueEntry.frame().depth();
75-
commandQueueEntry.execute((CommandExecutionContext)(Object)this);
80+
commandQueueEntry.execute(THIS);
7681
if (this.queueOverflowed) {
7782
LOGGER.error("Command execution stopped due to command queue overflow (max {})", 10000000);
7883
break;
@@ -87,4 +92,67 @@ private void onRun(CallbackInfo ci){
8792
ci.cancel();
8893
}
8994

95+
@Unique
96+
private void onStep(){
97+
98+
final var THIS = (CommandExecutionContext<T>) (Object) this;
99+
100+
this.queuePendingCommands();
101+
102+
while (true) {
103+
if (this.commandsRemaining <= 0) {
104+
LOGGER.info("Command execution stopped due to limit (executed {} commands)", this.maxCommandChainLength);
105+
break;
106+
}
107+
108+
CommandQueueEntry<T> commandQueueEntry = this.commandQueue.pollFirst();
109+
110+
if (commandQueueEntry == null) {
111+
return;
112+
}
113+
114+
LOGGER.info("Method run()V is injected!");
115+
116+
if(isDebugging && commandQueueEntry.frame().depth() != 0 && moveSteps == 0) {
117+
//在函数中执行的,把所有命令暂存
118+
commandQueue.addFirst(commandQueueEntry);
119+
if(storedCommandExecutionContext.peekFirst() != THIS) {
120+
storedCommandExecutionContext.addFirst(THIS);
121+
}
122+
return;
123+
}
124+
125+
this.currentDepth = commandQueueEntry.frame().depth();
126+
commandQueueEntry.execute(THIS);
127+
if (this.queueOverflowed) {
128+
LOGGER.error("Command execution stopped due to command queue overflow (max {})", 10000000);
129+
break;
130+
}
131+
132+
this.queuePendingCommands();
133+
}
134+
135+
this.currentDepth = 0;
136+
}
137+
138+
@Unique
139+
private boolean isFixCommandAction(@NotNull CommandAction<T> action){
140+
if(!(action instanceof SourcedCommandAction)) return false;
141+
try {
142+
Class<?> actionClass = action.getClass();
143+
Field[] fields = actionClass.getDeclaredFields();
144+
145+
for (Field field : fields) {
146+
field.setAccessible(true);
147+
Object fieldValue = field.get(action);
148+
if (fieldValue instanceof FixedCommandAction) {
149+
return true;
150+
}
151+
}
152+
} catch (IllegalAccessException e) {
153+
e.printStackTrace();
154+
}
155+
return false;
156+
}
157+
90158
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package top.mcfpp.mod.breakpoint.mixin;
2+
3+
import com.mojang.brigadier.context.ContextChain;
4+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
5+
import net.minecraft.command.CommandExecutionContext;
6+
import net.minecraft.command.FixedCommandAction;
7+
import net.minecraft.command.Frame;
8+
import net.minecraft.server.command.AbstractServerCommandSource;
9+
import net.minecraft.server.function.Tracer;
10+
import org.spongepowered.asm.mixin.Mixin;
11+
import org.spongepowered.asm.mixin.injection.At;
12+
import org.spongepowered.asm.mixin.injection.Inject;
13+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
14+
import top.mcfpp.mod.breakpoint.command.BreakPointCommand;
15+
16+
import java.util.function.Supplier;
17+
18+
@Mixin(FixedCommandAction.class)
19+
public class FixCommandActionMixin<T extends AbstractServerCommandSource<T>> {
20+
21+
@Inject(method = "execute(Lnet/minecraft/server/command/AbstractServerCommandSource;Lnet/minecraft/command/CommandExecutionContext;Lnet/minecraft/command/Frame;)V", at = @At("HEAD"))
22+
private void execute(T abstractServerCommandSource, CommandExecutionContext<T> commandExecutionContext, Frame frame, CallbackInfo ci) {
23+
if(BreakPointCommand.moveSteps > 0) BreakPointCommand.moveSteps --;
24+
}
25+
26+
}

src/main/kotlin/top/mcfpp/mod/breakpoint/DatapackBreakpoint.kt

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)