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 }