diff --git a/.gitignore b/.gitignore index b4e87106..81b82f5c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,8 @@ eclipse run/ logs/ /.apt_generated_tests/ +.kilo +fix_*.ps1 +error*.txt +PScommand.txt +PROGRESS.md diff --git a/README.md b/README.md index 4077b073..d5d0abbe 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ A [Tool-Assisted Speedrun](https://tasvideos.org/WelcomeToTASVideos) mod for Min Adds tools such as input playback, slowdown and savestates for creating TASes, which aim to beat the game as fast as possible. +> [!Warning] +This port project is AI slop!! + # Installation This mod uses the modloader [LegacyFabric](https://legacyfabric.net/), a fork of [Fabric](https://fabricmc.net/) for versions below 1.14.4. **Does NOT need LegacyFabric-API** diff --git a/build.gradle b/build.gradle index 0dacea1f..52c17c75 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,5 @@ plugins { - // loom plugin - id "fabric-loom" version "${loom_version}" - id "ploceus" version "${loom_version}" + id "net.fabricmc.fabric-loom" version "${loom_version}" id "com.palantir.git-version" version "4.2.0" id "com.diffplug.spotless" version "8.1.0" } @@ -19,8 +17,7 @@ base { } java { - // compile for java 8 - sourceCompatibility = targetCompatibility = 8 + sourceCompatibility = targetCompatibility = JavaVersion.VERSION_25 } loom { @@ -35,31 +32,23 @@ repositories { mavenCentral() maven { url = "https://maven.minecrafttas.com/main" } maven { url = "https://maven.legacyfabric.net/" } - //maven { url = "https://maven.minecrafttas.com/snapshots" } maven { url = "https://jitpack.io" } maven { url = "https://repo.spongepowered.org/maven" } } -// dependency configurations -configurations { - // embed dependency included in build - implementation.extendsFrom(embed) -} - -ploceus { - setIntermediaryGeneration(2) -} - // dependencies dependencies { // tasmod dependencies - embed "com.dselent:bigarraylist:1.6" - embed "com.github.KaptainWutax:SeedUtils:b6a383113c" + implementation "com.dselent:bigarraylist:1.6" + include "com.dselent:bigarraylist:1.6" + implementation "com.github.KaptainWutax:SeedUtils:b6a383113c" + include "com.github.KaptainWutax:SeedUtils:b6a383113c" // loom dependencies minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings ploceus.mcpMappings(project.mcp_channel, project.mcp_mcversion, project.mcp_build) - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + implementation "net.fabricmc:fabric-loader:${project.loader_version}" + implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" + implementation "org.lwjgl:lwjgl-glfw:3.4.3" // testing dependencies testImplementation "org.junit.jupiter:junit-jupiter:5.14.1" @@ -68,7 +57,7 @@ dependencies { compileJava { - options.release = 8 + options.release = 25 } // process fabric mod json @@ -83,13 +72,11 @@ processResources { // configure jar file jar { - - // pack embedded stuff from { - configurations.embed.collect { it.isDirectory() ? it : zipTree(it) } + configurations.include.collect { it.isDirectory() ? it : zipTree(it) } } { - exclude "LICENSE.txt", "META-INF/MANIFSET.MF", "META-INF/maven/**", "META-INF/*.RSA", "META-INF/*.SF" - } + exclude "LICENSE.txt", "META-INF/MANIFEST.MF", "META-INF/maven/**", "META-INF/*.RSA", "META-INF/*.SF" + } } // configure testing @@ -109,4 +96,4 @@ spotless { eclipse().configFile("formatter/TASmodFormatter.xml") } enforceCheck false -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index 19e25ce6..6f95443c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,12 +2,10 @@ org.gradle.jvmargs=-Xmx3G # Fabric properties -minecraft_version=1.12.2 -loader_version=0.18.4 -loom_version=1.15-SNAPSHOT -mcp_channel=stable -mcp_build=39 -mcp_mcversion=1.12 +minecraft_version=26.3 +loader_version=0.19.5 +loom_version=1.17-SNAPSHOT +fabric_api_version=0.161.0+26.3 # Mod properties mod_name=Tool-Assisted Speedrun Mod @@ -18,6 +16,6 @@ mod_email=scribble@minecrafttas.com # TASmod properties group=com.minecrafttas -artifact=TASmod-1.12.2 +artifact=TASmod-26.3 version=Beta2.2 -release=false +release=false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f78a6a..7e7d24f6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle b/settings.gradle index b5fd3644..daf8fd6b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,12 +1,16 @@ -// configure plugin management pluginManagement { - // add repositories for plugins repositories { - maven { url = "https://maven.minecrafttas.com/main" } - maven { url = "https://maven.fabricmc.net/" } - maven { url = "https://maven.ornithemc.net/releases" } - maven { url = "https://maven.ornithemc.net/snapshots" } + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + maven { + url = 'https://maven.minecrafttas.com/main' + } + maven { url = 'https://maven.legacyfabric.net/' } + maven { url = 'https://jitpack.io' } + maven { url = 'https://repo.spongepowered.org/maven' } mavenCentral() gradlePluginPortal() } -} \ No newline at end of file +} diff --git a/src/main/java/com/minecrafttas/mctcommon/CommandRegistry.java b/src/main/java/com/minecrafttas/mctcommon/CommandRegistry.java deleted file mode 100644 index 4ce4553c..00000000 --- a/src/main/java/com/minecrafttas/mctcommon/CommandRegistry.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.minecrafttas.mctcommon; - -import net.minecraft.command.CommandHandler; -import net.minecraft.command.ICommand; -import net.minecraft.server.MinecraftServer; - -public class CommandRegistry { - - public static void registerServerCommand(ICommand command, MinecraftServer server) { - CommandHandler ch = (CommandHandler) server.getCommandManager(); - ch.registerCommand(command); - } - -} diff --git a/src/main/java/com/minecrafttas/mctcommon/mixin/MixinNetHandlerPlayClient.java b/src/main/java/com/minecrafttas/mctcommon/mixin/MixinNetHandlerPlayClient.java deleted file mode 100644 index ef700e40..00000000 --- a/src/main/java/com/minecrafttas/mctcommon/mixin/MixinNetHandlerPlayClient.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.minecrafttas.mctcommon.mixin; - -import java.net.ConnectException; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.minecrafttas.mctcommon.events.EventClient.EventOtherPlayerJoinedClientSide; -import com.minecrafttas.mctcommon.events.EventClient.EventPlayerJoinedClientSide; -import com.minecrafttas.mctcommon.events.EventListenerRegistry; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.NetHandlerPlayClient; -import net.minecraft.network.play.server.SPacketPlayerListItem; -import net.minecraft.network.play.server.SPacketPlayerListItem.Action; - -@Mixin(NetHandlerPlayClient.class) -public class MixinNetHandlerPlayClient { - @Shadow - private Minecraft client; - - @Inject(method = "handleJoinGame", at = @At(value = "RETURN")) - public void clientJoinServerEvent(CallbackInfo ci) throws ConnectException { - EventListenerRegistry.fireEvent(EventPlayerJoinedClientSide.class, client.player); - } - - @Inject(method = "handlePlayerListItem", at = @At(value = "HEAD")) - public void otherClientJoinServerEvent(SPacketPlayerListItem packet, CallbackInfo ci) { - for (int i = 0; i < packet.getEntries().size(); i++) { - if (packet.getAction() == Action.ADD_PLAYER) { - EventListenerRegistry.fireEvent(EventOtherPlayerJoinedClientSide.class, packet.getEntries().get(i).getProfile()); - } - } - } -} diff --git a/src/main/java/com/minecrafttas/mctcommon/mixin/MixinPlayerList.java b/src/main/java/com/minecrafttas/mctcommon/mixin/MixinPlayerList.java deleted file mode 100644 index 5476f418..00000000 --- a/src/main/java/com/minecrafttas/mctcommon/mixin/MixinPlayerList.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.minecrafttas.mctcommon.mixin; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.minecrafttas.mctcommon.events.EventListenerRegistry; -import com.minecrafttas.mctcommon.events.EventServer.EventPlayerJoinedServerSide; -import com.minecrafttas.mctcommon.events.EventServer.EventPlayerLeaveServerSide; - -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.network.NetworkManager; -import net.minecraft.server.management.PlayerList; - -@Mixin(PlayerList.class) -public class MixinPlayerList { - @Inject(method = "initializeConnectionToPlayer", at = @At("RETURN"), remap = false) - public void inject_initializeConnectionToPlayer(NetworkManager netManager, EntityPlayerMP playerIn, CallbackInfo ci) { - EventListenerRegistry.fireEvent(EventPlayerJoinedServerSide.class, playerIn); - } - - @Inject(method = "playerLoggedOut", at = @At("HEAD")) - public void inject_playerLoggedOut(EntityPlayerMP playerIn, CallbackInfo ci) { - EventListenerRegistry.fireEvent(EventPlayerLeaveServerSide.class, playerIn); - } -} diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index 51700db5..7a703d91 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -5,12 +5,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import com.minecrafttas.mctcommon.CommandRegistry; -import com.minecrafttas.mctcommon.events.EventListenerRegistry; -import com.minecrafttas.mctcommon.events.EventServer.EventServerInit; -import com.minecrafttas.mctcommon.events.EventServer.EventServerStop; -import com.minecrafttas.mctcommon.networking.PacketHandlerRegistry; -import com.minecrafttas.mctcommon.networking.Server; +import com.minecrafttas.tasmod.mctcommon.events.EventListenerRegistry; +import com.minecrafttas.tasmod.mctcommon.events.EventServer.EventServerInit; +import com.minecrafttas.tasmod.mctcommon.events.EventServer.EventServerStop; +import com.minecrafttas.tasmod.mctcommon.networking.PacketHandlerRegistry; +import com.minecrafttas.tasmod.mctcommon.networking.Server; import com.minecrafttas.tasmod.commands.CommandClearInputs; import com.minecrafttas.tasmod.commands.CommandFileCommand; import com.minecrafttas.tasmod.commands.CommandFullPlay; @@ -39,8 +38,10 @@ import com.minecrafttas.tasmod.util.TabCompletionUtils; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.impl.FabricLoaderImpl; +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.commands.CommandSourceStack; import net.minecraft.server.MinecraftServer; /** @@ -73,7 +74,7 @@ public class TASmod implements ModInitializer, EventServerInit, EventServerStop public static final int networkingport = 8999; - public static final boolean isDevEnvironment = FabricLoaderImpl.INSTANCE.isDevelopmentEnvironment(); + public static final boolean isDevEnvironment = FabricLoader.getInstance().isDevelopmentEnvironment(); public static final StartpositionMetadataExtension startPositionMetadataExtension = new StartpositionMetadataExtension(); @@ -96,12 +97,28 @@ public void onInitialize() { version = modVersion; } + // Register commands + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { + CommandTickrate.register(dispatcher); + CommandRecord.register(dispatcher); + CommandPlay.register(dispatcher); + CommandSaveTAS.register(dispatcher); + CommandLoadTAS.register(dispatcher); + CommandClearInputs.register(dispatcher); + CommandSavestate.register(dispatcher); + CommandFullRecord.register(dispatcher); + CommandFullPlay.register(dispatcher); + CommandRestartAndPlay.register(dispatcher); + CommandPlayUntil.register(dispatcher); + CommandFileCommand.register(dispatcher); + }); + // Start ticksync ticksyncServer = new TickSyncServer(); // Initilize KillTheRNG LOGGER.info("Testing connection with KillTheRNG"); - // ktrngHandler = new KillTheRNGHandler(FabricLoaderImpl.INSTANCE.isModLoaded("killtherng")); + // ktrngHandler = new KillTheRNGHandler(FabricLoader.getInstance().isModLoaded("killtherng")); // Initialize TickrateChanger tickratechanger = new TickrateChangerServer(LOGGER); @@ -139,21 +156,6 @@ public void onServerInit(MinecraftServer server) { LOGGER.info("Initializing server"); serverInstance = server; - // Command handling - - CommandRegistry.registerServerCommand(new CommandTickrate(), server); - CommandRegistry.registerServerCommand(new CommandRecord(), server); - CommandRegistry.registerServerCommand(new CommandPlay(), server); - CommandRegistry.registerServerCommand(new CommandSaveTAS(), server); - CommandRegistry.registerServerCommand(new CommandLoadTAS(), server); - CommandRegistry.registerServerCommand(new CommandClearInputs(), server); - CommandRegistry.registerServerCommand(new CommandSavestate(), server); - CommandRegistry.registerServerCommand(new CommandFullRecord(), server); - CommandRegistry.registerServerCommand(new CommandFullPlay(), server); - CommandRegistry.registerServerCommand(new CommandRestartAndPlay(), server); - CommandRegistry.registerServerCommand(new CommandPlayUntil(), server); - CommandRegistry.registerServerCommand(commandFileCommand, server); - savestateHandlerServer = new SavestateHandlerServer(server, LOGGER); PacketHandlerRegistry.register(savestateHandlerServer); PacketHandlerRegistry.register(savestateHandlerServer.getPlayerHandler()); @@ -202,3 +204,4 @@ public static MinecraftServer getServerInstance() { return serverInstance; } } + diff --git a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java index 8dc8ec4c..2e8fbff0 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java @@ -10,19 +10,19 @@ import org.apache.logging.log4j.Level; -import com.minecrafttas.mctcommon.Configuration; -import com.minecrafttas.mctcommon.ConfigurationRegistry; -import com.minecrafttas.mctcommon.KeybindManager; -import com.minecrafttas.mctcommon.LanguageManager; -import com.minecrafttas.mctcommon.events.EventClient.EventClientInit; -import com.minecrafttas.mctcommon.events.EventClient.EventOpenGui; -import com.minecrafttas.mctcommon.events.EventClient.EventOptionsInit; -import com.minecrafttas.mctcommon.events.EventClient.EventPlayerJoinedClientSide; -import com.minecrafttas.mctcommon.events.EventListenerRegistry; -import com.minecrafttas.mctcommon.file.AbstractDataFile; -import com.minecrafttas.mctcommon.networking.Client; -import com.minecrafttas.mctcommon.networking.PacketHandlerRegistry; -import com.minecrafttas.mctcommon.networking.Server; +import com.minecrafttas.tasmod.mctcommon.Configuration; +import com.minecrafttas.tasmod.mctcommon.ConfigurationRegistry; +import com.minecrafttas.tasmod.mctcommon.KeybindManager; +import com.minecrafttas.tasmod.mctcommon.LanguageManager; +import com.minecrafttas.tasmod.mctcommon.events.EventClient.EventClientInit; +import com.minecrafttas.tasmod.mctcommon.events.EventClient.EventOpenGui; +import com.minecrafttas.tasmod.mctcommon.events.EventClient.EventOptionsInit; +import com.minecrafttas.tasmod.mctcommon.events.EventClient.EventPlayerJoinedClientSide; +import com.minecrafttas.tasmod.mctcommon.events.EventListenerRegistry; +import com.minecrafttas.tasmod.mctcommon.file.AbstractDataFile; +import com.minecrafttas.tasmod.mctcommon.networking.Client; +import com.minecrafttas.tasmod.mctcommon.networking.PacketHandlerRegistry; +import com.minecrafttas.tasmod.mctcommon.networking.Server; import com.minecrafttas.tasmod.commands.client.CommandFolder; import com.minecrafttas.tasmod.gui.InfoHud; import com.minecrafttas.tasmod.handlers.LoadingScreenHandler; @@ -52,23 +52,32 @@ import net.fabricmc.api.ClientModInitializer; import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.EntityPlayerSP; -import net.minecraft.client.gui.GuiControls; -import net.minecraft.client.gui.GuiMainMenu; -import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.multiplayer.ServerData; -import net.minecraft.client.settings.GameSettings; +import net.minecraft.client.Options; import net.minecraft.server.MinecraftServer; +import java.nio.file.Paths; + public class TASmodClient implements ClientModInitializer, EventClientInit, EventPlayerJoinedClientSide, EventOpenGui, EventOptionsInit { public static VirtualInput virtual; public static TickSyncClient ticksyncClient; - public final static Path tasfiledirectory = Minecraft.getMinecraft().gameDir.toPath().resolve("saves").resolve("tasfiles"); + public static Path getTasFileDirectory() { + return Paths.get(".").toAbsolutePath().resolve("saves").resolve("tasfiles"); + } + + public static Path getSavestateDirectory() { + return Paths.get(".").toAbsolutePath().resolve("saves").resolve("savestates"); + } - public final static Path savestatedirectory = Minecraft.getMinecraft().gameDir.toPath().resolve("saves").resolve("savestates"); + // Static fields for backward compatibility with other classes + public static final Path tasfiledirectory = getTasFileDirectory(); + public static final Path savestatedirectory = getSavestateDirectory(); public static InfoHud hud; @@ -80,7 +89,7 @@ public class TASmodClient implements ClientModInitializer, EventClientInit, Even public static Scheduler tickSchedulerClient = new Scheduler(); - public static Scheduler openMainMenuScheduler = new Scheduler(); + public static Scheduler openTitleScreenScheduler = new Scheduler(); public static Configuration config; @@ -103,7 +112,7 @@ public class TASmodClient implements ClientModInitializer, EventClientInit, Even public static void createTASfileDir() { try { - AbstractDataFile.createDirectory(tasfiledirectory); + AbstractDataFile.createDirectory(getTasFileDirectory()); } catch (IOException e) { TASmod.LOGGER.catching(e); } @@ -111,7 +120,7 @@ public static void createTASfileDir() { public static void createSavestatesDir() { try { - AbstractDataFile.createDirectory(savestatedirectory); + AbstractDataFile.createDirectory(getSavestateDirectory()); } catch (IOException e) { TASmod.LOGGER.catching(e); } @@ -126,7 +135,7 @@ public void onInitializeClient() { registerConfigValues(); - Minecraft mc = Minecraft.getMinecraft(); + Minecraft mc = Minecraft.getInstance(); loadConfig(mc); @@ -186,8 +195,8 @@ private void registerEventListeners() { EventListenerRegistry.register(ticksyncClient); EventListenerRegistry.register(keybindManager); EventListenerRegistry.register((EventOpenGui) (gui -> { - if (gui instanceof GuiMainMenu) { - openMainMenuScheduler.runAllTasks(); + if (gui instanceof TitleScreen) { + openTitleScreenScheduler.runAllTasks(); } return gui; })); @@ -202,7 +211,8 @@ private void registerEventListeners() { EventListenerRegistry.register(new LoggerMarkers()); EventListenerRegistry.register(savestateHandlerClient); - EventListenerRegistry.register(virtual.interpolationHandler); + // virtual.interpolationHandler is not an EventBase, handled elsewhere + // EventListenerRegistry.register(virtual.interpolationHandler); EventListenerRegistry.register(tickratechanger); } @@ -218,9 +228,9 @@ public void onClientInit(Minecraft mc) { boolean isLoading; @Override - public void onPlayerJoinedClientSide(EntityPlayerSP player) { - Minecraft mc = Minecraft.getMinecraft(); - ServerData data = mc.getCurrentServerData(); + public void onPlayerJoinedClientSide(LocalPlayer player) { + Minecraft mc = Minecraft.getInstance(); + ServerData data = mc.getCurrentServer(); MinecraftServer server = TASmod.getServerInstance(); String ip = null; @@ -230,10 +240,12 @@ public void onPlayerJoinedClientSide(EntityPlayerSP player) { ip = "localhost"; port = TASmod.server.port; local = true; - } else { - ip = data.serverIP.split(":")[0]; + } else if (data != null) { + ip = data.ip.split(":")[0]; port = TASmod.networkingport; local = false; + } else { + return; // No server data available } String connectedIP = null; @@ -243,7 +255,7 @@ public void onPlayerJoinedClientSide(EntityPlayerSP player) { e.printStackTrace(); } - if (!(ip + ":" + port).equals(connectedIP)) { // TODO Clean this up. Make TASmodNetworkHandler out of this... Maybe with Permission system? + if (!(ip + ":" + port).equals(connectedIP)) { try { LOGGER.info("Closing client connection: {}", client.getRemote()); client.disconnect(); @@ -255,9 +267,9 @@ public void onPlayerJoinedClientSide(EntityPlayerSP player) { gameLoopSchedulerClient.add(() -> { try { // connect to server and authenticate - client = new Client(IP, PORT, TASmodPackets.values(), mc.getSession().getUsername(), local); + client = new Client(IP, PORT, TASmodPackets.values(), mc.getUser().getName(), local); } catch (TimeoutException e) { - mc.getConnection().getNetworkManager().closeChannel(null); + // mc.getConnection().getNetworkManager().closeChannel(null); // API changed } catch (Exception e) { LOGGER.error("Unable to connect TASmod client: {}", e.getMessage()); e.printStackTrace(); @@ -267,16 +279,16 @@ public void onPlayerJoinedClientSide(EntityPlayerSP player) { } @Override - public GuiScreen onOpenGui(GuiScreen gui) { - if (gui instanceof GuiMainMenu) { + public Screen onOpenGui(Screen gui) { + if (gui instanceof TitleScreen) { initializeCustomPacketHandler(); - } else if (gui instanceof GuiControls) { + } else if (gui != null && gui.getClass().getSimpleName().equals("ControlsScreen")) { TASmodClient.controller.setTASState(TASstate.NONE); // Set the TASState to nothing to avoid collisions if (TASmodClient.tickratechanger.ticksPerSecond == 0) { TASmodClient.tickratechanger.pauseClientGame(false); // Unpause the game waszero = true; } - } else if (!(gui instanceof GuiControls)) { + } else if (gui != null && !gui.getClass().getSimpleName().equals("ControlsScreen")) { if (waszero) { waszero = false; TASmodClient.tickratechanger.pauseClientGame(true); @@ -287,7 +299,7 @@ public GuiScreen onOpenGui(GuiScreen gui) { private void initializeCustomPacketHandler() { if (client == null) { - Minecraft mc = Minecraft.getMinecraft(); + Minecraft mc = Minecraft.getInstance(); String IP = "localhost"; int PORT = TASmod.server.port; @@ -308,7 +320,7 @@ private void initializeCustomPacketHandler() { try { // connect to server and authenticate - client = new Client(IP, PORT, TASmodPackets.values(), mc.getSession().getUsername(), true); + client = new Client(IP, PORT, TASmodPackets.values(), mc.getUser().getName(), true); } catch (Exception e) { LOGGER.error("Unable to connect TASmod client: {}", e); } @@ -316,10 +328,10 @@ private void initializeCustomPacketHandler() { } @Override - public void onOptionsInit(GameSettings options) { + public void onOptionsInit(Options options) { // Initialize keybind manager keybindManager.registerKeybinds(options, TASmodKeybinds.class); - Arrays.stream(TASmodKeybinds.valuesVanillaKeybind()).forEach(VirtualKeybindings::registerBlockedKeyBinding); + Arrays.stream(TASmodKeybinds.valuesVanillaKeybind()).forEach(VirtualKeybindings::registerBlockedKeyMapping); } private void registerPlaybackMetadata(Minecraft mc) { @@ -354,7 +366,7 @@ private void registerConfigValues() { } private void loadConfig(Minecraft mc) { - Path configDir = mc.gameDir.toPath().resolve("config"); + Path configDir = Paths.get(".").toAbsolutePath().resolve("config"); if (!Files.exists(configDir)) { try { Files.createDirectory(configDir); @@ -368,3 +380,4 @@ private void loadConfig(Minecraft mc) { config.save(); } } + diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandClearInputs.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandClearInputs.java index 21c192e8..2b13de2a 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandClearInputs.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandClearInputs.java @@ -1,35 +1,52 @@ package com.minecrafttas.tasmod.commands; import com.minecrafttas.tasmod.TASmod; - -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.server.MinecraftServer; - -public class CommandClearInputs extends CommandBase { - - @Override - public String getName() { - return "clearinputs"; - } - - @Override - public String getUsage(ICommandSender sender) { - return "/clearinputs"; - } - - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - if (sender instanceof EntityPlayer) { - TASmod.playbackControllerServer.clearInputs(); - } - } - - @Override - public int getRequiredPermissionLevel() { - return 2; - } - -} +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.context.CommandContext; + +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; +import net.minecraft.world.entity.player.Player; + +public class CommandClearInputs { + + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("clearinputs") + .executes(CommandClearInputs::execute) + ); + } + + private static int execute(CommandContext context) { + CommandSourceStack source = context.getSource(); + // Permission check - use reflection or try different method names + try { + java.lang.reflect.Method method = source.getClass().getMethod("hasPermission", int.class); + if (!((Boolean) method.invoke(source, 2))) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + } catch (Exception e) { + // Fallback: try getPermission() >= 2 + try { + java.lang.reflect.Method method = source.getClass().getMethod("getPermission"); + if (!((Integer) method.invoke(source) >= 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + } catch (Exception ex) { + // Skip permission check if methods not found + } + } + if (!(source.getEntity() instanceof Player)) { + source.sendFailure(Component.literal("Only players can use this command").withStyle(ChatFormatting.RED)); + return 0; + } + + TASmod.playbackControllerServer.clearInputs(); + source.sendSuccess(() -> Component.literal("Cleared inputs").withStyle(ChatFormatting.GREEN), false); + return 1; + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandFileCommand.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandFileCommand.java index 7b0bbff2..5b1a3ae2 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandFileCommand.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandFileCommand.java @@ -3,6 +3,33 @@ import static com.minecrafttas.tasmod.registries.TASmodPackets.COMMAND_FILECOMMANDLIST; import static com.minecrafttas.tasmod.registries.TASmodPackets.PLAYBACK_FILECOMMAND_ENABLE; +import com.minecrafttas.tasmod.mctcommon.networking.Client.Side; +import com.minecrafttas.tasmod.mctcommon.networking.exception.PacketNotImplementedException; +import com.minecrafttas.tasmod.mctcommon.networking.exception.WrongSideException; +import com.minecrafttas.tasmod.mctcommon.networking.interfaces.ClientPacketHandler; +import com.minecrafttas.tasmod.mctcommon.networking.interfaces.PacketID; +import com.minecrafttas.tasmod.mctcommon.networking.interfaces.ServerPacketHandler; +import com.minecrafttas.tasmod.TASmod; +import com.minecrafttas.tasmod.TASmodClient; +import com.minecrafttas.tasmod.networking.TASmodBufferBuilder; +import com.minecrafttas.tasmod.playback.filecommands.PlaybackFileCommand.PlaybackFileCommandExtension; +import com.minecrafttas.tasmod.registries.TASmodAPIRegistry; +import com.minecrafttas.tasmod.registries.TASmodPackets; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; + import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -16,189 +43,182 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.minecrafttas.mctcommon.networking.Client.Side; -import com.minecrafttas.mctcommon.networking.exception.PacketNotImplementedException; -import com.minecrafttas.mctcommon.networking.exception.WrongSideException; -import com.minecrafttas.mctcommon.networking.interfaces.ClientPacketHandler; -import com.minecrafttas.mctcommon.networking.interfaces.PacketID; -import com.minecrafttas.mctcommon.networking.interfaces.ServerPacketHandler; -import com.minecrafttas.tasmod.TASmod; -import com.minecrafttas.tasmod.TASmodClient; -import com.minecrafttas.tasmod.networking.TASmodBufferBuilder; -import com.minecrafttas.tasmod.playback.filecommands.PlaybackFileCommand.PlaybackFileCommandExtension; -import com.minecrafttas.tasmod.registries.TASmodAPIRegistry; -import com.minecrafttas.tasmod.registries.TASmodPackets; - -import net.minecraft.client.Minecraft; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.command.PlayerNotFoundException; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.ChatType; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextFormatting; - -public class CommandFileCommand extends CommandBase implements ClientPacketHandler, ServerPacketHandler { - - CompletableFuture> fileCommandList = null; - - @Override - public String getName() { - return "filecommand"; - } - - @Override - public String getUsage(ICommandSender iCommandSender) { - return "/filecommand "; - } - - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - if (sender instanceof EntityPlayer) { - if (sender.canUseCommand(2, "fileCommand")) { - - String senderName = null; - - // Get the list of file commands from the server - Map fileCommandNames; - try { - senderName = getCommandSenderAsPlayer(sender).getName(); - fileCommandNames = getExtensions(senderName); - } catch (PlayerNotFoundException | InterruptedException | ExecutionException | TimeoutException e) { - sender.sendMessage(new TextComponentString(e.getMessage())); - return; - } - - if (args.length == 0) { // Displays all enabled and disabled filecommands - sender.sendMessage(new TextComponentString(String.join(" ", getColoredNames(fileCommandNames)))); - } else if (args.length == 1) { // Toggles the filecommand - - String name = args[0]; - Boolean enable = fileCommandNames.get(name); - - if (enable == null) { - throw new CommandException("The file command was not found: %s", name); - } - - try { - TASmod.server.sendTo(senderName, new TASmodBufferBuilder(PLAYBACK_FILECOMMAND_ENABLE).writeString(name).writeBoolean(!enable)); - } catch (Exception e) { - e.printStackTrace(); - } - } - } else { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "You have no permission to use this command")); - } - } - } - - @Override - public List getTabCompletions(MinecraftServer minecraftServer, ICommandSender iCommandSender, String[] args, BlockPos blockPos) { - if (args.length == 1) { - List names = null; - try { - names = new ArrayList<>(getExtensions(getCommandSenderAsPlayer(iCommandSender).getName()).keySet()); - } catch (PlayerNotFoundException | InterruptedException | ExecutionException | TimeoutException e) { - e.printStackTrace(); - return super.getTabCompletions(minecraftServer, iCommandSender, args, blockPos); - } - return getListOfStringsMatchingLastWord(args, names); - } - return super.getTabCompletions(minecraftServer, iCommandSender, args, blockPos); - } - - private Map getExtensions(String playername) throws InterruptedException, ExecutionException, TimeoutException { - Map out = new LinkedHashMap<>(); - fileCommandList = new CompletableFuture<>(); - - try { - TASmod.server.sendTo(playername, new TASmodBufferBuilder(COMMAND_FILECOMMANDLIST)); - } catch (Exception e) { - e.printStackTrace(); - } - - List commands = fileCommandList.get(2, TimeUnit.SECONDS); - - commands.forEach(element -> { - - Pattern pattern = Pattern.compile("^E_"); - Matcher matcher = pattern.matcher(element); - if (matcher.find()) { - element = matcher.replaceFirst(""); - out.put(element, true); - return; - } - - pattern = Pattern.compile("^D_"); - matcher = pattern.matcher(element); - if (matcher.find()) { - element = matcher.replaceFirst(""); - out.put(element, false); - return; - } - }); - - return out; - } - - private List getColoredNames(Map list) { - List out = new ArrayList<>(); - list.forEach((name, enabled) -> { - out.add(String.format("%s%s%s", enabled ? TextFormatting.GREEN : TextFormatting.RED, name, TextFormatting.RESET)); - }); - return out; - } - - @Override - public PacketID[] getAcceptedPacketIDs() { - return new PacketID[] { COMMAND_FILECOMMANDLIST, PLAYBACK_FILECOMMAND_ENABLE }; - } - - @Override - public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception { - TASmodPackets packet = (TASmodPackets) id; - switch (packet) { - case COMMAND_FILECOMMANDLIST: - String filecommandnames = TASmodBufferBuilder.readString(buf); - fileCommandList.complete(Arrays.asList(filecommandnames.split("\\|"))); - break; - default: - throw new WrongSideException(packet, Side.SERVER); - } - } - - // ========== Client - - @Override - public void onClientPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception { - TASmodPackets packet = (TASmodPackets) id; - switch (packet) { - case COMMAND_FILECOMMANDLIST: - String filecommandnames = String.join("|", getFileCommandNames(TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.getAll())); - TASmodClient.client.send(new TASmodBufferBuilder(COMMAND_FILECOMMANDLIST).writeString(filecommandnames)); - break; - case PLAYBACK_FILECOMMAND_ENABLE: - String filecommand = TASmodBufferBuilder.readString(buf); - boolean enable = TASmodBufferBuilder.readBoolean(buf); - boolean success = TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.setEnabled(filecommand, enable); - - String msg = success ? String.format("%s%s file command: %s", TextFormatting.GREEN, enable ? "Enabled" : "Disabled", filecommand) : String.format("%sFailed to %s file command: %s", TextFormatting.RED, enable ? "enable" : "disable", filecommand); - Minecraft.getMinecraft().ingameGUI.addChatMessage(ChatType.CHAT, new TextComponentString(msg)); - break; - default: - break; - } - } - - private List getFileCommandNames(List fileCommands) { - List out = new ArrayList<>(); - fileCommands.forEach(element -> { - out.add(String.format("%s_%s", element.isEnabled() ? "E" : "D", element.toString())); - }); - return out; - } - -} +import java.lang.reflect.Method; + +public class CommandFileCommand implements ClientPacketHandler, ServerPacketHandler { + + private static final SimpleCommandExceptionType USAGE_EXCEPTION = new SimpleCommandExceptionType(Component.literal("/filecommand ")); + + static CompletableFuture> fileCommandList = null; + + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("filecommand") + .executes(CommandFileCommand::showList) + .then(Commands.argument("name", StringArgumentType.string()) + .suggests(CommandFileCommand::suggestFileCommands) + .executes(CommandFileCommand::toggleFileCommand) + ) + ); + } + + private static int showList(CommandContext context) { + CommandSourceStack sender = context.getSource(); + if (!checkPermission(sender, 2)) { + sender.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + try { + Map fileCommandNames = getExtensions(sender); + sender.sendSuccess(() -> Component.literal(String.join(" ", getColoredNames(fileCommandNames))), false); + } catch (Exception e) { + sender.sendFailure(Component.literal(e.getMessage()).withStyle(ChatFormatting.RED)); + } + return 1; + } + + private static int toggleFileCommand(CommandContext context) { + CommandSourceStack sender = context.getSource(); + if (!checkPermission(sender, 2)) { + sender.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + String name = StringArgumentType.getString(context, "name"); + + try { + Map fileCommandNames = getExtensions(sender); + Boolean enable = fileCommandNames.get(name); + + if (enable == null) { + sender.sendFailure(Component.literal("The file command was not found: " + name).withStyle(ChatFormatting.RED)); + return 0; + } + + TASmod.server.sendTo(sender.getPlayer().getName().getString(), new TASmodBufferBuilder(PLAYBACK_FILECOMMAND_ENABLE).writeString(name).writeBoolean(!enable)); + sender.sendSuccess(() -> Component.literal("Toggled file command: " + name).withStyle(ChatFormatting.GREEN), false); + } catch (Exception e) { + TASmod.LOGGER.error("Failed to toggle file command", e); + sender.sendFailure(Component.literal("Failed to toggle file command: " + e.getMessage()).withStyle(ChatFormatting.RED)); + } + return 1; + } + + private static CompletableFuture suggestFileCommands(CommandContext context, SuggestionsBuilder builder) { + CommandSourceStack sender = context.getSource(); + try { + Map fileCommandNames = getExtensions(sender); + for (String name : fileCommandNames.keySet()) { + builder.suggest(name); + } + } catch (Exception e) { + TASmod.LOGGER.error("Failed to get file command list", e); + } + return builder.buildFuture(); + } + + private static Map getExtensions(CommandSourceStack sender) throws InterruptedException, ExecutionException, TimeoutException { + Map out = new LinkedHashMap<>(); + CompletableFuture> future = new CompletableFuture<>(); + fileCommandList = future; + + try { + String senderName = sender.getPlayer().getName().getString(); + TASmod.server.sendTo(senderName, new TASmodBufferBuilder(COMMAND_FILECOMMANDLIST)); + } catch (Exception e) { + e.printStackTrace(); + } + + List commands = future.get(2, TimeUnit.SECONDS); + + commands.forEach(element -> { + Pattern pattern = Pattern.compile("^E_"); + Matcher matcher = pattern.matcher(element); + if (matcher.find()) { + element = matcher.replaceFirst(""); + out.put(element, true); + return; + } + + pattern = Pattern.compile("^D_"); + matcher = pattern.matcher(element); + if (matcher.find()) { + element = matcher.replaceFirst(""); + out.put(element, false); + return; + } + }); + + return out; + } + + private static List getColoredNames(Map list) { + List out = new ArrayList<>(); + list.forEach((name, enabled) -> { + out.add(String.format("%s%s%s", enabled ? ChatFormatting.GREEN : ChatFormatting.RED, name, ChatFormatting.RESET)); + }); + return out; + } + + @Override + public PacketID[] getAcceptedPacketIDs() { + return new PacketID[] { COMMAND_FILECOMMANDLIST, PLAYBACK_FILECOMMAND_ENABLE }; + } + + @Override + public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception { + TASmodPackets packet = (TASmodPackets) id; + switch (packet) { + case COMMAND_FILECOMMANDLIST: + String filecommandnames = TASmodBufferBuilder.readString(buf); + fileCommandList.complete(Arrays.asList(filecommandnames.split("\\|"))); + break; + default: + throw new WrongSideException(packet, Side.SERVER); + } + } + + // ========== Client + + @Override + public void onClientPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception { + TASmodPackets packet = (TASmodPackets) id; + switch (packet) { + case COMMAND_FILECOMMANDLIST: + String filecommandnames = String.join("|", getFileCommandNames(TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.getAll())); + TASmodClient.client.send(new TASmodBufferBuilder(COMMAND_FILECOMMANDLIST).writeString(filecommandnames)); + break; + case PLAYBACK_FILECOMMAND_ENABLE: + String filecommand = TASmodBufferBuilder.readString(buf); + boolean enable = TASmodBufferBuilder.readBoolean(buf); + boolean success = TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.setEnabled(filecommand, enable); + + String msg = success ? String.format("%s%s file command: %s", ChatFormatting.GREEN, enable ? "Enabled" : "Disabled", filecommand) : String.format("%sFailed to %s file command: %s", ChatFormatting.RED, enable ? "enable" : "disable", filecommand); + // Minecraft.getInstance().gui.getChat().addMessage(Component.literal(msg)); + break; + default: + break; + } + } + + private List getFileCommandNames(List fileCommands) { + List out = new ArrayList<>(); + fileCommands.forEach(element -> { + out.add(String.format("%s_%s", element.isEnabled() ? "E" : "D", element.toString())); + }); + return out; + } + + private static boolean checkPermission(CommandSourceStack source, int level) { + try { + Method method = source.getClass().getMethod("hasPermission", int.class); + return (Boolean) method.invoke(source, level); + } catch (Exception e) { + try { + Method method = source.getClass().getMethod("getPermission"); + return (Integer) method.invoke(source) >= level; + } catch (Exception ex) { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandFullPlay.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandFullPlay.java index e45a3352..0b768bc2 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandFullPlay.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandFullPlay.java @@ -1,26 +1,47 @@ package com.minecrafttas.tasmod.commands; import com.minecrafttas.tasmod.TASmod; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.context.CommandContext; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.server.MinecraftServer; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; -public class CommandFullPlay extends CommandBase { +import java.lang.reflect.Method; - @Override - public String getName() { - return "fullplay"; - } +public class CommandFullPlay { - @Override - public String getUsage(ICommandSender sender) { - return "/fullplay"; - } + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("fullplay") + .executes(CommandFullPlay::execute) + ); + } - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - TASmod.playbackControllerServer.fullPlay(); - } -} + private static int execute(CommandContext context) { + CommandSourceStack source = context.getSource(); + if (!checkPermission(source, 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + TASmod.playbackControllerServer.fullPlay(); + context.getSource().sendSuccess(() -> Component.literal("Full play started").withStyle(ChatFormatting.GREEN), false); + return 1; + } + + private static boolean checkPermission(CommandSourceStack source, int level) { + try { + Method method = source.getClass().getMethod("hasPermission", int.class); + return (Boolean) method.invoke(source, level); + } catch (Exception e) { + try { + Method method = source.getClass().getMethod("getPermission"); + return (Integer) method.invoke(source) >= level; + } catch (Exception ex) { + return true; // Skip permission check if methods not found + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandFullRecord.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandFullRecord.java index b50d8053..d40522e0 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandFullRecord.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandFullRecord.java @@ -1,26 +1,47 @@ package com.minecrafttas.tasmod.commands; import com.minecrafttas.tasmod.TASmod; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.context.CommandContext; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.server.MinecraftServer; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; -public class CommandFullRecord extends CommandBase { +import java.lang.reflect.Method; - @Override - public String getName() { - return "fullrecord"; - } +public class CommandFullRecord { - @Override - public String getUsage(ICommandSender sender) { - return "/fullrecord"; - } + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("fullrecord") + .executes(CommandFullRecord::execute) + ); + } - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - TASmod.playbackControllerServer.fullRecord(); - } -} + private static int execute(CommandContext context) { + CommandSourceStack source = context.getSource(); + if (!checkPermission(source, 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + TASmod.playbackControllerServer.fullRecord(); + context.getSource().sendSuccess(() -> Component.literal("Full record started").withStyle(ChatFormatting.GREEN), false); + return 1; + } + + private static boolean checkPermission(CommandSourceStack source, int level) { + try { + Method method = source.getClass().getMethod("hasPermission", int.class); + return (Boolean) method.invoke(source, level); + } catch (Exception e) { + try { + Method method = source.getClass().getMethod("getPermission"); + return (Integer) method.invoke(source) >= level; + } catch (Exception ex) { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandLoadTAS.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandLoadTAS.java index 2aeb6974..0806edc0 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandLoadTAS.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandLoadTAS.java @@ -1,104 +1,110 @@ package com.minecrafttas.tasmod.commands; -import java.util.List; -import java.util.concurrent.TimeoutException; - -import com.google.common.collect.ImmutableList; import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.networking.TASmodBufferBuilder; import com.minecrafttas.tasmod.registries.TASmodPackets; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextFormatting; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; +import net.minecraft.world.entity.player.Player; -public class CommandLoadTAS extends CommandBase { - - @Override - public String getName() { - return "load"; - } +import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.TimeoutException; - @Override - public String getUsage(ICommandSender sender) { - return "/load [flavor]"; - } +public class CommandLoadTAS { - @Override - public List getAliases() { - return ImmutableList.of("loadTAS"); - } + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("load") + .then(Commands.argument("filename", StringArgumentType.string()) + .suggests((context, builder) -> { + CommandSourceStack source = context.getSource(); + if (source.getEntity() instanceof Player player) { + try { + List files = TASmod.tabCompletionUtils.getTASfileList(player.getName().getString()); + for (String file : files) { + builder.suggest(file); + } + } catch (TimeoutException e) { + TASmod.LOGGER.catching(e); + } catch (Exception e) { + TASmod.LOGGER.catching(e); + } + } + return builder.buildFuture(); + }) + .executes(CommandLoadTAS::execute) + .then(Commands.argument("flavor", StringArgumentType.string()) + .suggests((context, builder) -> { + CommandSourceStack source = context.getSource(); + if (source.getEntity() instanceof Player player) { + try { + List flavors = TASmod.tabCompletionUtils.getFlavorList(player.getName().getString()); + for (String flavor : flavors) { + builder.suggest(flavor); + } + } catch (TimeoutException e) { + TASmod.LOGGER.catching(e); + } catch (Exception e) { + TASmod.LOGGER.catching(e); + } + } + return builder.buildFuture(); + }) + .executes(CommandLoadTAS::executeWithFlavor) + ) + ) + ); + } - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - if (sender instanceof EntityPlayer) { - if (sender.canUseCommand(2, "load")) { - if (args.length < 1) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Please add a filename, " + getUsage(sender))); - } else if (args.length == 1) { - String filename = args[0]; - try { - TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.PLAYBACK_LOAD).writeString(filename).writeString("")); - } catch (Exception e) { - e.printStackTrace(); - } - } else if (args.length == 2) { - String filename = args[0]; - String flavorname = args[1]; - try { - TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.PLAYBACK_LOAD).writeString(filename).writeString(flavorname)); - } catch (Exception e) { - e.printStackTrace(); - } - } - } else { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "You have no permission to use this command")); - } - } - } + private static int execute(CommandContext context) { + return executeImpl(context, ""); + } - @Override - public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) { - List tab; - if (args.length == 1) { - try { - tab = TASmod.tabCompletionUtils.getTASfileList(getCommandSenderAsPlayer(sender).getName()); - } catch (TimeoutException e) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Failed to fetch the file list after 2 seconds, something went wrong")); - TASmod.LOGGER.catching(e); - return super.getTabCompletions(server, sender, args, targetPos); - } catch (Exception e) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Something went wrong with Tab Completions")); - TASmod.LOGGER.catching(e); - return super.getTabCompletions(server, sender, args, targetPos); - } + private static int executeWithFlavor(CommandContext context) { + String flavor = StringArgumentType.getString(context, "flavor"); + return executeImpl(context, flavor); + } - if (tab.isEmpty()) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "No files in directory")); - return super.getTabCompletions(server, sender, args, targetPos); - } - return getListOfStringsMatchingLastWord(args, tab); + private static int executeImpl(CommandContext context, String flavor) { + CommandSourceStack source = context.getSource(); + if (!checkPermission(source, 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + if (!(source.getEntity() instanceof Player)) { + source.sendFailure(Component.literal("Only players can use this command").withStyle(ChatFormatting.RED)); + return 0; + } - } else if (args.length == 2) { - try { - tab = TASmod.tabCompletionUtils.getFlavorList(getCommandSenderAsPlayer(sender).getName()); - } catch (TimeoutException e) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Failed to fetch the flavor list after 2 seconds, something went wrong")); - TASmod.LOGGER.catching(e); - return super.getTabCompletions(server, sender, args, targetPos); - } catch (Exception e) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Something went wrong with Tab Completions")); - TASmod.LOGGER.catching(e); - return super.getTabCompletions(server, sender, args, targetPos); - } - return getListOfStringsMatchingLastWord(args, tab); + String filename = StringArgumentType.getString(context, "filename"); + try { + TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.PLAYBACK_LOAD).writeString(filename).writeString(flavor)); + source.sendSuccess(() -> Component.literal("Loaded TAS: " + filename).withStyle(ChatFormatting.GREEN), false); + } catch (Exception e) { + TASmod.LOGGER.error("Failed to load TAS", e); + source.sendFailure(Component.literal("Failed to load TAS: " + e.getMessage()).withStyle(ChatFormatting.RED)); + } + return 1; + } - } else - return super.getTabCompletions(server, sender, args, targetPos); - } -} + private static boolean checkPermission(CommandSourceStack source, int level) { + try { + Method method = source.getClass().getMethod("hasPermission", int.class); + return (Boolean) method.invoke(source, level); + } catch (Exception e) { + try { + Method method = source.getClass().getMethod("getPermission"); + return (Integer) method.invoke(source) >= level; + } catch (Exception ex) { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandPlay.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandPlay.java index f95c10c5..1dbc308f 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandPlay.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandPlay.java @@ -1,68 +1,70 @@ package com.minecrafttas.tasmod.commands; -import java.util.List; - -import com.google.common.collect.ImmutableList; import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.savestates.handlers.SavestateTempHandler; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextFormatting; - -public class CommandPlay extends CommandBase { - - @Override - public String getName() { - return "play"; - } +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; +import net.minecraft.world.entity.player.Player; - @Override - public String getUsage(ICommandSender sender) { - return "/play [nosave]"; - } +import java.lang.reflect.Method; - @Override - public int getRequiredPermissionLevel() { - return 2; - } +public class CommandPlay { - @Override - public List getAliases() { - return ImmutableList.of("p"); - } + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("play") + .executes(CommandPlay::execute) + .then(Commands.literal("nosave") + .executes(CommandPlay::executeNoSave) + ) + ); + } - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - if (!(sender instanceof EntityPlayer)) { - return; - } + private static int execute(CommandContext context) { + return executeImpl(context, false); + } - // Activates temporary savestates, loading one when starting the playback - SavestateTempHandler tempSavestateHandler = TASmod.savestateHandlerServer.getSavestateTemporaryHandler(); - tempSavestateHandler.setActive(true); + private static int executeNoSave(CommandContext context) { + return executeImpl(context, true); + } - if (args.length <= 1) { - boolean noSave = args.length == 1 && "nosave".equals(args[0]); - tempSavestateHandler.setActive(!noSave); + private static int executeImpl(CommandContext context, boolean noSave) { + CommandSourceStack source = context.getSource(); + if (!checkPermission(source, 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + if (!(source.getEntity() instanceof Player)) { + source.sendFailure(Component.literal("Only players can use this command").withStyle(ChatFormatting.RED)); + return 0; + } - TASmod.playbackControllerServer.togglePlayback(); - } else if (args.length > 2) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Too many arguments. " + getUsage(sender))); - } + SavestateTempHandler tempSavestateHandler = TASmod.savestateHandlerServer.getSavestateTemporaryHandler(); + tempSavestateHandler.setActive(true); + tempSavestateHandler.setActive(!noSave); + TASmod.playbackControllerServer.togglePlayback(); - } + source.sendSuccess(() -> Component.literal("Playback " + (noSave ? "without saving" : "started")).withStyle(ChatFormatting.GREEN), false); + return 1; + } - @Override - public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) { - if (args.length == 1) { - return getListOfStringsMatchingLastWord(args, "nosave"); - } - return super.getTabCompletions(server, sender, args, targetPos); - } -} + private static boolean checkPermission(CommandSourceStack source, int level) { + try { + Method method = source.getClass().getMethod("hasPermission", int.class); + return (Boolean) method.invoke(source, level); + } catch (Exception e) { + try { + Method method = source.getClass().getMethod("getPermission"); + return (Integer) method.invoke(source) >= level; + } catch (Exception ex) { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandPlayUntil.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandPlayUntil.java index d34be78e..7a6c4180 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandPlayUntil.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandPlayUntil.java @@ -3,41 +3,68 @@ import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.networking.TASmodBufferBuilder; import com.minecrafttas.tasmod.registries.TASmodPackets; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.text.TextComponentString; - -public class CommandPlayUntil extends CommandBase { - - @Override - public String getName() { - return "playuntil"; - } - - @Override - public String getUsage(ICommandSender sender) { - return "/playuntil "; - } - - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - if (args.length == 1) { - int i = 0; - try { - i = Integer.parseInt(args[0]); - } catch (NumberFormatException e) { - throw new CommandException("{} is not a number", args[0]); - } - try { - TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.PLAYBACK_PLAYUNTIL).writeInt(i)); - } catch (Exception e) { - e.printStackTrace(); - } - } else { - sender.sendMessage(new TextComponentString("Stops the next playback one tick before the specified tick and lets you record from there:\n\n/playuntil 10, runs the playback until tick 9 and will record from there. Useful when you can't savestate")); - } - } -} +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; + +import java.lang.reflect.Method; + +public class CommandPlayUntil { + + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("playuntil") + .then(Commands.argument("ticks", IntegerArgumentType.integer(0)) + .executes(CommandPlayUntil::execute) + ) + .executes(CommandPlayUntil::showUsage) + ); + } + + private static int execute(CommandContext context) { + CommandSourceStack source = context.getSource(); + if (!checkPermission(source, 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + int ticks = IntegerArgumentType.getInteger(context, "ticks"); + try { + TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.PLAYBACK_PLAYUNTIL).writeInt(ticks)); + context.getSource().sendSuccess(() -> Component.literal("Play until tick: " + ticks).withStyle(ChatFormatting.GREEN), false); + } catch (Exception e) { + TASmod.LOGGER.error("Failed to send playuntil packet", e); + context.getSource().sendFailure(Component.literal("Failed to send playuntil packet: " + e.getMessage()).withStyle(ChatFormatting.RED)); + } + return 1; + } + + private static int showUsage(CommandContext context) { + CommandSourceStack source = context.getSource(); + if (!checkPermission(source, 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + context.getSource().sendFailure(Component.literal("Stops the next playback one tick before the specified tick and lets you record from there:\n\n/playuntil 10, runs the playback until tick 9 and will record from there. Useful when you can't savestate").withStyle(ChatFormatting.RED)); + return 0; + } + + private static boolean checkPermission(CommandSourceStack source, int level) { + try { + Method method = source.getClass().getMethod("hasPermission", int.class); + return (Boolean) method.invoke(source, level); + } catch (Exception e) { + try { + Method method = source.getClass().getMethod("getPermission"); + return (Integer) method.invoke(source) >= level; + } catch (Exception ex) { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandRecord.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandRecord.java index 44d8a0d0..87146577 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandRecord.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandRecord.java @@ -1,67 +1,71 @@ package com.minecrafttas.tasmod.commands; -import java.util.List; - -import com.google.common.collect.ImmutableList; import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.savestates.handlers.SavestateTempHandler; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextFormatting; - -public class CommandRecord extends CommandBase { +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; +import net.minecraft.world.entity.player.Player; - @Override - public String getName() { - return "record"; - } +import java.lang.reflect.Method; - @Override - public String getUsage(ICommandSender sender) { - return "/record [nosave]"; - } +public class CommandRecord { - @Override - public int getRequiredPermissionLevel() { - return 2; - } + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("record") + .executes(CommandRecord::execute) + .then(Commands.literal("nosave") + .executes(CommandRecord::executeNoSave) + ) + ); + } - @Override - public List getAliases() { - return ImmutableList.of("r"); - } + private static int execute(CommandContext context) { + return executeImpl(context, false); + } - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - if (!(sender instanceof EntityPlayer)) { - return; - } + private static int executeNoSave(CommandContext context) { + return executeImpl(context, true); + } - // Activates temporary savestates, creating one when starting the recording - SavestateTempHandler tempSavestateHandler = TASmod.savestateHandlerServer.getSavestateTemporaryHandler(); - tempSavestateHandler.setActive(true); + private static int executeImpl(CommandContext context, boolean noSave) { + CommandSourceStack source = context.getSource(); + if (!checkPermission(source, 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + if (!(source.getEntity() instanceof Player)) { + source.sendFailure(Component.literal("Only players can use this command").withStyle(ChatFormatting.RED)); + return 0; + } - if (args.length <= 1) { - boolean noSave = args.length == 1 && "nosave".equals(args[0]); - TASmod.savestateHandlerServer.getSavestateTemporaryHandler().setActive(!noSave); - TASmod.playbackControllerServer.toggleRecording(); - } else if (args.length > 1) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Too many arguments. " + getUsage(sender))); - } + SavestateTempHandler tempSavestateHandler = TASmod.savestateHandlerServer.getSavestateTemporaryHandler(); + tempSavestateHandler.setActive(true); + tempSavestateHandler.setActive(!noSave); + TASmod.playbackControllerServer.toggleRecording(); - } + source.sendSuccess(() -> Component.literal("Recording " + (noSave ? "without saving" : "started")).withStyle(ChatFormatting.GREEN), false); + return 1; + } - @Override - public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) { - if (args.length == 1) { - return getListOfStringsMatchingLastWord(args, "nosave"); - } - return super.getTabCompletions(server, sender, args, targetPos); - } -} + private static boolean checkPermission(CommandSourceStack source, int level) { + try { + Method method = source.getClass().getMethod("hasPermission", int.class); + return (Boolean) method.invoke(source, level); + } catch (Exception e) { + try { + Method method = source.getClass().getMethod("getPermission"); + return (Integer) method.invoke(source) >= level; + } catch (Exception ex) { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandRestartAndPlay.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandRestartAndPlay.java index 382cd872..b0105a8c 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandRestartAndPlay.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandRestartAndPlay.java @@ -1,72 +1,75 @@ package com.minecrafttas.tasmod.commands; +import com.minecrafttas.tasmod.TASmod; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; + import java.io.File; import java.io.FileFilter; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; -import com.minecrafttas.tasmod.TASmod; - -import net.minecraft.client.Minecraft; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextFormatting; - -public class CommandRestartAndPlay extends CommandBase { +public class CommandRestartAndPlay { - @Override - public String getName() { - return "restartandplay"; - } + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("restartandplay") + .then(Commands.argument("filename", StringArgumentType.string()) + .suggests(CommandRestartAndPlay::suggestFilenames) + .executes(CommandRestartAndPlay::execute) + ) + ); + } - @Override - public String getUsage(ICommandSender sender) { - return "/restartandplay "; - } + private static int execute(CommandContext context) { + CommandSourceStack source = context.getSource(); + if (!checkPermission(source, 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + String filename = StringArgumentType.getString(context, "filename"); + TASmod.playbackControllerServer.restartAndPlay(filename); + context.getSource().sendSuccess(() -> Component.literal("Restart and play: " + filename).withStyle(ChatFormatting.GREEN), false); + return 1; + } - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - if (sender.canUseCommand(2, "load")) { - if (args.length < 1) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Please add a filename, " + getUsage(sender))); - } else { - TASmod.playbackControllerServer.restartAndPlay(String.join(" ", args)); - } - } else { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "You have no permission to use this command")); - } - } + private static CompletableFuture suggestFilenames(CommandContext context, SuggestionsBuilder builder) { + List filenames = getFilenames(); + for (String filename : filenames) { + builder.suggest(filename); + } + return builder.buildFuture(); + } - @Override - public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) { - List tab; - if (args.length == 1) { - tab = getFilenames(); - if (tab.isEmpty()) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "No files in directory")); - return super.getTabCompletions(server, sender, args, targetPos); - } - return getListOfStringsMatchingLastWord(args, tab); - } else - return super.getTabCompletions(server, sender, args, targetPos); - } + public static List getFilenames() { + List tab = new ArrayList<>(); + // This is a client-side path, but we'll provide an empty list server-side + // The actual tab completion will be handled client-side via the networking + return tab; + } - public List getFilenames() { - List tab = new ArrayList(); - File folder = new File(Minecraft.getMinecraft().gameDir, "saves" + File.separator + "tasfiles"); - File[] listOfFiles = folder.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.getName().endsWith(".mctas"); - } - }); - for (int i = 0; i < listOfFiles.length; i++) { - tab.add(listOfFiles[i].getName().replaceAll("\\.mctas", "")); - } - return tab; - } -} + private static boolean checkPermission(CommandSourceStack source, int level) { + try { + Method method = source.getClass().getMethod("hasPermission", int.class); + return (Boolean) method.invoke(source, level); + } catch (Exception e) { + try { + Method method = source.getClass().getMethod("getPermission"); + return (Integer) method.invoke(source) >= level; + } catch (Exception ex) { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandSaveTAS.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandSaveTAS.java index e31c7392..000a04d7 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandSaveTAS.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandSaveTAS.java @@ -1,117 +1,112 @@ package com.minecrafttas.tasmod.commands; -import java.util.List; -import java.util.concurrent.TimeoutException; - -import com.google.common.collect.ImmutableList; import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.networking.TASmodBufferBuilder; import com.minecrafttas.tasmod.registries.TASmodPackets; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextFormatting; - -public class CommandSaveTAS extends CommandBase { - - private boolean check = false; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; +import net.minecraft.world.entity.player.Player; - @Override - public String getName() { - return "save"; - } - - @Override - public String getUsage(ICommandSender sender) { - return "/save [flavor]"; - } - - @Override - public List getAliases() { - return ImmutableList.of("saveTAS"); - } +import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.TimeoutException; - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { +public class CommandSaveTAS { - if (sender instanceof EntityPlayer) { - if (sender.canUseCommand(2, "save")) { - if (args.length < 1) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Command must contain a filename " + getUsage(sender))); - } else if (args.length == 1) { - String filename = args[0]; - try { - TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.PLAYBACK_SAVE).writeString(filename).writeString("")); - } catch (Exception e) { - e.printStackTrace(); - } - } else if (args.length == 2) { - String filename = args[0]; - String flavorname = args[1]; - try { - TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.PLAYBACK_SAVE).writeString(filename).writeString(flavorname)); - } catch (Exception e) { - e.printStackTrace(); - } - } - } else { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "You have no permission to use this command")); - } - } - } + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("save") + .executes(CommandSaveTAS::execute) + .then(Commands.argument("filename", StringArgumentType.string()) + .suggests((context, builder) -> { + CommandSourceStack source = context.getSource(); + if (source.getEntity() instanceof Player player) { + try { + List files = TASmod.tabCompletionUtils.getTASfileList(player.getName().getString()); + for (String file : files) { + builder.suggest(file); + } + } catch (TimeoutException e) { + TASmod.LOGGER.catching(e); + } catch (Exception e) { + TASmod.LOGGER.catching(e); + } + } + return builder.buildFuture(); + }) + .executes(CommandSaveTAS::execute) + .then(Commands.argument("flavor", StringArgumentType.string()) + .suggests((context, builder) -> { + CommandSourceStack source = context.getSource(); + if (source.getEntity() instanceof Player player) { + try { + List flavors = TASmod.tabCompletionUtils.getFlavorList(player.getName().getString()); + for (String flavor : flavors) { + builder.suggest(flavor); + } + } catch (TimeoutException e) { + TASmod.LOGGER.catching(e); + } catch (Exception e) { + TASmod.LOGGER.catching(e); + } + } + return builder.buildFuture(); + }) + .executes(CommandSaveTAS::executeWithFlavor) + ) + ) + ); + } - @Override - public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) { - List tab = null; - if (args.length == 1) { - if (!check) { - sender.sendMessage(new TextComponentString(TextFormatting.BOLD + "" + TextFormatting.RED + "WARNING!" + TextFormatting.RESET + TextFormatting.RED - + " Existing filenames will be overwritten! /fail to abort the recording if you accidentally started one")); - check = true; - } - try { - tab = TASmod.tabCompletionUtils.getTASfileList(getCommandSenderAsPlayer(sender).getName()); - } catch (TimeoutException e) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Failed to fetch the file list after 2 seconds, something went wrong")); - TASmod.LOGGER.catching(e); - return super.getTabCompletions(server, sender, args, targetPos); - } catch (Exception e) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Something went wrong with Tab Completions")); - TASmod.LOGGER.catching(e); - return super.getTabCompletions(server, sender, args, targetPos); - } + private static int execute(CommandContext context) { + return executeImpl(context, ""); + } - if (tab.isEmpty()) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "No files in directory")); - return super.getTabCompletions(server, sender, args, targetPos); - } - return getListOfStringsMatchingLastWord(args, tab); + private static int executeWithFlavor(CommandContext context) { + String flavor = StringArgumentType.getString(context, "flavor"); + return executeImpl(context, flavor); + } - } else if (args.length == 2) { - try { - tab = TASmod.tabCompletionUtils.getFlavorList(getCommandSenderAsPlayer(sender).getName()); - } catch (TimeoutException e) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Failed to fetch the flavor list after 2 seconds, something went wrong")); - TASmod.LOGGER.catching(e); - return super.getTabCompletions(server, sender, args, targetPos); - } catch (Exception e) { - sender.sendMessage(new TextComponentString(TextFormatting.RED + "Something went wrong with Tab Completions")); - TASmod.LOGGER.catching(e); - return super.getTabCompletions(server, sender, args, targetPos); - } - return getListOfStringsMatchingLastWord(args, tab); + private static int executeImpl(CommandContext context, String flavor) { + CommandSourceStack source = context.getSource(); + if (!checkPermission(source, 2)) { + source.sendFailure(Component.literal("You don't have permission to use this command").withStyle(ChatFormatting.RED)); + return 0; + } + if (!(source.getEntity() instanceof Player)) { + source.sendFailure(Component.literal("Only players can use this command").withStyle(ChatFormatting.RED)); + return 0; + } - } else - return super.getTabCompletions(server, sender, args, targetPos); - } + String filename = StringArgumentType.getString(context, "filename"); + try { + TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.PLAYBACK_SAVE).writeString(filename).writeString(flavor)); + source.sendSuccess(() -> Component.literal("Saved TAS: " + filename).withStyle(ChatFormatting.GREEN), false); + } catch (Exception e) { + TASmod.LOGGER.error("Failed to save TAS", e); + source.sendFailure(Component.literal("Failed to save TAS: " + e.getMessage()).withStyle(ChatFormatting.RED)); + } + return 1; + } - @Override - public int getRequiredPermissionLevel() { - return 2; - } -} + private static boolean checkPermission(CommandSourceStack source, int level) { + try { + Method method = source.getClass().getMethod("hasPermission", int.class); + return (Boolean) method.invoke(source, level); + } catch (Exception e) { + try { + Method method = source.getClass().getMethod("getPermission"); + return (Integer) method.invoke(source) >= level; + } catch (Exception ex) { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandSavestate.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandSavestate.java index 0373883c..8879a0a5 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandSavestate.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandSavestate.java @@ -1,12 +1,5 @@ package com.minecrafttas.tasmod.commands; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.UnaryOperator; -import java.util.regex.Pattern; - import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.networking.TASmodBufferBuilder; import com.minecrafttas.tasmod.registries.TASmodPackets; @@ -17,732 +10,565 @@ import com.minecrafttas.tasmod.savestates.exceptions.LoadstateException; import com.minecrafttas.tasmod.savestates.exceptions.SavestateDeleteException; import com.minecrafttas.tasmod.savestates.exceptions.SavestateException; -import com.minecrafttas.tasmod.util.Component; -import com.minecrafttas.tasmod.util.Component.CClickEvent; -import com.minecrafttas.tasmod.util.Component.CHoverEvent; +import com.minecrafttas.tasmod.util.TASComponent; +import com.minecrafttas.tasmod.util.TASComponent.CClickEvent; +import com.minecrafttas.tasmod.util.TASComponent.CHoverEvent; import com.minecrafttas.tasmod.util.I18n; import com.minecrafttas.tasmod.util.LoggerMarkers; -import net.minecraft.client.Minecraft; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.command.WrongUsageException; -import net.minecraft.entity.player.EntityPlayerMP; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.ComponentContents; +import net.minecraft.ChatFormatting; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.Style; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextFormatting; -import net.minecraft.util.text.event.ClickEvent; -import net.minecraft.util.text.event.HoverEvent; - -public class CommandSavestate extends CommandBase { - - public static boolean once = true; - - @Override - public String getName() { - return "savestate"; - } - - @Override - public String getUsage(ICommandSender sender) { - return "/savestate save|load|delete|reload|rename|info"; - } - - @Override - public int getRequiredPermissionLevel() { - return 2; - } - - /** - *
-	 * savestate -> info
-	 * ├── index -> infoIndex
-	 * │   └── amount -> infoIndexAmount
-	 * ├── save -> saveNew
-	 * │   ├── index -> saveIndex
-	 * │   │   └── name -> saveNameIndex
-	 * │   └── name -> saveName
-	 * ├── load -> loadRecent
-	 * │   └── index -> loadIndex
-	 * ├── delete
-	 * │   └── index -> delete
-	 * │       └── indexTo -> deleteMore
-	 * │           └── force -> deleteDis
-	 * ├── reload -> reload
-	 * ├── rename
-	 * │   └── index
-	 * │       └── name -> rename
-	 * ├── info -> info
-	 * │   ├── index -> infoIndex
-	 * │   │   └── amount -> infoIndexAmount
-	 * │   └── all -> infoAll
-	 * └── import -> importing
-	 * 
- * @param server The MinecraftServer - * @param sender The command sender - * @param args The command arguments - */ - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - int length = args.length; - - if (length == 0) { - info(sender); - return; - } - - String first = args[0]; - - if (isNumeric(first)) { - int index = processIndex(first); - - if (length == 1) { - infoIndex(sender, index); - return; - } - - String second = args[1]; - int amount = parseInt(second); - infoIndexAmount(sender, index, amount); - return; - } - - else if ("save".equals(first)) { - - if (length == 1) { - saveNew(sender); - return; - } - - String second = args[1]; - if (isNumeric(second)) { - int index = processIndex(second); - - if (length == 2) { - saveIndex(sender, index); - return; - } - - String third = getRestArgsAsString(2, args); - saveIndexName(sender, index, third); - return; - - } else { - second = getRestArgsAsString(1, args); - saveName(sender, second); - return; - } - } - - else if ("load".equals(first)) { - - if (length == 1) { - loadRecent(sender); - return; - } - - String second = args[1]; - int index = processIndex(second); - loadIndex(sender, index); - return; - } - - else if ("delete".equals(first)) { - - if (length == 1) { - throw new WrongUsageException("/savestate delete [indexTo]"); - } - - String second = args[1]; - int indexFrom = processIndex(second); - if (length == 2) { - delete(sender, indexFrom); - return; - } - - String third = args[2]; - int indexTo = processIndex(third); - if (length == 3) { - deleteMore(sender, indexFrom, indexTo); - return; - } - - String fourth = args[3]; - if ("force".equals(fourth)) { - deleteDis(sender, indexFrom, indexTo); - return; - } - } - - else if ("reload".equals(first)) { - reload(sender); - return; - } - - else if ("rename".equals(first)) { - int index = processIndex(args[1]); - String name = getRestArgsAsString(2, args); - - rename(sender, index, name); - return; - } - - else if ("info".equals(first)) { - - if (length == 1) { - info(sender); - return; - } - - String second = args[1]; - if (isNumeric(second)) { - int index = processIndex(second); - - if (length == 2) { - infoIndex(sender, index); - return; - } - - String third = args[2]; - int amount = parseInt(third); - infoIndexAmount(sender, index, amount); - return; - } else if ("all".equals(second)) { - infoAll(sender); - return; - } - } - -// else if ("import".equals(first)) { -// importing(sender); -// } - - throw new WrongUsageException(getUsage(sender)); - } - - @Override - public List getTabCompletions(MinecraftServer minecraftServer, ICommandSender iCommandSender, String[] args, BlockPos blockPos) { - int length = args.length; - if (length == 1) { - return getListOfStringsMatchingLastWord(args, "save", "load", "delete", "reload", "rename", "info", "import"); - } - - String first = args[0]; - if ("save".equals(first)) { - if (length == 2) { - return getIndexes(args); - } - String second = args[1]; - if (isNumeric(second)) { - iCommandSender.sendMessage(new TextComponentString("Type the name of the savestate")); - return new ArrayList<>(); - } - - } - - else if ("load".equals(first)) { - if (length == 2) { - return getIndexes(args); - } - } - - else if ("delete".equals(first)) { - if (length <= 3) { - return getIndexes(args); - } - } - - else if ("rename".equals(first)) { - if (length == 2) { - return getIndexes(args); - } else if (length == 3) { - iCommandSender.sendMessage(new TextComponentString("Type the new name of the savestate")); - return new ArrayList<>(); - } - } - - else if ("info".equals(first)) { - if (length == 2) { - String second = args[1]; - if (isNumeric(second)) { - return getIndexes(args); - } else { - return getListOfStringsMatchingLastWord(args, "all"); - } - } - } - return new ArrayList<>(); - } - - private void info(ICommandSender sender) { - TASmod.LOGGER.trace(LoggerMarkers.Savestate, "Command Info"); - infoIndexAmount(sender, null, null); - } - - private void infoIndex(ICommandSender sender, Integer index) { - TASmod.LOGGER.trace(LoggerMarkers.Savestate, "Command InfoIndex {}", index); - infoIndexAmount(sender, index, null); - } - - @SuppressWarnings("unused") - private void infoIndexAmount(ICommandSender sender, Integer indexToDisplay, Integer amount) { - TASmod.LOGGER.trace(LoggerMarkers.Savestate, "Command InfoIndexAmount {}|{}", indexToDisplay, amount); - - int currentIndex = TASmod.savestateHandlerServer.getCurrentIndex(); - int size = TASmod.savestateHandlerServer.size(); - - if (size == 0) - sendHelp(sender); - - if (indexToDisplay == null) { - indexToDisplay = currentIndex; - } - if (amount == null) { - amount = 10; - } - - sender.sendMessage(Component.literal("").build()); // Print an empty line - - String format = "MM/dd/yyyy hh:mm:ss a"; // TODO Add server config - if (!sender.getServer().isDedicatedServer()) { - format = I18n.format("msg.tasmod.savestate.dateformat"); - } - SimpleDateFormat dateFormat = new SimpleDateFormat(format); - - List savestateList = TASmod.savestateHandlerServer.getSavestateInfo(indexToDisplay, amount); - - if (savestateList.size() < size && once) { - sender.sendMessage(Component.translatable("msg.tasmod.savestate.omitted", "/savestate info all").withStyle(TextFormatting.RED, TextFormatting.ITALIC).build()); - once = false; - } - - for (Savestate savestate : savestateList) { - - String index = savestate.getIndex() == null ? "" : Integer.toString(savestate.getIndex()); - boolean isCurrentIndex = savestate.getIndex() == currentIndex; - String name = savestate.getName() == null ? "" : savestate.getName(); - String date = savestate.getDate() == null ? "" : dateFormat.format(savestate.getDate()); - - TextFormatting indexColor = isCurrentIndex ? TextFormatting.AQUA : TextFormatting.BLUE; - TextFormatting nameColor = isCurrentIndex ? TextFormatting.WHITE : TextFormatting.GRAY; - TextFormatting dateColor = isCurrentIndex ? TextFormatting.AQUA : TextFormatting.DARK_AQUA; - TextFormatting saveColor = isCurrentIndex ? TextFormatting.LIGHT_PURPLE : TextFormatting.DARK_PURPLE; - TextFormatting deleteColor = isCurrentIndex ? TextFormatting.RED : TextFormatting.DARK_RED; - TextFormatting renameColor = isCurrentIndex ? TextFormatting.YELLOW : TextFormatting.GOLD; - TextFormatting loadColor = isCurrentIndex ? TextFormatting.GREEN : TextFormatting.DARK_GREEN; - - //@formatter:off - UnaryOperator