Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
725fb15031 | |||
db307c7223 | |||
c54b646488 | |||
7c44209d07 | |||
3c31d78ab8 | |||
e1be8aeed9 | |||
e1d19df4c1 | |||
49bdf4b921 | |||
88d44b6737 | |||
e04cfaaf93 |
@ -1,16 +1,16 @@
|
||||
plugins {
|
||||
id("jfmod") version "1.5-SNAPSHOT"
|
||||
id("jfmod") version "1.6-SNAPSHOT"
|
||||
}
|
||||
|
||||
allprojects { group = "io.gitlab.jfronny" }
|
||||
base.archivesName = "google-chat"
|
||||
|
||||
val fabricVersion = "0.83.0+1.20"
|
||||
jfMod {
|
||||
minecraftVersion = "1.20.1"
|
||||
yarn("build.9")
|
||||
loaderVersion = "0.14.21"
|
||||
libJfVersion = "3.10.2"
|
||||
minecraftVersion = "1.21"
|
||||
yarn("build.1")
|
||||
loaderVersion = "0.15.11"
|
||||
libJfVersion = "3.16.0"
|
||||
fabricApiVersion = "0.100.1+1.21"
|
||||
|
||||
modrinth {
|
||||
projectId = "google-chat"
|
||||
@ -25,12 +25,19 @@ jfMod {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v1:${jfMod.libJfVersion.get()}")
|
||||
modImplementation("io.gitlab.jfronny.libjf:libjf-translate-v1:${jfMod.libJfVersion.get()}")
|
||||
include(modImplementation(fabricApi.module("fabric-message-api-v1", fabricVersion))!!)
|
||||
modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v2")
|
||||
modImplementation("io.gitlab.jfronny.libjf:libjf-translate-v1")
|
||||
include(modImplementation("net.fabricmc.fabric-api:fabric-message-api-v1")!!)
|
||||
// Keybind
|
||||
modCompileOnly("net.fabricmc.fabric-api:fabric-key-binding-api-v1")
|
||||
modCompileOnly("net.fabricmc.fabric-api:fabric-lifecycle-events-v1")
|
||||
|
||||
// Dev env
|
||||
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-config-ui-tiny-v1:${jfMod.libJfVersion.get()}")
|
||||
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil:${jfMod.libJfVersion.get()}")
|
||||
modLocalRuntime("com.terraformersmc:modmenu:7.1.0")
|
||||
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-config-ui-tiny")
|
||||
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil")
|
||||
modLocalRuntime("net.fabricmc.fabric-api:fabric-resource-loader-v0")
|
||||
modLocalRuntime("com.terraformersmc:modmenu:11.0.0-beta.1")
|
||||
// for modmenu
|
||||
modLocalRuntime("net.fabricmc.fabric-api:fabric-screen-api-v1")
|
||||
modLocalRuntime("net.fabricmc.fabric-api:fabric-key-binding-api-v1")
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
package io.gitlab.jfronny.googlechat.client;
|
||||
|
||||
import io.gitlab.jfronny.googlechat.GoogleChat;
|
||||
import io.gitlab.jfronny.googlechat.GoogleChatConfig;
|
||||
import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder;
|
||||
import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class GoogleChatClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ConfigInstance ci = ConfigHolder.getInstance().get(GoogleChat.MOD_ID);
|
||||
if (ci != null
|
||||
&& FabricLoader.getInstance().isModLoaded("fabric-key-binding-api-v1")
|
||||
&& FabricLoader.getInstance().isModLoaded("fabric-lifecycle-events-v1")) {
|
||||
setupKeybind(ci);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setupKeybind(@NotNull ConfigInstance ci) {
|
||||
// Factored out to prevent loading classes if mods are not present
|
||||
KeyBinding keyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
"key." + GoogleChat.MOD_ID + ".toggle",
|
||||
InputUtil.Type.KEYSYM,
|
||||
-1,
|
||||
KeyBinding.MULTIPLAYER_CATEGORY
|
||||
));
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
if (keyBinding.wasPressed()) {
|
||||
GoogleChatConfig.General.enabled = !GoogleChatConfig.General.enabled;
|
||||
ci.write();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
@Mixin(ChatScreen.class)
|
||||
public class ChatScreenMixin {
|
||||
@ModifyVariable(method = "sendMessage(Ljava/lang/String;Z)Z", at = @At(value = "HEAD"), argsOnly = true, ordinal = 0)
|
||||
@ModifyVariable(method = "sendMessage(Ljava/lang/String;Z)V", at = @At(value = "HEAD"), argsOnly = true, ordinal = 0)
|
||||
String googlechat$translateChatText(String chatText) {
|
||||
if (chatText.startsWith("/")) return chatText; // Bypass for client-side commands (Carpet, ...)
|
||||
return GoogleChat.translateIfNeeded(chatText, TranslationDirection.C2S, true);
|
||||
|
@ -21,6 +21,8 @@ public abstract class MessageHandlerMixin {
|
||||
@Shadow @Final private MinecraftClient client;
|
||||
@Shadow protected abstract void narrate(MessageType.Parameters params, Text message);
|
||||
|
||||
//TODO somehow modify applyChatDecoration, since that is the only method that knows the real text
|
||||
|
||||
@Unique CompletableFuture<Void> googlechat$currentFuture = CompletableFuture.completedFuture(null);
|
||||
@Unique ThreadLocal<GameProfile> sender = new ThreadLocal<>();
|
||||
|
||||
@ -78,10 +80,12 @@ public abstract class MessageHandlerMixin {
|
||||
this.sender.remove();
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Text googlechat$s2c(Text message) {
|
||||
return GoogleChat.translateIfNeeded(message, TranslationDirection.S2C, true);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void googlechat$schedule(Runnable runnable) {
|
||||
if (!GoogleChatConfig.Advanced.async) runnable.run();
|
||||
else googlechat$currentFuture.whenCompleteAsync((_1, _2) -> runnable.run()).exceptionally(throwable -> {
|
||||
@ -90,6 +94,7 @@ public abstract class MessageHandlerMixin {
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean googlechat$shouldTranslate() {
|
||||
if (!GoogleChatConfig.General.enabled) return false;
|
||||
if (client == null || client.player == null) return false;
|
||||
|
@ -1,20 +1,27 @@
|
||||
package io.gitlab.jfronny.googlechat;
|
||||
|
||||
import io.gitlab.jfronny.commons.cache.FixedSizeMap;
|
||||
import io.gitlab.jfronny.commons.log.Logger;
|
||||
import io.gitlab.jfronny.commons.io.cache.FixedSizeMap;
|
||||
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
|
||||
import io.gitlab.jfronny.commons.throwable.Coerce;
|
||||
import io.gitlab.jfronny.commons.throwable.Try;
|
||||
import io.gitlab.jfronny.libjf.translate.api.Language;
|
||||
import io.gitlab.jfronny.libjf.translate.api.TranslateService;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.text.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class GoogleChat implements ModInitializer {
|
||||
public static final String MOD_ID = "google-chat";
|
||||
public static final Logger LOGGER = Logger.forName(MOD_ID);
|
||||
public static final SystemLoggerPlus LOGGER = SystemLoggerPlus.forName(MOD_ID);
|
||||
public static TranslateService<?> TRANSLATE_SERVICE;
|
||||
private static final boolean IS_SERVER = FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER;
|
||||
|
||||
private static final Map<Text, Text> s2ct = new FixedSizeMap<>(GoogleChatConfig.Advanced.cacheSize);
|
||||
private static final Map<Text, Text> c2st = new FixedSizeMap<>(GoogleChatConfig.Advanced.cacheSize);
|
||||
@ -25,7 +32,7 @@ public class GoogleChat implements ModInitializer {
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
ForkJoinPool.commonPool().execute(() -> TRANSLATE_SERVICE = TranslateService.getConfigured());
|
||||
ForkJoinPool.commonPool().execute(Try.handle(Coerce.runnable(() -> TRANSLATE_SERVICE = TranslateService.getConfigured()), e -> LOGGER.error("Could not initialize translation service", e)));
|
||||
}
|
||||
|
||||
public static void onConfigChange() {
|
||||
@ -86,7 +93,7 @@ public class GoogleChat implements ModInitializer {
|
||||
}
|
||||
|
||||
public static TextContent translateIfNeeded(TextContent source, TranslationDirection direction, boolean respectRegex) {
|
||||
if (source == null) return null;
|
||||
if (source == null || source == PlainTextContent.EMPTY) return source;
|
||||
if (direction.shouldSkipOutright()) return source;
|
||||
String sourceString = toString(source);
|
||||
if (respectRegex && direction.failsRegex(sourceString)) return source;
|
||||
@ -103,8 +110,8 @@ public class GoogleChat implements ModInitializer {
|
||||
else args[i] = args[i];
|
||||
}
|
||||
return new TranslatableTextContent(tx.getKey(), translateIfNeeded(tx.getFallback(), direction, false), args);
|
||||
} else if (t instanceof LiteralTextContent tx) {
|
||||
return new LiteralTextContent(translateIfNeeded(tx.string(), direction, false));
|
||||
} else if (t instanceof PlainTextContent.Literal tx) {
|
||||
return new PlainTextContent.Literal(translateIfNeeded(tx.string(), direction, false));
|
||||
} else {
|
||||
// LOGGER.info("Unhandled text type: " + source.getClass() + " (" + source + ")");
|
||||
return t;
|
||||
@ -125,19 +132,22 @@ public class GoogleChat implements ModInitializer {
|
||||
return style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverText));
|
||||
}
|
||||
|
||||
private static final Pattern SURROUNDING_SPACE_PATTERN = Pattern.compile("^(\\s*)(.*\\S+)(\\s*)$", Pattern.MULTILINE);
|
||||
public static String translateIfNeeded(String source, TranslationDirection direction, boolean respectRegex) {
|
||||
if (source == null) return null;
|
||||
if (direction.shouldSkipOutright()) return source;
|
||||
if (respectRegex && direction.failsRegex(source)) return source;
|
||||
return computeIfAbsent2(direction == TranslationDirection.C2S ? c2ss : s2cs, source, t -> {
|
||||
try {
|
||||
Matcher m = SURROUNDING_SPACE_PATTERN.matcher(source);
|
||||
if (!m.find()) return source;
|
||||
// Ignore generics since this is apparently not something java supports
|
||||
@SuppressWarnings("rawtypes") TranslateService svc = GoogleChat.TRANSLATE_SERVICE;
|
||||
if (svc == null) throw new NullPointerException("Translate service uninitialized");
|
||||
Language sourceLang = svc.parseLang(direction.source());
|
||||
Language targetLang = svc.parseLang(direction.target());
|
||||
//noinspection unchecked
|
||||
return svc.translate(source, sourceLang, targetLang);
|
||||
return m.group(1) + svc.translate(m.group(2), sourceLang, targetLang) + m.group(3);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Could not translate text: " + source, e);
|
||||
return source;
|
||||
@ -146,7 +156,7 @@ public class GoogleChat implements ModInitializer {
|
||||
}
|
||||
|
||||
private static <K, V> V computeIfAbsent2(Map<K, V> map, K key, Function<K, V> compute) {
|
||||
if (!GoogleChatConfig.Advanced.async) return map.computeIfAbsent(key, compute);
|
||||
if (!GoogleChatConfig.Advanced.async && !IS_SERVER) return map.computeIfAbsent(key, compute);
|
||||
synchronized (map) {
|
||||
if (map.containsKey(key)) return map.get(key);
|
||||
V value = compute.apply(key);
|
||||
|
@ -1,11 +1,16 @@
|
||||
package io.gitlab.jfronny.googlechat;
|
||||
|
||||
import io.gitlab.jfronny.commons.serialize.gson.api.v1.Ignore;
|
||||
import io.gitlab.jfronny.libjf.config.api.v1.*;
|
||||
import io.gitlab.jfronny.libjf.config.api.v1.dsl.ConfigBuilder;
|
||||
import io.gitlab.jfronny.commons.serialize.SerializeReader;
|
||||
import io.gitlab.jfronny.commons.serialize.annotations.Ignore;
|
||||
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
|
||||
import io.gitlab.jfronny.libjf.config.api.v2.*;
|
||||
import io.gitlab.jfronny.libjf.config.api.v2.dsl.ConfigBuilder;
|
||||
import io.gitlab.jfronny.libjf.config.api.v2.dsl.Migration;
|
||||
import net.fabricmc.api.*;
|
||||
import net.fabricmc.loader.api.*;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@JfConfig(tweaker = GoogleChatConfig.class)
|
||||
public class GoogleChatConfig {
|
||||
@Category(referencedConfigs = "libjf-translate-v1")
|
||||
@ -64,17 +69,28 @@ public class GoogleChatConfig {
|
||||
|
||||
public static ConfigBuilder<?> tweak(ConfigBuilder<?> builder) {
|
||||
return builder
|
||||
.addMigration("enabled", reader -> General.enabled = reader.nextBoolean())
|
||||
.addMigration("serverLanguage", reader -> General.serverLanguage = reader.nextString())
|
||||
.addMigration("clientLanguage", reader -> General.clientLanguage = reader.nextString())
|
||||
.addMigration("translationTooltip", reader -> General.translationTooltip = reader.nextBoolean())
|
||||
.addMigration("desugar", reader -> Processing.desugar = reader.nextBoolean())
|
||||
.addMigration("receivingRegex", reader -> Processing.receivingRegex = reader.nextString())
|
||||
.addMigration("receivingRegexIsBlacklist", reader -> Processing.receivingRegexIsBlacklist = reader.nextBoolean())
|
||||
.addMigration("sendingRegex", reader -> Processing.sendingRegex = reader.nextString())
|
||||
.addMigration("sendingRegexIsBlacklist", reader -> Processing.sendingRegexIsBlacklist = reader.nextBoolean())
|
||||
.addMigration("cacheSize", reader -> Advanced.cacheSize = reader.nextInt())
|
||||
.addMigration("debugLogs", reader -> Advanced.debugLogs = reader.nextBoolean());
|
||||
.addMigration("enabled", of(reader -> General.enabled = reader.nextBoolean()))
|
||||
.addMigration("serverLanguage", of(reader -> General.serverLanguage = reader.nextString()))
|
||||
.addMigration("clientLanguage", of(reader -> General.clientLanguage = reader.nextString()))
|
||||
.addMigration("translationTooltip", of(reader -> General.translationTooltip = reader.nextBoolean()))
|
||||
.addMigration("desugar", of(reader -> Processing.desugar = reader.nextBoolean()))
|
||||
.addMigration("receivingRegex", of(reader -> Processing.receivingRegex = reader.nextString()))
|
||||
.addMigration("receivingRegexIsBlacklist", of(reader -> Processing.receivingRegexIsBlacklist = reader.nextBoolean()))
|
||||
.addMigration("sendingRegex", of(reader -> Processing.sendingRegex = reader.nextString()))
|
||||
.addMigration("sendingRegexIsBlacklist", of(reader -> Processing.sendingRegexIsBlacklist = reader.nextBoolean()))
|
||||
.addMigration("cacheSize", of(reader -> Advanced.cacheSize = reader.nextInt()))
|
||||
.addMigration("debugLogs", of(reader -> Advanced.debugLogs = reader.nextBoolean()));
|
||||
}
|
||||
|
||||
private static Migration of(ThrowingConsumer<SerializeReader<?, ?>, Exception> dm) {
|
||||
//TODO use the libjf-native method
|
||||
Consumer<SerializeReader<?, ?>> cn = ((ThrowingConsumer<SerializeReader<?, ?>, RuntimeException>) (ThrowingConsumer) dm)::accept;
|
||||
return new Migration() {
|
||||
@Override
|
||||
public <TEx extends Exception, Reader extends SerializeReader<TEx, Reader>> void apply(Reader reader) throws TEx {
|
||||
cn.accept(reader);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static {
|
||||
|
@ -4,41 +4,56 @@ import io.gitlab.jfronny.googlechat.*;
|
||||
import net.fabricmc.api.DedicatedServerModInitializer;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.message.v1.ServerMessageDecoratorEvent;
|
||||
import net.minecraft.network.message.MessageDecorator;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static io.gitlab.jfronny.libjf.LibJf.LOGGER;
|
||||
|
||||
public class GoogleChatServer implements DedicatedServerModInitializer {
|
||||
public class GoogleChatServer implements DedicatedServerModInitializer, MessageDecorator {
|
||||
@Override
|
||||
public void onInitializeServer() {
|
||||
// Default phase is executed between CONTENT and STYLING
|
||||
// Perform translation there instead of during CONTENT to better support other mods (such as chat-transform)
|
||||
// If this causes an incompatibility, I'll add my own phase
|
||||
ServerMessageDecoratorEvent.EVENT.register(Event.DEFAULT_PHASE, (sender, originalMessage) -> {
|
||||
CompletableFuture<Text> futureMessage = CompletableFuture.completedFuture(originalMessage);
|
||||
if (!GoogleChatConfig.General.enabled) return futureMessage; // fast fallthrough
|
||||
ServerMessageDecoratorEvent.EVENT.register(Event.DEFAULT_PHASE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text decorate(@Nullable ServerPlayerEntity sender, Text original) {
|
||||
if (!GoogleChatConfig.General.enabled) return original;
|
||||
if (!GoogleChatConfig.Advanced.async) {
|
||||
return decorate(sender, new TranslatableContainer.Sync(original)).text();
|
||||
}
|
||||
try {
|
||||
return decorate(sender, new TranslatableContainer.Async(CompletableFuture.completedFuture(original)))
|
||||
.text()
|
||||
.exceptionally(e -> {
|
||||
GoogleChat.LOGGER.error("Could not compute translation", e);
|
||||
return original;
|
||||
})
|
||||
.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
GoogleChat.LOGGER.error("Could not synchronize async translation for synchronous decorator", e);
|
||||
return original;
|
||||
}
|
||||
}
|
||||
|
||||
private <K, T extends TranslatableContainer<K, T>> T decorate(@Nullable ServerPlayerEntity sender, T original) {
|
||||
T message = original;
|
||||
if (sender != 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 futureMessage;
|
||||
return message;
|
||||
}
|
||||
}
|
||||
futureMessage = futureMessage.thenApplyAsync(msg -> {
|
||||
var translated = GoogleChat.translateIfNeeded(msg, TranslationDirection.C2S, true);
|
||||
if (GoogleChatConfig.Advanced.debugLogs) LOGGER.info("Applied C2S translation from " + msg + " to " + translated);
|
||||
return translated;
|
||||
});
|
||||
message = message.translate(TranslationDirection.C2S);
|
||||
}
|
||||
// All messages should be translated to the client language before sending
|
||||
futureMessage = futureMessage.thenApplyAsync(msg -> {
|
||||
var translated = GoogleChat.translateIfNeeded(msg, TranslationDirection.S2C, true);
|
||||
if (GoogleChatConfig.Advanced.debugLogs) LOGGER.info("Applied S2C translation from " + msg + " to " + translated);
|
||||
return translated;
|
||||
});
|
||||
return futureMessage;
|
||||
});
|
||||
message = message.translate(TranslationDirection.S2C);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
package io.gitlab.jfronny.googlechat.server;
|
||||
|
||||
import io.gitlab.jfronny.googlechat.*;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static io.gitlab.jfronny.libjf.LibJf.LOGGER;
|
||||
|
||||
public sealed interface TranslatableContainer<T, S extends TranslatableContainer<T, S>> {
|
||||
S translate(TranslationDirection direction);
|
||||
|
||||
record Sync(Text text) implements TranslatableContainer<Text, Sync> {
|
||||
@Override
|
||||
public Sync translate(TranslationDirection direction) {
|
||||
return new Sync(translateAndLog(text, direction));
|
||||
}
|
||||
}
|
||||
|
||||
record Async(CompletableFuture<Text> text) implements TranslatableContainer<CompletableFuture<Text>, Async> {
|
||||
@Override
|
||||
public Async translate(TranslationDirection direction) {
|
||||
return new Async(text.thenApplyAsync(msg -> translateAndLog(msg, direction)));
|
||||
}
|
||||
}
|
||||
|
||||
static Text translateAndLog(final Text source, final TranslationDirection direction) {
|
||||
var translated = GoogleChat.translateIfNeeded(source, direction, true);
|
||||
if (GoogleChatConfig.Advanced.debugLogs) LOGGER.info("Applied C2S translation from {0} to {1}", source, translated);
|
||||
return translated;
|
||||
}
|
||||
}
|
@ -29,5 +29,7 @@
|
||||
"google-chat.jfconfig.advanced.debugLogs.tooltips": "Log additional information about message processing. Useful for debugging",
|
||||
|
||||
"google-chat.jfconfig.client": "Client",
|
||||
"google-chat.jfconfig.server": "Server"
|
||||
"google-chat.jfconfig.server": "Server",
|
||||
|
||||
"key.google-chat.toggle": "Toggle GoogleChat"
|
||||
}
|
@ -17,7 +17,8 @@
|
||||
"entrypoints": {
|
||||
"libjf:config": ["io.gitlab.jfronny.googlechat.JFC_GoogleChatConfig"],
|
||||
"server": ["io.gitlab.jfronny.googlechat.server.GoogleChatServer"],
|
||||
"main": ["io.gitlab.jfronny.googlechat.GoogleChat"]
|
||||
"main": ["io.gitlab.jfronny.googlechat.GoogleChat"],
|
||||
"client": ["io.gitlab.jfronny.googlechat.client.GoogleChatClient"]
|
||||
},
|
||||
"mixins": [
|
||||
{
|
||||
@ -28,7 +29,7 @@
|
||||
"depends": {
|
||||
"fabricloader": ">=0.12.12",
|
||||
"minecraft": "*",
|
||||
"libjf-config-core-v1": "*",
|
||||
"libjf-config-core-v2": "*",
|
||||
"libjf-translate-v1": "*",
|
||||
"fabric-message-api-v1": "*"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user