Skip to content

Commit

Permalink
Live scripting (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
tth05 authored Oct 11, 2021
1 parent 8f2651a commit 2d612d8
Show file tree
Hide file tree
Showing 30 changed files with 1,227 additions and 171 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ repositories {
dependencies {
minecraft 'net.minecraftforge:forge:1.12.2-14.23.5.2854'

implementation "com.github.tth05:SCNet:master-SNAPSHOT"
implementation "com.github.tth05:SCNet:519b65"
implementation "io.github.classgraph:classgraph:4.8.90"
implementation "org.bitbucket.mstrobel:procyon-compilertools:0.5.36"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ public boolean decompileClassIfNotExists(Class<?> clazz) {
}

public void setup() {
this.dataDir = FMLClientHandler.instance().getSavesDirectory().toPath().getParent().resolve("code-viewer");
this.decompilationDir = this.dataDir.resolve(DECOMPILED_FILES_FOLDER);
this.dataDir = FMLClientHandler.instance().getSavesDirectory().toPath().getParent().resolve("total-debug");
this.decompilationDir = this.dataDir.resolve(CompanionApp.DATA_FOLDER).resolve(DECOMPILED_FILES_FOLDER);

createDirectory(this.dataDir);
createDirectory(this.decompilationDir);
Expand All @@ -79,7 +79,7 @@ public void openGui(Class<?> clazz, int line) {
CompanionApp companionApp = TotalDebug.PROXY.getCompanionApp();
companionApp.startAndConnect();

if (companionApp.isConnected()) {
if (companionApp.isConnected() && companionApp.waitForUI()) {
Minecraft.getMinecraft().player.sendMessage(
new TextComponentTranslation("companion_app.open_file",
new TextComponentString(filePath.getFileName().toString())
Expand Down Expand Up @@ -110,7 +110,7 @@ public void openGui(Class<?> clazz, int line) {
private void createDirectory(Path path) {
try {
if (Files.notExists(path))
Files.createDirectory(path);
Files.createDirectories(path);
} catch (IOException e) {
TotalDebug.LOGGER.error("Unable to create directory " + path + "!", e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.minecraft_ta.totaldebug;

import com.github.minecraft_ta.totaldebug.block.TickBlock;
import com.github.minecraft_ta.totaldebug.companionApp.script.ScriptRunner;
import com.github.minecraft_ta.totaldebug.proxy.CommonProxy;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
Expand All @@ -14,6 +15,7 @@
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
Expand Down Expand Up @@ -53,6 +55,11 @@ public void init(FMLInitializationEvent event) {
PROXY.init(event);
}

@Mod.EventHandler
public void serverStopping(FMLServerStoppingEvent event) {
ScriptRunner.stopAllScripts();
}

@GameRegistry.ObjectHolder(MOD_ID)
public static class Blocks {
public static final TickBlock TICK_BLOCK = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public void execute(@Nonnull MinecraftServer server, @Nonnull ICommandSender sen
CompanionApp companionApp = TotalDebug.PROXY.getCompanionApp();
companionApp.startAndConnect();

if (companionApp.isConnected()) {
if (companionApp.isConnected() && companionApp.waitForUI()) {
companionApp.getClient().getMessageProcessor().enqueueMessage(
new OpenSearchResultsMessage(args[1], resultPair.getLeft(), searchMethod, resultPair.getRight(), scanTime)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.github.minecraft_ta.totaldebug.companionApp;

import com.github.minecraft_ta.totaldebug.DecompilationManager;
import com.github.minecraft_ta.totaldebug.TotalDebug;
import com.github.minecraft_ta.totaldebug.companionApp.messages.CompanionAppReadyMessage;
import com.github.minecraft_ta.totaldebug.companionApp.messages.chunkGrid.CompanionAppChunkGridDataMessage;
import com.github.minecraft_ta.totaldebug.companionApp.messages.chunkGrid.CompanionAppChunkGridRequestInfoUpdateMessage;
import com.github.minecraft_ta.totaldebug.companionApp.messages.chunkGrid.CompanionAppReceiveDataStateMessage;
import com.github.minecraft_ta.totaldebug.companionApp.messages.chunkGrid.CompanionAppUpdateFollowPlayerStateMessage;
import com.github.minecraft_ta.totaldebug.companionApp.messages.codeView.CodeViewClickMessage;
import com.github.minecraft_ta.totaldebug.companionApp.messages.codeView.DecompileAndOpenRequestMessage;
import com.github.minecraft_ta.totaldebug.companionApp.messages.codeView.OpenFileMessage;
import com.github.minecraft_ta.totaldebug.companionApp.messages.script.*;
import com.github.minecraft_ta.totaldebug.companionApp.messages.search.OpenSearchResultsMessage;
import com.github.tth05.scnet.Client;
import com.google.common.collect.Lists;
Expand Down Expand Up @@ -42,37 +43,56 @@
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class CompanionApp {

public static final String COMPANION_APP_FOLDER = "companion-app";
public static final String DATA_FOLDER = "data";

private static final Gson GSON = new GsonBuilder().create();

private final Path appDir;
private final Metafile metafile;

private Process companionAppProcess;
private CompletableFuture<Void> awaitCompanionAppUIReadyFuture = new CompletableFuture<>();
private final Client companionAppClient = new Client();
{
companionAppClient.getMessageProcessor().registerMessage((short) 1, OpenFileMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) 2, OpenSearchResultsMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) 3, DecompileAndOpenRequestMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) 4, CodeViewClickMessage.class);

companionAppClient.getMessageProcessor().registerMessage((short) 5, CompanionAppReceiveDataStateMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) 6, CompanionAppChunkGridDataMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) 7, CompanionAppChunkGridRequestInfoUpdateMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) 8, CompanionAppUpdateFollowPlayerStateMessage.class);
int id = 1;
companionAppClient.getMessageProcessor().registerMessage((short) id++, CompanionAppReadyMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, OpenFileMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, OpenSearchResultsMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, DecompileAndOpenRequestMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, CodeViewClickMessage.class);

companionAppClient.getMessageProcessor().registerMessage((short) id++, CompanionAppReceiveDataStateMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, CompanionAppChunkGridDataMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, CompanionAppChunkGridRequestInfoUpdateMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, CompanionAppUpdateFollowPlayerStateMessage.class);

companionAppClient.getMessageProcessor().registerMessage((short) id++, RunScriptMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, ScriptStatusMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, ClassPathMessage.class);
companionAppClient.getMessageProcessor().registerMessage((short) id++, StopScriptMessage.class);

companionAppClient.getMessageBus().listenAlways(DecompileAndOpenRequestMessage.class, DecompileAndOpenRequestMessage::handle);
companionAppClient.getMessageBus().listenAlways(CodeViewClickMessage.class, CodeViewClickMessage::handle);

companionAppClient.getMessageBus().listenAlways(CompanionAppReceiveDataStateMessage.class, CompanionAppReceiveDataStateMessage::handle);
companionAppClient.getMessageBus().listenAlways(CompanionAppChunkGridRequestInfoUpdateMessage.class, CompanionAppChunkGridRequestInfoUpdateMessage::handle);
companionAppClient.getMessageBus().listenAlways(CompanionAppUpdateFollowPlayerStateMessage.class, CompanionAppUpdateFollowPlayerStateMessage::handle);

companionAppClient.getMessageBus().listenAlways(RunScriptMessage.class, RunScriptMessage::handle);
companionAppClient.getMessageBus().listenAlways(ClassPathMessage.class, ClassPathMessage::handle);
companionAppClient.getMessageBus().listenAlways(StopScriptMessage.class, StopScriptMessage::handle);

companionAppClient.getMessageBus().listenAlways(CompanionAppReadyMessage.class, (m) -> awaitCompanionAppUIReadyFuture.complete(null));
}

public CompanionApp(Path appDir) {
Expand Down Expand Up @@ -108,7 +128,7 @@ public void startAndConnect() {
Path exePath = this.appDir.resolve("TotalDebugCompanion.jar");

if (!Files.exists(exePath) ||
!this.metafile.currentCompanionAppVersion.equals(this.metafile.newestCompatibleCompanionAppVersion)) {
!this.metafile.currentCompanionAppVersion.equals(this.metafile.newestCompatibleCompanionAppVersion)) {
downloadCompanionApp(this.metafile.newestCompatibleCompanionAppVersion);
this.metafile.currentCompanionAppVersion = this.metafile.newestCompatibleCompanionAppVersion;
this.metafile.write();
Expand All @@ -127,6 +147,10 @@ public void startAndConnect() {
new TextComponentTranslation("companion_app.connecting")
.setStyle(new Style().setColor(TextFormatting.GRAY))
);

this.awaitCompanionAppUIReadyFuture.cancel(true);
this.awaitCompanionAppUIReadyFuture = new CompletableFuture<>();

if (connect(5, 1000)) {
sender.sendMessage(
new TextComponentTranslation("companion_app.connection_success")
Expand All @@ -141,6 +165,26 @@ public void startAndConnect() {
}
}

/**
* @return {@code true} if the companion's UI is ready
*/
public boolean waitForUI() {
if (this.awaitCompanionAppUIReadyFuture.isDone())
return true;

try {
this.awaitCompanionAppUIReadyFuture.get(60, TimeUnit.SECONDS);
this.awaitCompanionAppUIReadyFuture.cancel(true);
return true;
} catch (InterruptedException | ExecutionException | TimeoutException e) {
TotalDebug.LOGGER.error("Timed out while waiting for companion app ready message", e);
if (this.companionAppClient.isConnected())
this.companionAppClient.close();

return false;
}
}

/**
* @return {@code true} if we're still connected to the companion app; {@code false} otherwise
*/
Expand All @@ -153,6 +197,7 @@ public boolean isConnected() {
*/
public boolean isRunning() {
return this.companionAppProcess != null && this.companionAppProcess.isAlive();
// return true;
}

public Client getClient() {
Expand Down Expand Up @@ -187,9 +232,10 @@ private void startApp() {
try {
ProcessBuilder processBuilder = new ProcessBuilder(
this.appDir.resolve("bin").resolve("java.exe").toAbsolutePath().toString(),
"--illegal-access=permit",
"-jar",
exePath.toAbsolutePath().toString(),
"\"" + this.appDir.getParent().resolve(DecompilationManager.DECOMPILED_FILES_FOLDER).toAbsolutePath() + "\""
"\"" + this.appDir.getParent().resolve(DATA_FOLDER).toAbsolutePath() + "\""
);

if (logFile != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.github.minecraft_ta.totaldebug.companionApp.chunkGrid;

import com.github.minecraft_ta.totaldebug.TotalDebug;
import com.github.minecraft_ta.totaldebug.network.chunkGrid.ChunkGridDataMessage;
import com.github.minecraft_ta.totaldebug.companionApp.messages.chunkGrid.CompanionAppChunkGridDataMessage;
import com.github.minecraft_ta.totaldebug.network.CompanionAppForwardedMessage;
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
import net.minecraft.entity.player.EntityPlayerMP;
Expand Down Expand Up @@ -84,7 +85,7 @@ else if (isChunkLoaded)
continue;
}

TotalDebug.INSTANCE.network.sendTo(new ChunkGridDataMessage(chunkGridRequestInfo, stateMap), player);
TotalDebug.INSTANCE.network.sendTo(new CompanionAppForwardedMessage(new CompanionAppChunkGridDataMessage(chunkGridRequestInfo, stateMap)), player);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.github.minecraft_ta.totaldebug.companionApp.messages;

import com.github.tth05.scnet.message.AbstractMessageIncoming;
import com.github.tth05.scnet.util.ByteBufferInputStream;

public class CompanionAppReadyMessage extends AbstractMessageIncoming {

@Override
public void read(ByteBufferInputStream messageStream) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import com.github.minecraft_ta.totaldebug.companionApp.chunkGrid.ChunkGridRequestInfo;
import com.github.tth05.scnet.message.AbstractMessageOutgoing;
import com.github.tth05.scnet.util.ByteBufferInputStream;
import com.github.tth05.scnet.util.ByteBufferOutputStream;
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;

public class CompanionAppChunkGridDataMessage extends AbstractMessageOutgoing {

Expand All @@ -27,4 +29,15 @@ public void write(ByteBufferOutputStream messageStream) {
messageStream.writeByte(v);
});
}

@Override
public void read(ByteBufferInputStream messageStream) {
this.requestInfo = ChunkGridRequestInfo.fromBytes(messageStream);

int size = messageStream.readInt();
this.stateMap = new Long2ByteOpenHashMap(size);
for (int i = 0; i < size; i++) {
this.stateMap.put(messageStream.readLong(), messageStream.readByte());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static void handle(CodeViewClickMessage message) {
}

try {
String code = new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
String code = removeAnsiCodes(new String(Files.readAllBytes(file), StandardCharsets.UTF_8));
Position position = new Position(message.row + 1, message.column + 1);

ParserConfiguration config = new ParserConfiguration()
Expand Down Expand Up @@ -86,10 +86,10 @@ public static void handle(CodeViewClickMessage message) {
//Parse the target class
config.setSymbolResolver(null);
CompilationUnit declaringTypeUnit = javaParser.parse(
new String(
removeAnsiCodes(new String(
Files.readAllBytes(decompilationDir.resolve(name + ".java")),
StandardCharsets.UTF_8
)
))
).getResult().get();

//Find the resolved object in the target class
Expand All @@ -114,4 +114,8 @@ else if (m instanceof FieldDeclaration)
t.printStackTrace();
}
}

private static String removeAnsiCodes(String text) {
return text.replaceAll("[\\u001b]\\[[0-9;]+?m(.*?)[\\u001b]\\[m", "$1");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.github.minecraft_ta.totaldebug.companionApp.messages.script;

import com.github.minecraft_ta.totaldebug.TotalDebug;
import com.github.minecraft_ta.totaldebug.util.compiler.InMemoryJavaCompiler;
import com.github.minecraft_ta.totaldebug.util.mappings.ClassUtil;
import com.github.tth05.scnet.message.AbstractMessage;
import com.github.tth05.scnet.util.ByteBufferInputStream;
import com.github.tth05.scnet.util.ByteBufferOutputStream;
import net.minecraft.launchwrapper.LaunchClassLoader;

import java.net.URISyntaxException;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ClassPathMessage extends AbstractMessage {

@Override
public void read(ByteBufferInputStream messageStream) {
//Acts as a request when received
}

@Override
public void write(ByteBufferOutputStream messageStream) {
messageStream.writeString(Stream.concat(
((LaunchClassLoader) InMemoryJavaCompiler.class.getClassLoader()).getSources()
.stream()
.map(url -> {
try {
return Paths.get(url.toURI()).toAbsolutePath().normalize().toString();
} catch (URISyntaxException | FileSystemNotFoundException e) {
return null;
}
})
.filter(Objects::nonNull)
.filter(s -> !s.contains("akka") && !s.contains("jre\\lib") && !s.contains("jdk") && !s.contains("forge-")),
Stream.of(TotalDebug.PROXY.getMinecraftClassDumpPath().toString())
).collect(Collectors.joining(";"))
);
}

public static void handle(ClassPathMessage m) {
CompletableFuture.runAsync(() -> {
ClassUtil.dumpMinecraftClasses();
TotalDebug.PROXY.getCompanionApp().getClient().getMessageProcessor().enqueueMessage(new ClassPathMessage());
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.minecraft_ta.totaldebug.companionApp.messages.script;

public enum ExecutionEnvironment {
THREAD,
PRE_TICK,
POST_TICK;
}
Loading

0 comments on commit 2d612d8

Please sign in to comment.