diff --git a/common/src/shaders/java/net/coderbot/iris/mixin/MixinClientLanguage.java b/common/src/shaders/java/net/coderbot/iris/mixin/MixinClientLanguage.java new file mode 100644 index 00000000..14268345 --- /dev/null +++ b/common/src/shaders/java/net/coderbot/iris/mixin/MixinClientLanguage.java @@ -0,0 +1,90 @@ +package net.coderbot.iris.mixin; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.LanguageMap; +import net.coderbot.iris.shaderpack.ShaderPack; +import net.minecraft.client.resource.language.TranslationStorage; +import net.minecraft.resource.ResourceManager; +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.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Allows shader packs to provide extra usable language entries outside of resource packs. + * + *

We "sideload" the language entries with an override system to avoid having to reload the + * resource manager on shader pack changes, since reloading the resource manager is very slow.

+ * + * Uses a lower priority to inject before Incubus-Core to prevent translations from breaking + * @see Incubus-Core translation mixin + */ +@Mixin(value = TranslationStorage.class, priority = 990) +public class MixinClientLanguage { + // storage + @Shadow Map translations; + + @Unique + private static final List languageCodes = new ArrayList<>(); + + @Inject(method = "translate", at = @At("HEAD"), cancellable = true) + private void iris$overrideLanguageEntries(String key, CallbackInfoReturnable cir) { + final String override = iris$lookupOverriddenEntry(key); + + if (override != null) { + cir.setReturnValue(override); + } + } + + @Unique + private String iris$lookupOverriddenEntry(String key) { + final ShaderPack pack = Iris.getCurrentPack().orElse(null); + + if (pack == null) { + // If no shaderpack is loaded, do not try to process language overrides. + // + // This prevents a cryptic NullPointerException when shaderpack loading fails for some reason. + return null; + } + + // Minecraft loads the "en_US" language code by default, and any other code will be right after it. + // + // So we also check if the user is loading a special language, and if the shaderpack has support for that + // language. If they do, we load that, but if they do not, we load "en_US" instead. + final LanguageMap languageMap = pack.getLanguageMap(); + + if (translations.containsKey(key)) { + return null; + } + + for (String code : languageCodes) { + final Map translations = languageMap.getTranslations(code); + + if (translations != null) { + final String translation = translations.get(key); + + if (translation != null) { + return translation; + } + } + } + + return null; + } + + @Inject(method = "load(Lnet/minecraft/resource/ResourceManager;Ljava/util/List;)V", at = @At("HEAD")) + private void iris$addLanguageCodes(ResourceManager resourceManager, List definitions, CallbackInfo ci) { + languageCodes.clear(); + + // Reverse order due to how minecraft has English and then the primary language in the language definitions list + new LinkedList<>(definitions).descendingIterator().forEachRemaining(languageCodes::add); + } +} diff --git a/common/src/shaders/java/net/coderbot/iris/mixin/MixinMinecraft_Keybinds.java b/common/src/shaders/java/net/coderbot/iris/mixin/MixinMinecraft_Keybinds.java new file mode 100644 index 00000000..7b4111c2 --- /dev/null +++ b/common/src/shaders/java/net/coderbot/iris/mixin/MixinMinecraft_Keybinds.java @@ -0,0 +1,22 @@ +package net.coderbot.iris.mixin; + +import net.caffeinemc.mods.sodium.mixin.features.options.MinecraftClientMixin; +import net.coderbot.iris.Iris; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.profiler.Profiler; +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.CallbackInfo; + +/** + * Small hook giving Iris a chance to check for keyboard input for its keybindings. + * + *

This is equivalent to the END_CLIENT_TICK event in Fabric API, but since it's a super simple mixin and we + * only need this event (out of the many events provided by Fabric API) I've just implemented it myself. This + * alone shaves over 60kB off the released JAR size.

+ */ +@Mixin(MinecraftClient.class) +public class MixinMinecraft_Keybinds { +} diff --git a/common/src/shaders/java/net/coderbot/iris/mixin/MixinMinecraft_NoAuthInDev.java b/common/src/shaders/java/net/coderbot/iris/mixin/MixinMinecraft_NoAuthInDev.java new file mode 100644 index 00000000..856e5518 --- /dev/null +++ b/common/src/shaders/java/net/coderbot/iris/mixin/MixinMinecraft_NoAuthInDev.java @@ -0,0 +1,23 @@ +package net.coderbot.iris.mixin; + +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; +import net.caffeinemc.mods.sodium.mixin.features.options.MinecraftClientMixin; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import org.apache.logging.log4j.Logger; +import org.spongepowered.asm.mixin.Final; +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; + +/** + * Suppresses Minecraft's authentication check in development environments. It's unnecessary log spam, and there's no + * need to send off a network request to Microsoft telling them that we're using Fabric/Quilt every time we launch the + * game in the development environment. + */ +@Mixin(MinecraftClient.class) +public class MixinMinecraft_NoAuthInDev { + +} diff --git a/common/src/shaders/java/net/coderbot/iris/mixin/vertices/block_rendering/MixinChunkRebuildTask.java b/common/src/shaders/java/net/coderbot/iris/mixin/vertices/block_rendering/MixinChunkRebuildTask.java new file mode 100644 index 00000000..efca2f37 --- /dev/null +++ b/common/src/shaders/java/net/coderbot/iris/mixin/vertices/block_rendering/MixinChunkRebuildTask.java @@ -0,0 +1,72 @@ +package net.coderbot.iris.mixin.vertices.block_rendering; + +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.vertices.BlockSensitiveBufferBuilder; +import net.coderbot.iris.vertices.ExtendedDataHelper; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.block.BlockModelRenderer; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +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.util.Iterator; +import java.util.Random; +import java.util.Set; + +/** + * Captures and tracks the current block being rendered. + * + * Uses a priority of 999 so that we apply before Indigo's mixins. + */ +@Mixin(BlockModelRenderer.class) +public class MixinChunkRebuildTask { + @Unique + private BlockSensitiveBufferBuilder lastBufferBuilder; + + // Resolve the ID map on the main thread to avoid thread safety issues + @Unique + private final Object2IntMap blockStateIds = getBlockStateIds(); + + @Unique + private Object2IntMap getBlockStateIds() { + return BlockRenderingSettings.INSTANCE.getBlockStateIds(); + } + + @Unique + private short resolveBlockId(BlockState state) { + if (blockStateIds == null) { + return -1; + } + + return (short) blockStateIds.getOrDefault(state, -1); + } + + @Inject(method = "render(Lnet/minecraft/world/BlockView;Lnet/minecraft/client/render/model/BakedModel;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/render/BufferBuilder;Z)Z", at = @At(value = "HEAD")) + private void iris$onRenderBlock(BlockView world, BakedModel model, BlockState state, BlockPos pos, BufferBuilder buffer, boolean cull, CallbackInfoReturnable cir) { + try { + if (buffer instanceof BlockSensitiveBufferBuilder) { + lastBufferBuilder = ((BlockSensitiveBufferBuilder) buffer); + lastBufferBuilder.beginBlock(resolveBlockId(state), ExtendedDataHelper.BLOCK_RENDER_TYPE, pos.getX() & 0xF, pos.getY() & 0xF, pos.getZ() & 0xF); + } + } catch (Throwable e) {} + } + + @Inject(method = "render(Lnet/minecraft/world/BlockView;Lnet/minecraft/client/render/model/BakedModel;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/render/BufferBuilder;Z)Z", at = @At(value = "RETURN")) + private void iris$finishRenderingBlock(BlockView world, BakedModel model, BlockState state, BlockPos pos, BufferBuilder buffer, boolean cull, CallbackInfoReturnable cir) { + if (lastBufferBuilder != null) { + lastBufferBuilder.endBlock(); + lastBufferBuilder = null; + } + } +}