From 644471c6bfed2aa5d44db94576588e88f93c03ab Mon Sep 17 00:00:00 2001 From: ToadDev <748280+Toad-Dev@users.noreply.github.com> Date: Wed, 16 Jun 2021 00:03:04 -0700 Subject: [PATCH] Fix getItemDetail showing raw translation keys. The dedicated server always uses the default Language instance, as it's setter method is stripped from the server jar. So if we mixin to this instance's creation and load it with mods' en_us lang files, we will be able to "translate" text on the server. Translate in quotes as we're only loading en_us files, but mojang was the one who left out translations on the dedicated server we shouldn't feel too bad. --- config/checkstyle/suppressions.xml | 3 + .../fabric/mixin/MixinLanguage.java | 75 +++++++++++++++++++ src/main/resources/computercraft.mixins.json | 3 + 3 files changed, 81 insertions(+) create mode 100644 src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index 647da4baa..dc7ba5d07 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -7,6 +7,9 @@ + + + diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java new file mode 100644 index 000000000..fdd5eeeb3 --- /dev/null +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java @@ -0,0 +1,75 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.fabric.mixin; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonParseException; +import dan200.computercraft.shared.peripheral.generic.data.ItemData; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.util.Language; +import org.apache.logging.log4j.Logger; +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.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.function.BiConsumer; + +/** + * Loads all mods en_us lang file into the default Language instance on the dedicated server. + * Needed so that lua code running on the server can access the display name of items. + * + * @see ItemData#fill + */ +@Mixin( Language.class ) +public class MixinLanguage +{ + @Shadow + private static Logger LOGGER; + + @Shadow + public static void load( InputStream inputStream, BiConsumer entryConsumer ) + { + } + + private static void loadModLangFile( String modId, BiConsumer biConsumer ) + { + String path = "/assets/" + modId + "/lang/en_us.json"; + + try ( InputStream inputStream = Language.class.getResourceAsStream( path ) ) + { + if ( inputStream == null ) return; + load( inputStream, biConsumer ); + } + catch ( JsonParseException | IOException e ) + { + LOGGER.error( "Couldn't read strings from " + path, e ); + } + } + + @Inject( method = "create", locals = LocalCapture.CAPTURE_FAILSOFT, at = @At( value = "INVOKE", remap = false, target = "Lcom/google/common/collect/ImmutableMap$Builder;build()Lcom/google/common/collect/ImmutableMap;" ) ) + private static void create( CallbackInfoReturnable cir, ImmutableMap.Builder builder ) + { + /* We must ensure that the keys are de-duplicated because we can't catch the error that might otherwise + * occur when the injected function calls build() on the ImmutableMap builder. So we use our own hash map and + * exclude "minecraft", as the injected function has already loaded those keys at this point. + */ + HashMap translations = new HashMap<>(); + + FabricLoader.getInstance().getAllMods().stream().map( modContainer -> modContainer.getMetadata().getId() ) + .filter( id -> !id.equals( "minecraft" ) ).forEach( id -> { + loadModLangFile( id, translations::put ); + } ); + + builder.putAll( translations ); + } +} diff --git a/src/main/resources/computercraft.mixins.json b/src/main/resources/computercraft.mixins.json index 09a5bc326..cdc81c628 100644 --- a/src/main/resources/computercraft.mixins.json +++ b/src/main/resources/computercraft.mixins.json @@ -25,6 +25,9 @@ "MixinScreen", "MixinWorldRenderer" ], + "server": [ + "MixinLanguage" + ], "injectors": { "defaultRequire": 1 }