feat: translate Message arguments in commands
This commit is contained in:
parent
42e6b1a03f
commit
32c34f2a6f
@ -1,5 +1,11 @@
|
|||||||
package io.gitlab.jfronny.googlechat.client;
|
package io.gitlab.jfronny.googlechat.client;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.context.CommandContextBuilder;
|
||||||
|
import com.mojang.brigadier.context.ParsedArgument;
|
||||||
|
import com.mojang.brigadier.context.ParsedCommandNode;
|
||||||
|
import com.mojang.brigadier.tree.ArgumentCommandNode;
|
||||||
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
|
import com.mojang.brigadier.tree.RootCommandNode;
|
||||||
import io.gitlab.jfronny.googlechat.GoogleChat;
|
import io.gitlab.jfronny.googlechat.GoogleChat;
|
||||||
import io.gitlab.jfronny.googlechat.GoogleChatConfig;
|
import io.gitlab.jfronny.googlechat.GoogleChatConfig;
|
||||||
import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder;
|
import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder;
|
||||||
@ -10,8 +16,12 @@ import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
|||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.client.option.KeyBinding;
|
import net.minecraft.client.option.KeyBinding;
|
||||||
import net.minecraft.client.util.InputUtil;
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.command.CommandSource;
|
||||||
|
import net.minecraft.command.argument.MessageArgumentType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class GoogleChatClient implements ClientModInitializer {
|
public class GoogleChatClient implements ClientModInitializer {
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
@ -38,4 +48,31 @@ public class GoogleChatClient implements ClientModInitializer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<String> reconstitute(String source, CommandContextBuilder<CommandSource> results) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (ParsedCommandNode<CommandSource> node : results.getNodes()) {
|
||||||
|
switch (node.getNode()) {
|
||||||
|
case ArgumentCommandNode<?, ?> arg -> {
|
||||||
|
ParsedArgument<CommandSource, ?> pa = results.getArguments().get(arg.getName());
|
||||||
|
String datum = pa.getRange().get(source);
|
||||||
|
if (pa.getResult() instanceof MessageArgumentType.MessageFormat fmt) builder.append(fmt.contents());
|
||||||
|
else builder.append(datum);
|
||||||
|
builder.append(' ');
|
||||||
|
}
|
||||||
|
case LiteralCommandNode<?> lit -> {
|
||||||
|
builder.append(lit.getLiteral());
|
||||||
|
builder.append(' ');
|
||||||
|
}
|
||||||
|
case RootCommandNode<?> root -> {}
|
||||||
|
default -> {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GoogleChatConfig.Advanced.debugLogs) {
|
||||||
|
GoogleChat.LOGGER.info("Reconstituted command: {0} from {1}", builder.substring(0, builder.length() - 1), source);
|
||||||
|
}
|
||||||
|
return Optional.of(builder.substring(0, builder.length() - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package io.gitlab.jfronny.googlechat.client.mixin;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.ParseResults;
|
||||||
|
import com.mojang.brigadier.context.ParsedArgument;
|
||||||
|
import io.gitlab.jfronny.googlechat.GoogleChat;
|
||||||
|
import io.gitlab.jfronny.googlechat.GoogleChatConfig;
|
||||||
|
import io.gitlab.jfronny.googlechat.TranslationDirection;
|
||||||
|
import io.gitlab.jfronny.googlechat.client.GoogleChatClient;
|
||||||
|
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||||
|
import net.minecraft.command.CommandSource;
|
||||||
|
import net.minecraft.command.argument.MessageArgumentType;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
@Mixin(ClientPlayNetworkHandler.class)
|
||||||
|
public class ClientPlayNetworkHandlerMixin {
|
||||||
|
@Shadow private ParseResults<CommandSource> parse(String command) {
|
||||||
|
throw new IllegalStateException("Mixin failed to apply");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique private final AtomicReference<ParseResults<CommandSource>> googlechat$lastResults = new AtomicReference<>(null);
|
||||||
|
|
||||||
|
@ModifyVariable(method = "sendChatCommand(Ljava/lang/String;)V", at = @At("HEAD"), ordinal = 0, argsOnly = true)
|
||||||
|
public String translateCommand(String command) {
|
||||||
|
ParseResults<CommandSource> results = parse(command);
|
||||||
|
if (!GoogleChatConfig.General.enabled || !GoogleChatConfig.Advanced.translateMessageArguments || !results.getExceptions().isEmpty()) return command;
|
||||||
|
final boolean[] modified = {false};
|
||||||
|
results.getContext().getArguments().replaceAll((key, value) -> {
|
||||||
|
if (value.getResult() instanceof MessageArgumentType.MessageFormat fmt) {
|
||||||
|
if (fmt.selectors().length != 0) return value; // Selectors contain position information, which this would break
|
||||||
|
fmt = new MessageArgumentType.MessageFormat(GoogleChat.translateIfNeeded(fmt.contents(), TranslationDirection.C2S, true), new MessageArgumentType.MessageSelector[0]);
|
||||||
|
modified[0] = true;
|
||||||
|
return new ParsedArgument<>(value.getRange().getStart(), value.getRange().getEnd(), fmt);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
if (!modified[0]) return command;
|
||||||
|
return GoogleChatClient.reconstitute(command, results.getContext()).map(s -> {
|
||||||
|
googlechat$lastResults.set(results);
|
||||||
|
return s;
|
||||||
|
}).orElse(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "sendChatCommand(Ljava/lang/String;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;parse(Ljava/lang/String;)Lcom/mojang/brigadier/ParseResults;"))
|
||||||
|
public ParseResults<CommandSource> googlechat$modifyArguments(ClientPlayNetworkHandler handler, String command) {
|
||||||
|
ParseResults<CommandSource> results = googlechat$lastResults.getAndSet(null);
|
||||||
|
if (results != null) return results;
|
||||||
|
return parse(command);
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
"client": [
|
"client": [
|
||||||
"ChatScreenMixin",
|
"ChatScreenMixin",
|
||||||
"ClientPlayerEntityMixin",
|
"ClientPlayerEntityMixin",
|
||||||
|
"ClientPlayNetworkHandlerMixin",
|
||||||
"MessageHandlerMixin"
|
"MessageHandlerMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
|
@ -52,6 +52,7 @@ public class GoogleChatConfig {
|
|||||||
public static class Advanced {
|
public static class Advanced {
|
||||||
@Entry(min = 1, max = 1024) public static int cacheSize = 256;
|
@Entry(min = 1, max = 1024) public static int cacheSize = 256;
|
||||||
@Entry public static boolean async = true;
|
@Entry public static boolean async = true;
|
||||||
|
@Entry public static boolean translateMessageArguments = true;
|
||||||
@Entry public static boolean debugLogs = FabricLoader.getInstance().isDevelopmentEnvironment();
|
@Entry public static boolean debugLogs = FabricLoader.getInstance().isDevelopmentEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package io.gitlab.jfronny.googlechat.server.mixin;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import io.gitlab.jfronny.googlechat.GoogleChatConfig;
|
||||||
|
import io.gitlab.jfronny.googlechat.TranslationDirection;
|
||||||
|
import io.gitlab.jfronny.googlechat.server.TranslatableContainer;
|
||||||
|
import net.minecraft.command.argument.MessageArgumentType;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Mixin(MessageArgumentType.class)
|
||||||
|
public class MessageArgumentTypeMixin {
|
||||||
|
@Inject(method = "getMessage(Lcom/mojang/brigadier/context/CommandContext;Ljava/lang/String;)Lnet/minecraft/text/Text;", at = @At("TAIL"), cancellable = true)
|
||||||
|
private static void modifyMessage(CommandContext<ServerCommandSource> context, String name, CallbackInfoReturnable<Text> cir) {
|
||||||
|
if (!GoogleChatConfig.General.enabled || !GoogleChatConfig.Advanced.translateMessageArguments) return;
|
||||||
|
Text message = cir.getReturnValue();
|
||||||
|
if (context.getSource().getPlayer() != null) { // Client messages should first be translated to the server language
|
||||||
|
if (TranslationDirection.C2S.hasTarget()) {
|
||||||
|
if (TranslationDirection.S2C.hasTarget()) {
|
||||||
|
// Do not translate back and forth
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message = TranslatableContainer.translateAndLog(message, TranslationDirection.C2S);
|
||||||
|
}
|
||||||
|
// All messages should be translated to the client language before sending
|
||||||
|
message = TranslatableContainer.translateAndLog(message, TranslationDirection.S2C);
|
||||||
|
cir.setReturnValue(message);
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,8 @@
|
|||||||
"google-chat.jfconfig.advanced.cacheSize.tooltips": "The size of each message cache. Since there are six caches, the actual size will be six times this.",
|
"google-chat.jfconfig.advanced.cacheSize.tooltips": "The size of each message cache. Since there are six caches, the actual size will be six times this.",
|
||||||
"google-chat.jfconfig.advanced.async": "Async",
|
"google-chat.jfconfig.advanced.async": "Async",
|
||||||
"google-chat.jfconfig.advanced.async.tooltips": "Whether to asynchronously process messages. Should prevent some stutters, but might cause other issues. Disable if you no longer receive messages",
|
"google-chat.jfconfig.advanced.async.tooltips": "Whether to asynchronously process messages. Should prevent some stutters, but might cause other issues. Disable if you no longer receive messages",
|
||||||
|
"google-chat.jfconfig.advanced.translateMessageArguments": "Translate MessageArguments",
|
||||||
|
"google-chat.jfconfig.advanced.translateMessageArguments.tooltips": "Whether to translate arguments of commands designated as being messages",
|
||||||
"google-chat.jfconfig.advanced.debugLogs": "Debug Logs",
|
"google-chat.jfconfig.advanced.debugLogs": "Debug Logs",
|
||||||
"google-chat.jfconfig.advanced.debugLogs.tooltips": "Log additional information about message processing. Useful for debugging",
|
"google-chat.jfconfig.advanced.debugLogs.tooltips": "Log additional information about message processing. Useful for debugging",
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"client": ["io.gitlab.jfronny.googlechat.client.GoogleChatClient"]
|
"client": ["io.gitlab.jfronny.googlechat.client.GoogleChatClient"]
|
||||||
},
|
},
|
||||||
"mixins": [
|
"mixins": [
|
||||||
|
"google-chat.mixins.json",
|
||||||
{
|
{
|
||||||
"config": "google-chat.client.mixins.json",
|
"config": "google-chat.client.mixins.json",
|
||||||
"environment": "client"
|
"environment": "client"
|
||||||
|
12
src/main/resources/google-chat.mixins.json
Normal file
12
src/main/resources/google-chat.mixins.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"minVersion": "0.8",
|
||||||
|
"package": "io.gitlab.jfronny.googlechat.server.mixin",
|
||||||
|
"compatibilityLevel": "JAVA_17",
|
||||||
|
"mixins": [
|
||||||
|
"MessageArgumentTypeMixin"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user