mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-11-05 09:36:19 +00:00
Use client-side commands for opening computer folders
Forge doesn't run client-side commands from sendUnsignedCommand, so we still require a mixin there. We do need to change the command name, as Fabric doesn't properly merge the two command trees.
This commit is contained in:
parent
f284328656
commit
27c72a4571
@ -39,7 +39,6 @@ dependencies {
|
||||
compileOnly(libs.bundles.externalMods.common)
|
||||
clientCompileOnly(variantOf(libs.emi) { classifier("api") })
|
||||
|
||||
compileOnly(libs.mixin)
|
||||
annotationProcessorEverywhere(libs.autoService)
|
||||
testFixturesAnnotationProcessor(libs.autoService)
|
||||
|
||||
@ -47,6 +46,7 @@ dependencies {
|
||||
testImplementation(libs.bundles.test)
|
||||
testRuntimeOnly(libs.bundles.testRuntime)
|
||||
|
||||
testModCompileOnly(libs.mixin)
|
||||
testModImplementation(testFixtures(project(":core")))
|
||||
testModImplementation(testFixtures(project(":common")))
|
||||
testModImplementation(libs.bundles.kotlin)
|
||||
|
@ -17,8 +17,6 @@ import dan200.computercraft.client.render.monitor.MonitorRenderState;
|
||||
import dan200.computercraft.client.sound.SpeakerManager;
|
||||
import dan200.computercraft.shared.CommonHooks;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant;
|
||||
@ -28,7 +26,6 @@ import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.util.PauseAwareTimer;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
@ -43,7 +40,6 @@ import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@ -71,10 +67,6 @@ public final class ClientHooks {
|
||||
ClientPocketComputers.reset();
|
||||
}
|
||||
|
||||
public static boolean onChatMessage(String message) {
|
||||
return handleOpenComputerCommand(message);
|
||||
}
|
||||
|
||||
public static boolean drawHighlight(PoseStack transform, MultiBufferSource bufferSource, Camera camera, BlockHitResult hit) {
|
||||
return CableHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit)
|
||||
|| MonitorHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit);
|
||||
@ -109,34 +101,6 @@ public final class ClientHooks {
|
||||
SpeakerManager.onPlayStreaming(engine, channel, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the {@link CommandComputerCraft#OPEN_COMPUTER} "clientside command". This isn't a true command, as we
|
||||
* don't want it to actually be visible to the user.
|
||||
*
|
||||
* @param message The current chat message.
|
||||
* @return Whether to cancel sending this message.
|
||||
*/
|
||||
private static boolean handleOpenComputerCommand(String message) {
|
||||
if (!message.startsWith(CommandComputerCraft.OPEN_COMPUTER)) return false;
|
||||
|
||||
var server = Minecraft.getInstance().getSingleplayerServer();
|
||||
if (server == null) return false;
|
||||
|
||||
var idStr = message.substring(CommandComputerCraft.OPEN_COMPUTER.length()).trim();
|
||||
int id;
|
||||
try {
|
||||
id = Integer.parseInt(idStr);
|
||||
} catch (NumberFormatException ignore) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var file = new File(ServerContext.get(server).storageDir().toFile(), "computer/" + id);
|
||||
if (!file.isDirectory()) return false;
|
||||
|
||||
Util.getPlatform().openFile(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional information about the currently targeted block to the debug screen.
|
||||
*
|
||||
|
@ -4,9 +4,13 @@
|
||||
|
||||
package dan200.computercraft.client;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
||||
import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller;
|
||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
||||
import dan200.computercraft.client.gui.*;
|
||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||
import dan200.computercraft.client.render.RenderTypes;
|
||||
@ -16,11 +20,14 @@ import dan200.computercraft.client.turtle.TurtleModemModeller;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import dan200.computercraft.core.util.Colour;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.common.IColouredItem;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
|
||||
import dan200.computercraft.shared.media.items.DiskItem;
|
||||
import dan200.computercraft.shared.media.items.TreasureDiskItem;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.item.ItemColor;
|
||||
import net.minecraft.client.gui.screens.MenuScreens;
|
||||
@ -30,6 +37,7 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||
import net.minecraft.client.renderer.item.ClampedItemPropertyFunction;
|
||||
import net.minecraft.client.renderer.item.ItemProperties;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.server.packs.resources.ResourceProvider;
|
||||
@ -39,6 +47,7 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
@ -181,4 +190,45 @@ public final class ClientRegistry {
|
||||
return function.unclampedCall(stack, level, entity, layer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register client-side commands.
|
||||
*
|
||||
* @param dispatcher The dispatcher to register the commands to.
|
||||
* @param sendError A function to send an error message.
|
||||
* @param <T> The type of the client-side command context.
|
||||
*/
|
||||
public static <T> void registerClientCommands(CommandDispatcher<T> dispatcher, BiConsumer<T, Component> sendError) {
|
||||
dispatcher.register(LiteralArgumentBuilder.<T>literal(CommandComputerCraft.CLIENT_OPEN_FOLDER)
|
||||
.requires(x -> Minecraft.getInstance().getSingleplayerServer() != null)
|
||||
.then(RequiredArgumentBuilder.<T, Integer>argument("computer_id", IntegerArgumentType.integer(0))
|
||||
.executes(c -> handleOpenComputerCommand(c.getSource(), sendError, c.getArgument("computer_id", Integer.class)))
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the {@link CommandComputerCraft#CLIENT_OPEN_FOLDER} command.
|
||||
*
|
||||
* @param context The command context.
|
||||
* @param sendError A function to send an error message.
|
||||
* @param id The computer's id.
|
||||
* @param <T> The type of the client-side command context.
|
||||
* @return {@code 1} if a folder was opened, {@code 0} otherwise.
|
||||
*/
|
||||
private static <T> int handleOpenComputerCommand(T context, BiConsumer<T, Component> sendError, int id) {
|
||||
var server = Minecraft.getInstance().getSingleplayerServer();
|
||||
if (server == null) {
|
||||
sendError.accept(context, Component.literal("Not on a single-player server"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
var file = new File(ServerContext.get(server).storageDir().toFile(), "computer/" + id);
|
||||
if (!file.isDirectory()) {
|
||||
sendError.accept(context, Component.literal("Computer's folder does not exist"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
Util.getPlatform().openFile(file);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "dan200.computercraft.mixin.client",
|
||||
"minVersion": "0.8",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"client": [
|
||||
"ClientPacketListenerMixin"
|
||||
],
|
||||
"refmap": "client-computercraft.refmap.json"
|
||||
}
|
@ -54,7 +54,12 @@ import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public final class CommandComputerCraft {
|
||||
public static final UUID SYSTEM_UUID = new UUID(0, 0);
|
||||
public static final String OPEN_COMPUTER = "computercraft open-computer ";
|
||||
|
||||
/**
|
||||
* The client-side command to open the folder. Ideally this would live under the main {@code computercraft}
|
||||
* namespace, but unfortunately that overrides commands, rather than merging them.
|
||||
*/
|
||||
public static final String CLIENT_OPEN_FOLDER = "computercraft-computer-folder";
|
||||
|
||||
private CommandComputerCraft() {
|
||||
}
|
||||
@ -389,7 +394,7 @@ public final class CommandComputerCraft {
|
||||
|
||||
return link(
|
||||
text("\u270E"),
|
||||
"/" + OPEN_COMPUTER + id,
|
||||
"/" + CLIENT_OPEN_FOLDER + " " + id,
|
||||
Component.translatable("commands.computercraft.dump.open_path")
|
||||
);
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
|
||||
import dan200.computercraft.shared.platform.FabricConfigFile;
|
||||
import dan200.computercraft.shared.platform.FabricMessageType;
|
||||
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
@ -81,6 +83,10 @@ public class ComputerCraftClient {
|
||||
return cable.getCloneItemStack(state, hit, level, pos, player);
|
||||
});
|
||||
|
||||
ClientCommandRegistrationCallback.EVENT.register(
|
||||
(dispatcher, registryAccess) -> ClientRegistry.registerClientCommands(dispatcher, FabricClientCommandSource::sendError)
|
||||
);
|
||||
|
||||
((FabricConfigFile) ConfigSpec.clientSpec).load(FabricLoader.getInstance().getConfigDir().resolve(ComputerCraftAPI.MOD_ID + "-client.toml"));
|
||||
}
|
||||
}
|
||||
|
@ -38,10 +38,6 @@
|
||||
},
|
||||
"mixins": [
|
||||
"computercraft.fabric.mixins.json",
|
||||
{
|
||||
"config": "computercraft-client.mixins.json",
|
||||
"environment": "client"
|
||||
},
|
||||
{
|
||||
"config": "computercraft-client.fabric.mixins.json",
|
||||
"environment": "client"
|
||||
|
@ -106,10 +106,8 @@ minecraft {
|
||||
}
|
||||
|
||||
mixin {
|
||||
add(sourceSets.main.get(), "computercraft.refmap.json")
|
||||
add(sourceSets.client.get(), "client-computercraft.refmap.json")
|
||||
|
||||
config("computercraft-client.mixins.json")
|
||||
config("computercraft-client.forge.mixins.json")
|
||||
}
|
||||
|
||||
|
@ -6,11 +6,9 @@ package dan200.computercraft.client;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.client.sound.SpeakerSound;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.CustomizeGuiOverlayEvent;
|
||||
import net.minecraftforge.client.event.RenderHandEvent;
|
||||
import net.minecraftforge.client.event.RenderHighlightEvent;
|
||||
import net.minecraftforge.client.event.RenderItemInFrameEvent;
|
||||
import net.minecraftforge.client.event.*;
|
||||
import net.minecraftforge.client.event.sound.PlayStreamingSourceEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.level.LevelEvent;
|
||||
@ -78,4 +76,9 @@ public final class ForgeClientHooks {
|
||||
if (!(event.getSound() instanceof SpeakerSound sound) || sound.getStream() == null) return;
|
||||
ClientHooks.onPlayStreaming(event.getEngine(), event.getChannel(), sound.getStream());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerClientCommands(RegisterClientCommandsEvent event) {
|
||||
ClientRegistry.registerClientCommands(event.getDispatcher(), CommandSourceStack::sendFailure);
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,23 @@
|
||||
|
||||
package dan200.computercraft.mixin.client;
|
||||
|
||||
import dan200.computercraft.client.ClientHooks;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraftforge.client.ClientCommandHandler;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
/**
|
||||
* Allows triggering ComputerCraft's client commands from chat components events.
|
||||
*/
|
||||
@Mixin(ClientPacketListener.class)
|
||||
class ClientPacketListenerMixin {
|
||||
@Inject(method = "sendUnsignedCommand", at = @At("HEAD"), cancellable = true)
|
||||
void commandUnsigned(String message, CallbackInfoReturnable<Boolean> ci) {
|
||||
if (ClientHooks.onChatMessage(message)) ci.setReturnValue(true);
|
||||
void commandUnsigned(String command, CallbackInfoReturnable<Boolean> ci) {
|
||||
if (command.startsWith(CommandComputerCraft.CLIENT_OPEN_FOLDER) && ClientCommandHandler.runCommand(command)) {
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,8 @@
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"client": [
|
||||
"BlockRenderDispatcherMixin"
|
||||
"BlockRenderDispatcherMixin",
|
||||
"ClientPacketListenerMixin"
|
||||
],
|
||||
"refmap": "client-computercraft.refmap.json"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user