├── CHANGE_LOG.md ├── neoforge ├── gradle.properties ├── src │ └── main │ │ ├── resources │ │ ├── mixins.indicatia_neoforge.json │ │ └── META-INF │ │ │ └── neoforge.mods.toml │ │ └── java │ │ └── com │ │ └── stevekung │ │ └── indicatia │ │ ├── utils │ │ └── neoforge │ │ │ └── PlatformKeyInputImpl.java │ │ └── neoforge │ │ ├── mixin │ │ └── gui │ │ │ └── MixinGui.java │ │ └── IndicatiaNeoForge.java └── build.gradle ├── .gitignore ├── common ├── src │ └── main │ │ ├── resources │ │ ├── logo.png │ │ ├── assets │ │ │ └── indicatia │ │ │ │ ├── textures │ │ │ │ └── gui │ │ │ │ │ └── sprites │ │ │ │ │ └── widget │ │ │ │ │ ├── reload.png │ │ │ │ │ └── reload_highlighted.png │ │ │ │ └── lang │ │ │ │ ├── zh_cn.json │ │ │ │ ├── ru_ru.json │ │ │ │ ├── th_th.json │ │ │ │ └── en_us.json │ │ ├── architectury.common.json │ │ └── mixins.indicatia.json │ │ └── java │ │ └── com │ │ └── stevekung │ │ └── indicatia │ │ ├── EnchantedFoilExtender.java │ │ ├── utils │ │ ├── PlatformKeyInput.java │ │ └── RenderUtils.java │ │ ├── mixin │ │ ├── renderer │ │ │ ├── MixinLivingEntityRenderState.java │ │ │ ├── special │ │ │ │ ├── MixinConduitSpecialRenderer.java │ │ │ │ ├── MixinCopperGolemStatueSpecialRenderer.java │ │ │ │ ├── MixinBedSpecialRenderer.java │ │ │ │ ├── MixinShulkerBoxSpecialRenderer.java │ │ │ │ ├── MixinBannerSpecialRenderer.java │ │ │ │ ├── MixinDecoratedPotSpecialRenderer.java │ │ │ │ ├── MixinSkullSpecialRenderer.java │ │ │ │ ├── MixinPlayerHeadSpecialRenderer.java │ │ │ │ └── MixinChestSpecialRenderer.java │ │ │ ├── MixinSkullBlockRenderer.java │ │ │ ├── MixinDecoratedPotRenderer.java │ │ │ ├── MixinLivingEntityRenderer.java │ │ │ ├── entity │ │ │ │ └── layers │ │ │ │ │ └── MixinCustomHeadLayer.java │ │ │ ├── MixinBedRenderer.java │ │ │ ├── MixinBannerRenderer.java │ │ │ └── MixinShulkerBoxRenderer.java │ │ ├── gui │ │ │ └── screens │ │ │ │ ├── inventory │ │ │ │ └── MixinCreativeModeInventoryScreen.java │ │ │ │ ├── MixinPauseScreen.java │ │ │ │ └── recipebook │ │ │ │ └── MixinRecipeBookComponent.java │ │ └── MixinMinecraft.java │ │ ├── config │ │ └── IndicatiaConfig.java │ │ ├── EnchantedSkullRenderer.java │ │ ├── Indicatia.java │ │ └── EnchantedBannerRenderer.java └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── fabric ├── src │ └── main │ │ ├── resources │ │ ├── mixins.indicatia_fabric.json │ │ └── fabric.mod.json │ │ └── java │ │ └── com │ │ └── stevekung │ │ └── indicatia │ │ ├── fabric │ │ ├── modmenu │ │ │ └── ModMenuIntegrationIN.java │ │ ├── IndicatiaFabric.java │ │ └── mixin │ │ │ └── gui │ │ │ └── MixinGui.java │ │ └── utils │ │ └── fabric │ │ └── PlatformKeyInputImpl.java └── build.gradle ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ └── publish.yml ├── settings.gradle ├── README.md ├── LICENSE.md ├── gradle.properties ├── gradlew.bat └── gradlew /CHANGE_LOG.md: -------------------------------------------------------------------------------- 1 | * Reduced pngs file size -------------------------------------------------------------------------------- /neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | loom.platform=neoforge -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # folder 2 | .architectury-transformer 3 | .gradle 4 | .idea 5 | build 6 | run -------------------------------------------------------------------------------- /common/src/main/resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SteveKunG/Indicatia/HEAD/common/src/main/resources/logo.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SteveKunG/Indicatia/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | apply from: "https://raw.githubusercontent.com/SteveKunG/GradleScripts/main/architectury/common.gradle" 2 | 3 | tasks.shadowJar { 4 | zip64 = true 5 | } -------------------------------------------------------------------------------- /common/src/main/resources/assets/indicatia/textures/gui/sprites/widget/reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SteveKunG/Indicatia/HEAD/common/src/main/resources/assets/indicatia/textures/gui/sprites/widget/reload.png -------------------------------------------------------------------------------- /common/src/main/resources/assets/indicatia/textures/gui/sprites/widget/reload_highlighted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SteveKunG/Indicatia/HEAD/common/src/main/resources/assets/indicatia/textures/gui/sprites/widget/reload_highlighted.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /fabric/src/main/resources/mixins.indicatia_fabric.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8.7", 4 | "compatibilityLevel": "JAVA_21", 5 | "package": "com.stevekung.indicatia.fabric.mixin", 6 | "client": [ 7 | "gui.MixinGui" 8 | ], 9 | "injectors": { 10 | "defaultRequire": 1 11 | } 12 | } -------------------------------------------------------------------------------- /neoforge/src/main/resources/mixins.indicatia_neoforge.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8.7", 4 | "compatibilityLevel": "JAVA_21", 5 | "package": "com.stevekung.indicatia.neoforge.mixin", 6 | "client": [ 7 | "gui.MixinGui" 8 | ], 9 | "injectors": { 10 | "defaultRequire": 1 11 | } 12 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/EnchantedFoilExtender.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia; 2 | 3 | public interface EnchantedFoilExtender 4 | { 5 | default void indicatia$setFoil(boolean hasFoil) 6 | { 7 | throw new AssertionError("Implemented via mixin"); 8 | } 9 | 10 | default boolean indicatia$hasFoil() 11 | { 12 | throw new AssertionError("Implemented via mixin"); 13 | } 14 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | day: "monday" 8 | time: "08:00" 9 | timezone: "Asia/Bangkok" 10 | 11 | - package-ecosystem: "gradle" 12 | directory: "/" 13 | schedule: 14 | interval: "weekly" 15 | day: "monday" 16 | time: "08:00" 17 | timezone: "Asia/Bangkok" 18 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url = "https://maven.fabricmc.net/" } 4 | maven { url = "https://maven.architectury.dev/" } 5 | maven { url = "https://maven.minecraftforge.net/" } 6 | gradlePluginPortal() 7 | } 8 | } 9 | 10 | include("common") 11 | 12 | enabled_platforms.split(",").each { platform -> 13 | include(platform.trim()) 14 | } 15 | 16 | rootProject.name = "Indicatia" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](http://cf.way2muchnoise.eu/full_indicatia_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/indicatia) [![](http://cf.way2muchnoise.eu/versions/Minecraft_indicatia_all.svg)](https://www.curseforge.com/minecraft/mc-mods/indicatia) [![Discord](https://img.shields.io/discord/356400329086205953.svg?color=%237289da&label=discord&logo=discord&logoColor=%237289da)](https://discord.gg/4bAj4mkGag) 2 | 3 | # [Indicatia](https://www.curseforge.com/minecraft/mc-mods/indicatia) 4 | A small quality of life mod! -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/utils/PlatformKeyInput.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.utils; 2 | 3 | import net.minecraft.client.input.KeyEvent; 4 | 5 | import dev.architectury.injectables.annotations.ExpectPlatform; 6 | 7 | public class PlatformKeyInput 8 | { 9 | @ExpectPlatform 10 | public static boolean isAltChatEnabled() 11 | { 12 | throw new AssertionError(); 13 | } 14 | 15 | @ExpectPlatform 16 | public static boolean isAltChatMatches(KeyEvent keyEvent) 17 | { 18 | throw new AssertionError(); 19 | } 20 | } -------------------------------------------------------------------------------- /common/src/main/resources/architectury.common.json: -------------------------------------------------------------------------------- 1 | { 2 | "injected_interfaces": { 3 | "net/minecraft/class_10042": [ 4 | "com/stevekung/indicatia/EnchantedFoilExtender" 5 | ], 6 | "net/minecraft/class_8188": [ 7 | "com/stevekung/indicatia/EnchantedFoilExtender" 8 | ], 9 | "net/minecraft/class_825": [ 10 | "com/stevekung/indicatia/EnchantedFoilExtender" 11 | ], 12 | "net/minecraft/class_834": [ 13 | "com/stevekung/indicatia/EnchantedFoilExtender" 14 | ], 15 | "net/minecraft/class_823": [ 16 | "com/stevekung/indicatia/EnchantedFoilExtender" 17 | ] 18 | } 19 | } -------------------------------------------------------------------------------- /fabric/src/main/java/com/stevekung/indicatia/fabric/modmenu/ModMenuIntegrationIN.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.fabric.modmenu; 2 | 3 | import com.stevekung.indicatia.config.IndicatiaConfig; 4 | import com.terraformersmc.modmenu.api.ConfigScreenFactory; 5 | import com.terraformersmc.modmenu.api.ModMenuApi; 6 | import me.shedaniel.autoconfig.AutoConfig; 7 | 8 | public class ModMenuIntegrationIN implements ModMenuApi 9 | { 10 | @Override 11 | public ConfigScreenFactory getModConfigScreenFactory() 12 | { 13 | return parent -> AutoConfig.getConfigScreen(IndicatiaConfig.class, parent).get(); 14 | } 15 | } -------------------------------------------------------------------------------- /fabric/src/main/java/com/stevekung/indicatia/utils/fabric/PlatformKeyInputImpl.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.utils.fabric; 2 | 3 | import com.stevekung.indicatia.Indicatia; 4 | 5 | import net.minecraft.client.input.KeyEvent; 6 | 7 | public class PlatformKeyInputImpl 8 | { 9 | public static boolean isAltChatEnabled() 10 | { 11 | return Indicatia.CONFIG.enableAlternateChatKey && Indicatia.KEY_ALT_OPEN_CHAT.consumeClick(); 12 | } 13 | 14 | public static boolean isAltChatMatches(KeyEvent keyEvent) 15 | { 16 | return Indicatia.CONFIG.enableAlternateChatKey && Indicatia.KEY_ALT_OPEN_CHAT.matches(keyEvent); 17 | } 18 | } -------------------------------------------------------------------------------- /neoforge/src/main/java/com/stevekung/indicatia/utils/neoforge/PlatformKeyInputImpl.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.utils.neoforge; 2 | 3 | import com.stevekung.indicatia.Indicatia; 4 | 5 | import net.minecraft.client.input.KeyEvent; 6 | 7 | public class PlatformKeyInputImpl 8 | { 9 | public static boolean isAltChatEnabled() 10 | { 11 | return Indicatia.CONFIG.enableAlternateChatKey && Indicatia.KEY_ALT_OPEN_CHAT.consumeClick(); 12 | } 13 | 14 | public static boolean isAltChatMatches(KeyEvent keyEvent) 15 | { 16 | return Indicatia.CONFIG.enableAlternateChatKey && Indicatia.KEY_ALT_OPEN_CHAT.matches(keyEvent); 17 | } 18 | } -------------------------------------------------------------------------------- /common/src/main/resources/assets/indicatia/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "text.autoconfig.indicatia.title": "Indicatia Config", 3 | "text.autoconfig.indicatia.option.enableAlternateChatKey": "Enable Alternate Chat Key", 4 | "text.autoconfig.indicatia.option.timeOnVanillaPotionHUD": "Enable Duration on Top Right Potion HUD", 5 | "text.autoconfig.indicatia.option.confirmationOnDisconnect": "Enable Confirmation on Disconnect", 6 | "text.autoconfig.indicatia.option.enableEnchantedRenderingOnSkull": "Enable Enchanted Effect on Skull", 7 | "text.autoconfig.indicatia.option.reloadResourcesButton": "Enable Reload resources button", 8 | "key.alt_open_chat": "Alternate Open Chat", 9 | "menu.confirm_disconnect": "您确定要断开连接吗?", 10 | "menu.reload_resources": "Reload resources" 11 | } -------------------------------------------------------------------------------- /common/src/main/resources/assets/indicatia/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "text.autoconfig.indicatia.title": "Indicatia Config", 3 | "text.autoconfig.indicatia.option.enableAlternateChatKey": "Enable Alternate Chat Key", 4 | "text.autoconfig.indicatia.option.timeOnVanillaPotionHUD": "Enable Duration on Top Right Potion HUD", 5 | "text.autoconfig.indicatia.option.confirmationOnDisconnect": "Enable Confirmation on Disconnect", 6 | "text.autoconfig.indicatia.option.enableEnchantedRenderingOnSkull": "Enable Enchanted Effect on Skull", 7 | "text.autoconfig.indicatia.option.reloadResourcesButton": "Enable Reload resources button", 8 | "key.alt_open_chat": "Alternate Open Chat", 9 | "menu.confirm_disconnect": "Покинуть сервер?", 10 | "menu.reload_resources": "Reload resources" 11 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/MixinLivingEntityRenderState.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.Unique; 5 | 6 | import com.stevekung.indicatia.EnchantedFoilExtender; 7 | 8 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 9 | 10 | @Mixin(LivingEntityRenderState.class) 11 | public class MixinLivingEntityRenderState implements EnchantedFoilExtender 12 | { 13 | @Unique 14 | private boolean hasFoil; 15 | 16 | @Override 17 | public void indicatia$setFoil(boolean hasFoil) 18 | { 19 | this.hasFoil = hasFoil; 20 | } 21 | 22 | @Override 23 | public boolean indicatia$hasFoil() 24 | { 25 | return this.hasFoil; 26 | } 27 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/gui/screens/inventory/MixinCreativeModeInventoryScreen.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.gui.screens.inventory; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 6 | import com.stevekung.indicatia.utils.PlatformKeyInput; 7 | import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen; 8 | import net.minecraft.client.input.KeyEvent; 9 | 10 | @Mixin(CreativeModeInventoryScreen.class) 11 | public class MixinCreativeModeInventoryScreen 12 | { 13 | @SuppressWarnings("ConstantValue") 14 | @ModifyExpressionValue(method = "keyPressed", at = @At(value = "INVOKE", target = "net/minecraft/client/KeyMapping.matches(Lnet/minecraft/client/input/KeyEvent;)Z")) 15 | private boolean indicatia$addAltChatKey(boolean original, KeyEvent keyEvent) 16 | { 17 | return original || PlatformKeyInput.isAltChatMatches(keyEvent); 18 | } 19 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/config/IndicatiaConfig.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.config; 2 | 3 | import com.stevekung.indicatia.Indicatia; 4 | import me.shedaniel.autoconfig.ConfigData; 5 | import me.shedaniel.autoconfig.annotation.Config; 6 | import me.shedaniel.autoconfig.annotation.ConfigEntry; 7 | 8 | @Config(name = Indicatia.MOD_ID) 9 | public final class IndicatiaConfig implements ConfigData 10 | { 11 | @ConfigEntry.Gui.Tooltip 12 | public boolean enableAlternateChatKey = true; 13 | 14 | @ConfigEntry.Gui.Tooltip 15 | public boolean displayPotionDurationOnTopRightPotionHUD = true; 16 | 17 | @ConfigEntry.Gui.Tooltip 18 | public boolean confirmationOnDisconnect = true; 19 | 20 | @ConfigEntry.Gui.Tooltip 21 | public boolean enableEnchantedRenderingOnSkulls = true; 22 | 23 | @ConfigEntry.Gui.Tooltip 24 | public boolean enableEnchantedRenderingOnAllBlockEntities = true; 25 | 26 | @ConfigEntry.Gui.Tooltip 27 | public boolean enableReloadResourcesButton = true; 28 | 29 | @ConfigEntry.Gui.Tooltip 30 | public boolean saveLastSearchInRecipeBook = true; 31 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/MixinMinecraft.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Slice; 6 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 7 | import com.stevekung.indicatia.utils.PlatformKeyInput; 8 | import net.minecraft.client.Minecraft; 9 | 10 | @Mixin(Minecraft.class) 11 | public class MixinMinecraft 12 | { 13 | @SuppressWarnings("ConstantValue") 14 | @ModifyExpressionValue(method = "handleKeybinds", slice = @Slice(from = @At(value = "FIELD", target = "net/minecraft/client/Options.keyChat:Lnet/minecraft/client/KeyMapping;"), to = @At(value = "INVOKE", target = "net/minecraft/client/Minecraft.openChatScreen(Lnet/minecraft/client/gui/components/ChatComponent$ChatMethod;)V", ordinal = 0)), at = @At(value = "INVOKE", target = "net/minecraft/client/KeyMapping.consumeClick()Z")) 15 | private boolean indicatia$addAltChatKey(boolean original) 16 | { 17 | return original || PlatformKeyInput.isAltChatEnabled(); 18 | } 19 | } -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [ pull_request, push ] 3 | 4 | jobs: 5 | build: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout 9 | uses: actions/checkout@v6 10 | 11 | - name: Set up JDK 21 12 | uses: actions/setup-java@v5 13 | with: 14 | java-version: '21' 15 | distribution: 'temurin' 16 | 17 | - name: Cache Gradle packages 18 | uses: actions/cache@v5 19 | with: 20 | path: ~/.gradle/caches 21 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 22 | restore-keys: ${{ runner.os }}-gradle 23 | 24 | - name: Validate Gradle Wrapper 25 | uses: gradle/actions/wrapper-validation@v5 26 | 27 | - name: Grant execute permission to gradlew 28 | run: chmod +x gradlew 29 | 30 | - name: Build with Gradle 31 | run: ./gradlew build 32 | 33 | - name: Upload Build Artifacts 34 | uses: actions/upload-artifact@v6 35 | with: 36 | name: Artifacts 37 | path: | 38 | ./fabric/build/libs/ 39 | ./neoforge/build/libs/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Wasinthorn Suksri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # gradle 2 | org.gradle.jvmargs=-Xmx4G 3 | org.gradle.parallel=true 4 | java_version=21 5 | use_mixin=true 6 | upload_debug=true 7 | 8 | # minecraft 9 | minecraft_version=1.21.11 10 | parchmentmc_version=1.21.10:2025.10.12 11 | 12 | # mod 13 | display_name=Indicatia 14 | archives_base_name=indicatia 15 | mod_id=indicatia 16 | mod_description=A small quality of life mod! 17 | maven_group=com.stevekung.indicatia 18 | mod_version=9.1.1 19 | release_type=release 20 | enabled_platforms=fabric,neoforge 21 | cloth_config_version=20.0.148 22 | 23 | # curseforge 24 | curseforge_project_id=272146 25 | curseforge_fabric_required_dependencies=fabric-api,cloth-config 26 | curseforge_fabric_optional_dependencies=modmenu 27 | curseforge_neoforge_required_dependencies=cloth-config 28 | 29 | # modrinth 30 | modrinth_project_id=indicatia 31 | modrinth_fabric_required_dependencies=fabric-api,cloth-config 32 | modrinth_fabric_optional_dependencies=modmenu 33 | modrinth_neoforge_required_dependencies=cloth-config 34 | 35 | # fabric 36 | fabric_loader_version=0.18.2 37 | fabric_api_version=0.139.5+1.21.11 38 | modmenu_version=17.0.0-alpha.1 39 | 40 | # neoforge 41 | neoforge_version=21.11.5-beta -------------------------------------------------------------------------------- /neoforge/src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "javafml" 2 | loaderVersion = "[2,)" 3 | license = "MIT" 4 | issueTrackerURL = "https://github.com/SteveKunG/Indicatia/issues" 5 | 6 | [[mods]] 7 | modId = "${mod_id}" 8 | version = "${version}" 9 | displayName = "${display_name}" 10 | description = "${mod_description}" 11 | displayURL = "https://www.curseforge.com/minecraft/mc-mods/indicatia" 12 | updateJSONURL = "https://raw.githubusercontent.com/SteveKunG/VersionCheckLibrary/master/indicatia_version.json" 13 | logoFile = "logo.png" 14 | authors = "SteveKunG" 15 | displayTest = "IGNORE_SERVER_VERSION" 16 | 17 | [[mixins]] 18 | config = "mixins.indicatia.json" 19 | [[mixins]] 20 | config = "mixins.indicatia_neoforge.json" 21 | 22 | [[dependencies.indicatia]] 23 | modId = "neoforge" 24 | type = "required" 25 | versionRange = "[21.11.0-beta,)" 26 | ordering = "NONE" 27 | side = "CLIENT" 28 | 29 | [[dependencies.indicatia]] 30 | modId = "cloth_config" 31 | type = "required" 32 | versionRange = "[20.0,)" 33 | ordering = "NONE" 34 | side = "CLIENT" 35 | 36 | [[dependencies.indicatia]] 37 | modId = "minecraft" 38 | type = "required" 39 | versionRange = "[1.21.11,)" 40 | ordering = "NONE" 41 | side = "CLIENT" -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/special/MixinConduitSpecialRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.special; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.ModifyArg; 6 | 7 | import com.llamalad7.mixinextras.sugar.Local; 8 | import com.stevekung.indicatia.Indicatia; 9 | 10 | import net.minecraft.client.renderer.special.ConduitSpecialRenderer; 11 | 12 | @Mixin(ConduitSpecialRenderer.class) 13 | public class MixinConduitSpecialRenderer 14 | { 15 | @ModifyArg(method = "submit", at = @At( 16 | value = "INVOKE", 17 | target = "net/minecraft/client/renderer/SubmitNodeCollector.submitModelPart(Lnet/minecraft/client/model/geom/ModelPart;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/rendertype/RenderType;IILnet/minecraft/client/renderer/texture/TextureAtlasSprite;ZZILnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;I)V"), 18 | index = 7) 19 | private boolean indicatia$addEnchantedGlint(boolean original, @Local(argsOnly = true) boolean hasFoil) 20 | { 21 | return Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities && hasFoil; 22 | } 23 | } -------------------------------------------------------------------------------- /fabric/src/main/java/com/stevekung/indicatia/fabric/IndicatiaFabric.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.fabric; 2 | 3 | import org.lwjgl.glfw.GLFW; 4 | import com.mojang.blaze3d.platform.InputConstants; 5 | import com.stevekung.indicatia.Indicatia; 6 | import net.fabricmc.api.ClientModInitializer; 7 | import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; 8 | import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; 9 | import net.fabricmc.fabric.api.client.screen.v1.Screens; 10 | import net.minecraft.client.KeyMapping; 11 | 12 | public class IndicatiaFabric implements ClientModInitializer 13 | { 14 | static 15 | { 16 | Indicatia.KEY_ALT_OPEN_CHAT = new KeyMapping("key.alt_open_chat", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_ENTER, KeyMapping.Category.MULTIPLAYER); 17 | } 18 | 19 | @Override 20 | public void onInitializeClient() 21 | { 22 | Indicatia.initConfig(); 23 | KeyBindingHelper.registerKeyBinding(Indicatia.KEY_ALT_OPEN_CHAT); 24 | ScreenEvents.AFTER_INIT.register((minecraft, screen, scaledWidth, scaledHeight) -> 25 | { 26 | if (Indicatia.canAddReloadButton(screen)) 27 | { 28 | Screens.getButtons(screen).add(Indicatia.getReloadResourcesButton(screen, minecraft)); 29 | } 30 | }); 31 | } 32 | } -------------------------------------------------------------------------------- /common/src/main/resources/mixins.indicatia.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8.7", 4 | "compatibilityLevel": "JAVA_21", 5 | "package": "com.stevekung.indicatia.mixin", 6 | "client": [ 7 | "gui.screens.inventory.MixinCreativeModeInventoryScreen", 8 | "gui.screens.recipebook.MixinRecipeBookComponent", 9 | "gui.screens.MixinPauseScreen", 10 | 11 | "renderer.entity.layers.MixinCustomHeadLayer", 12 | 13 | "renderer.special.MixinBannerSpecialRenderer", 14 | "renderer.special.MixinBedSpecialRenderer", 15 | "renderer.special.MixinChestSpecialRenderer", 16 | "renderer.special.MixinConduitSpecialRenderer", 17 | "renderer.special.MixinCopperGolemStatueSpecialRenderer", 18 | "renderer.special.MixinDecoratedPotSpecialRenderer", 19 | "renderer.special.MixinPlayerHeadSpecialRenderer", 20 | "renderer.special.MixinShulkerBoxSpecialRenderer", 21 | "renderer.special.MixinSkullSpecialRenderer", 22 | 23 | "renderer.MixinBedRenderer", 24 | "renderer.MixinBannerRenderer", 25 | "renderer.MixinDecoratedPotRenderer", 26 | "renderer.MixinLivingEntityRenderer", 27 | "renderer.MixinLivingEntityRenderState", 28 | "renderer.MixinShulkerBoxRenderer", 29 | "renderer.MixinSkullBlockRenderer", 30 | 31 | "MixinMinecraft" 32 | ], 33 | "injectors": { 34 | "defaultRequire": 1 35 | } 36 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/MixinSkullBlockRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | 6 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 7 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 8 | import com.stevekung.indicatia.Indicatia; 9 | 10 | import net.minecraft.client.renderer.blockentity.SkullBlockRenderer; 11 | import net.minecraft.client.renderer.rendertype.RenderType; 12 | import net.minecraft.client.renderer.rendertype.RenderTypes; 13 | import net.minecraft.resources.Identifier; 14 | 15 | @Mixin(SkullBlockRenderer.class) 16 | public class MixinSkullBlockRenderer 17 | { 18 | @WrapOperation(method = "getSkullRenderType", at = @At( 19 | value = "INVOKE", 20 | target = "net/minecraft/client/renderer/rendertype/RenderTypes.entityCutoutNoCullZOffset(Lnet/minecraft/resources/Identifier;)Lnet/minecraft/client/renderer/rendertype/RenderType;")) 21 | private static RenderType indicatia$changeSkullRenderType(Identifier identifier, Operation original) 22 | { 23 | if (Indicatia.CONFIG.enableEnchantedRenderingOnSkulls) 24 | { 25 | return RenderTypes.entityTranslucent(identifier); 26 | } 27 | return original.call(identifier); 28 | } 29 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/utils/RenderUtils.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.utils; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.Font; 5 | import net.minecraft.client.gui.GuiGraphics; 6 | import net.minecraft.network.chat.Component; 7 | import net.minecraft.network.chat.FontDescription; 8 | import net.minecraft.network.chat.Style; 9 | import net.minecraft.util.Mth; 10 | import net.minecraft.util.StringUtil; 11 | import net.minecraft.world.effect.MobEffectInstance; 12 | 13 | public class RenderUtils 14 | { 15 | private static final FontDescription UNIFORM = new FontDescription.Resource(Minecraft.UNIFORM_FONT); 16 | 17 | public static void renderPotionDurationOnTopRight(Font font, GuiGraphics guiGraphics, MobEffectInstance mobEffectInstance, int x, int y, float alpha, float ticksPerSecond) 18 | { 19 | var isInfinite = mobEffectInstance.isInfiniteDuration(); 20 | var ticks = Mth.floor((float) mobEffectInstance.getDuration()); 21 | var component = isInfinite ? Component.translatable("effect.duration.infinite") : Component.literal(StringUtil.formatTickDuration(ticks, ticksPerSecond)); 22 | var text = component.withStyle(Style.EMPTY.withFont(isInfinite ? null : UNIFORM)); 23 | var color = 0xFFFFFF | Mth.floor(alpha * 255.0F) << 24 & 0xFF000000; 24 | guiGraphics.drawCenteredString(font, text, x + 12, y + 15, color); 25 | } 26 | } -------------------------------------------------------------------------------- /neoforge/build.gradle: -------------------------------------------------------------------------------- 1 | apply from: "https://raw.githubusercontent.com/SteveKunG/GradleScripts/main/architectury/neoforge.gradle" 2 | 3 | loom { 4 | runs.configureEach { 5 | properties project.commonProperties 6 | vmArgs project.commonVmArgs 7 | vmArgs project.hotswapVmArgs 8 | } 9 | 10 | runs { 11 | client { 12 | if (project.hasProperty("usernameAndUUID")) { 13 | programArgs project.usernameAndUUID 14 | } 15 | } 16 | server { 17 | ideConfigGenerated = false 18 | } 19 | } 20 | } 21 | 22 | String fileName = "${archives_base_name}-mc${minecraft_version}" 23 | 24 | shadowJar { 25 | configurations = [project.configurations.shadowBundle] 26 | archiveClassifier = "dev" 27 | archiveVersion = "v${mod_version}" 28 | archiveBaseName = fileName 29 | } 30 | 31 | sourcesJar { 32 | Jar commonSources = project(":common").sourcesJar 33 | dependsOn commonSources 34 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 35 | from commonSources.archiveFile.map { zipTree(it) } 36 | } 37 | 38 | remapSourcesJar { 39 | archiveVersion = "v${mod_version}" 40 | archiveBaseName = fileName 41 | } 42 | 43 | remapJar { 44 | inputFile.set shadowJar.archiveFile 45 | dependsOn shadowJar 46 | archiveClassifier = "neoforge" 47 | archiveVersion = "v${mod_version}" 48 | archiveBaseName = fileName 49 | } -------------------------------------------------------------------------------- /fabric/build.gradle: -------------------------------------------------------------------------------- 1 | apply from: "https://raw.githubusercontent.com/SteveKunG/GradleScripts/main/architectury/fabric.gradle" 2 | 3 | loom { 4 | runs.configureEach { 5 | properties project.commonProperties 6 | vmArgs project.commonVmArgs 7 | vmArgs project.hotswapVmArgs 8 | } 9 | 10 | runs { 11 | client { 12 | if (project.hasProperty("usernameAndUUID")) { 13 | programArgs project.usernameAndUUID 14 | } 15 | } 16 | server { 17 | ideConfigGenerated = false 18 | } 19 | } 20 | } 21 | 22 | String fileName = "${archives_base_name}-mc${minecraft_version}" 23 | List devExcludes = ["architectury.common.json"] 24 | 25 | shadowJar { 26 | configurations = [project.configurations.shadowBundle] 27 | archiveClassifier = "dev" 28 | archiveVersion = "v${mod_version}" 29 | archiveBaseName = fileName 30 | excludes = devExcludes 31 | } 32 | 33 | sourcesJar { 34 | Jar commonSources = project(":common").sourcesJar 35 | dependsOn commonSources 36 | from commonSources.archiveFile.map { zipTree(it) } 37 | excludes = devExcludes 38 | } 39 | 40 | remapSourcesJar { 41 | archiveVersion = "v${mod_version}" 42 | archiveBaseName = fileName 43 | } 44 | 45 | remapJar { 46 | inputFile.set shadowJar.archiveFile 47 | dependsOn shadowJar 48 | archiveClassifier = "fabric" 49 | archiveVersion = "v${mod_version}" 50 | archiveBaseName = fileName 51 | } -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | version: 6 | description: 'Version (Example: mc1.21.9-v9.0.2)' 7 | required: true 8 | 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v6 15 | 16 | - name: Create version tag 17 | uses: actions/github-script@v8 18 | with: 19 | script: | 20 | github.rest.git.createRef({ 21 | owner: context.repo.owner, 22 | repo: context.repo.repo, 23 | ref: "refs/tags/${{ github.event.inputs.version }}", 24 | sha: context.sha 25 | }) 26 | 27 | - name: Fetch tags 28 | run: git fetch --tags 29 | 30 | - name: Set up JDK 21 31 | uses: actions/setup-java@v5 32 | with: 33 | java-version: '21' 34 | distribution: 'temurin' 35 | 36 | - name: Cache Gradle packages 37 | uses: actions/cache@v5 38 | with: 39 | path: ~/.gradle/caches 40 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 41 | restore-keys: ${{ runner.os }}-gradle 42 | 43 | - name: Validate Gradle Wrapper 44 | uses: gradle/actions/wrapper-validation@v5 45 | 46 | - name: Grant execute permission to gradlew 47 | run: chmod +x gradlew 48 | 49 | - name: Publish Mod to CurseForge/Modrinth 50 | run: ./gradlew curseforgeModrinthNeoForge curseforgeModrinthFabric -Pupload_debug=false -Pcurseforge_api_token=${{ secrets.CURSEFORGE_API_TOKEN }} -Pmodrinth_api_token=${{ secrets.MODRINTH_API_TOKEN }} -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/MixinDecoratedPotRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.Unique; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.ModifyArg; 7 | 8 | import com.stevekung.indicatia.EnchantedFoilExtender; 9 | 10 | import net.minecraft.client.renderer.blockentity.DecoratedPotRenderer; 11 | 12 | @Mixin(DecoratedPotRenderer.class) 13 | public class MixinDecoratedPotRenderer implements EnchantedFoilExtender 14 | { 15 | @Unique 16 | private boolean hasFoil; 17 | 18 | @Override 19 | public void indicatia$setFoil(boolean hasFoil) 20 | { 21 | this.hasFoil = hasFoil; 22 | } 23 | 24 | @Override 25 | public boolean indicatia$hasFoil() 26 | { 27 | return this.hasFoil; 28 | } 29 | 30 | @ModifyArg( 31 | method = "submit(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;IILnet/minecraft/world/level/block/entity/PotDecorations;I)V", 32 | at = @At( 33 | value = "INVOKE", 34 | target = "net/minecraft/client/renderer/SubmitNodeCollector.submitModelPart(Lnet/minecraft/client/model/geom/ModelPart;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/rendertype/RenderType;IILnet/minecraft/client/renderer/texture/TextureAtlasSprite;ZZILnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;I)V"), 35 | index = 7) 36 | private boolean indicatia$addEnchantedGlint(boolean original) 37 | { 38 | return this.hasFoil; 39 | } 40 | } -------------------------------------------------------------------------------- /common/src/main/resources/assets/indicatia/lang/th_th.json: -------------------------------------------------------------------------------- 1 | { 2 | "text.autoconfig.indicatia.title": "การตั้งค่า Indicatia", 3 | "text.autoconfig.indicatia.option.enableAlternateChatKey": "เปิดใช้งานปุ่มแชทสำรอง", 4 | "text.autoconfig.indicatia.option.enableAlternateChatKey.@Tooltip": "ตัวเลือกนี้อนุญาตให้ใช้ปุ่ม Numpad Enter เพื่อเปิดแชท", 5 | "text.autoconfig.indicatia.option.displayPotionDurationOnTopRightPotionHUD": "เปิดใช้งานแสดงระยะเวลาของยาที่มุมขวาบนของ Potion HUD", 6 | "text.autoconfig.indicatia.option.displayPotionDurationOnTopRightPotionHUD.@Tooltip": "แสดงระยะเวลาของยาที่มุมขวาบนของ Potion HUD", 7 | "text.autoconfig.indicatia.option.confirmationOnDisconnect": "เปิดใช้งานหน้าจอยืนยันก่อนตัดการเชื่อมต่อ", 8 | "text.autoconfig.indicatia.option.confirmationOnDisconnect.@Tooltip": "แสดงหน้าจอยืนยันก่อนตัดการเชื่อมต่อจากเซิร์ฟเวอร์", 9 | "text.autoconfig.indicatia.option.enableEnchantedRenderingOnSkulls": "เปิดใช้งานการแสดงเอฟเฟกต์เอนชานต์ที่กะโหลก", 10 | "text.autoconfig.indicatia.option.enableEnchantedRenderingOnSkulls.@Tooltip": "เปิดใช้งานการแสดงเอฟเฟกต์เอนชานต์ที่กะโหลก", 11 | "text.autoconfig.indicatia.option.enableReloadResourcesButton": "เปิดใช้งานปุ่มรีโหลดรีซอร์ส", 12 | "text.autoconfig.indicatia.option.enableReloadResourcesButton.@Tooltip": "เปิดใช้งานปุ่มรีโหลดทรัพยากรซ้ำบนหน้าจอการเลือกแพ็ค", 13 | "text.autoconfig.indicatia.option.saveLastSearchInRecipeBook": "เปิดใช้งานการค้นหาล่าสุดในหนังสือสูตรคราฟต์", 14 | "text.autoconfig.indicatia.option.saveLastSearchInRecipeBook.@Tooltip": "ตัวเลือกนี้จะบันทึกการค้นหาครั้งล่าสุดของคุณไว้ในหนังสือสูตรคราฟต์", 15 | "key.alt_open_chat": "แชทสำรอง", 16 | "menu.confirm_disconnect": "คุณต้องการตัดการเชื่อมต่อหรือไม่?", 17 | "menu.reload_resources": "รีโหลดรีซอร์ส" 18 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/special/MixinCopperGolemStatueSpecialRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.special; 2 | 3 | import org.spongepowered.asm.mixin.Final; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | import com.mojang.blaze3d.vertex.PoseStack; 11 | import com.stevekung.indicatia.Indicatia; 12 | 13 | import net.minecraft.client.model.object.statue.CopperGolemStatueModel; 14 | import net.minecraft.client.renderer.SubmitNodeCollector; 15 | import net.minecraft.client.renderer.rendertype.RenderTypes; 16 | import net.minecraft.client.renderer.special.CopperGolemStatueSpecialRenderer; 17 | import net.minecraft.core.Direction; 18 | import net.minecraft.world.item.ItemDisplayContext; 19 | 20 | @Mixin(CopperGolemStatueSpecialRenderer.class) 21 | public class MixinCopperGolemStatueSpecialRenderer 22 | { 23 | @Shadow 24 | @Final 25 | CopperGolemStatueModel model; 26 | 27 | @Inject(method = "submit", at = @At("TAIL")) 28 | private void indicatia$addEnchantedGlint(ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, int packedOverlay, boolean hasFoil, int outlineColor, CallbackInfo info) 29 | { 30 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities && hasFoil) 31 | { 32 | submitNodeCollector.submitModel(this.model, Direction.SOUTH, poseStack, RenderTypes.entityGlint(), packedLight, packedOverlay, -1, null, outlineColor, null); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/gui/screens/MixinPauseScreen.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.gui.screens; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.ModifyArg; 6 | import com.stevekung.indicatia.Indicatia; 7 | import net.minecraft.client.gui.components.Button; 8 | import net.minecraft.client.gui.screens.ConfirmScreen; 9 | import net.minecraft.client.gui.screens.PauseScreen; 10 | import net.minecraft.client.gui.screens.Screen; 11 | import net.minecraft.network.chat.CommonComponents; 12 | import net.minecraft.network.chat.Component; 13 | 14 | @Mixin(PauseScreen.class) 15 | public class MixinPauseScreen extends Screen 16 | { 17 | MixinPauseScreen() 18 | { 19 | super(null); 20 | } 21 | 22 | @ModifyArg(method = "createPauseMenu", at = @At(value = "INVOKE", target = "net/minecraft/client/gui/components/Button.builder(Lnet/minecraft/network/chat/Component;Lnet/minecraft/client/gui/components/Button$OnPress;)Lnet/minecraft/client/gui/components/Button$Builder;", ordinal = 1), index = 1) 23 | private Button.OnPress indicatia$replaceDisconnectButton(Button.OnPress originalOnPress) 24 | { 25 | return Indicatia.CONFIG.confirmationOnDisconnect && !this.minecraft.isLocalServer() ? button -> this.minecraft.setScreen(new ConfirmScreen(yes -> 26 | { 27 | if (yes) 28 | { 29 | originalOnPress.onPress(button); 30 | } 31 | else 32 | { 33 | this.minecraft.setScreen(this); 34 | } 35 | }, Component.translatable("menu.confirm_disconnect"), Component.empty(), CommonComponents.GUI_YES, CommonComponents.GUI_CANCEL)) : originalOnPress; 36 | } 37 | } -------------------------------------------------------------------------------- /fabric/src/main/java/com/stevekung/indicatia/fabric/mixin/gui/MixinGui.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.fabric.mixin.gui; 2 | 3 | import org.spongepowered.asm.mixin.Final; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | import com.llamalad7.mixinextras.sugar.Local; 10 | import com.stevekung.indicatia.Indicatia; 11 | import com.stevekung.indicatia.utils.RenderUtils; 12 | import net.minecraft.client.DeltaTracker; 13 | import net.minecraft.client.Minecraft; 14 | import net.minecraft.client.gui.Gui; 15 | import net.minecraft.client.gui.GuiGraphics; 16 | import net.minecraft.world.effect.MobEffectInstance; 17 | 18 | @Mixin(Gui.class) 19 | public class MixinGui 20 | { 21 | @Shadow 22 | @Final 23 | Minecraft minecraft; 24 | 25 | @Inject(method = "renderEffects", at = @At( 26 | value = "INVOKE", 27 | target = "net/minecraft/client/gui/GuiGraphics.blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIIII)V", 28 | shift = At.Shift.AFTER)) 29 | private void indicatia$addPotionTime(GuiGraphics guiGraphics, DeltaTracker deltaTracker, CallbackInfo info, @Local MobEffectInstance mobEffectInstance, @Local(index = 9, ordinal = 2) int x, @Local(index = 10, ordinal = 3) int y, @Local(index = 11) float alpha) 30 | { 31 | if (Indicatia.CONFIG.displayPotionDurationOnTopRightPotionHUD) 32 | { 33 | RenderUtils.renderPotionDurationOnTopRight(this.minecraft.font, guiGraphics, mobEffectInstance, x, y, alpha, this.minecraft.level.tickRateManager().tickrate()); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${mod_id}", 4 | "version": "${version}", 5 | "name": "${display_name}", 6 | "description": "${mod_description}", 7 | "authors": [ 8 | "SteveKunG" 9 | ], 10 | "contact": { 11 | "homepage": "https://www.curseforge.com/minecraft/mc-mods/indicatia", 12 | "sources": "https://github.com/SteveKunG/Indicatia", 13 | "issues": "https://github.com/SteveKunG/Indicatia/issues" 14 | }, 15 | "license": "MIT", 16 | "icon": "logo.png", 17 | "environment": "client", 18 | "entrypoints": { 19 | "client": [ 20 | "com.stevekung.indicatia.fabric.IndicatiaFabric" 21 | ], 22 | "modmenu": [ 23 | "com.stevekung.indicatia.fabric.modmenu.ModMenuIntegrationIN" 24 | ] 25 | }, 26 | "depends": { 27 | "fabricloader": ">=0.18", 28 | "fabric": ">=0.139", 29 | "cloth-config": ">=20.0", 30 | "minecraft": "~1.21.11" 31 | }, 32 | "mixins": [ 33 | "mixins.indicatia.json", 34 | "mixins.indicatia_fabric.json" 35 | ], 36 | "custom": { 37 | "modmenu": { 38 | "links": { 39 | "modmenu.discord": "https://discord.gg/4bAj4mkGag" 40 | } 41 | }, 42 | "loom:injected_interfaces": { 43 | "net/minecraft/class_10042": [ 44 | "com/stevekung/indicatia/EnchantedFoilExtender" 45 | ], 46 | "net/minecraft/class_8188": [ 47 | "com/stevekung/indicatia/EnchantedFoilExtender" 48 | ], 49 | "net/minecraft/class_825": [ 50 | "com/stevekung/indicatia/EnchantedFoilExtender" 51 | ], 52 | "net/minecraft/class_834": [ 53 | "com/stevekung/indicatia/EnchantedFoilExtender" 54 | ], 55 | "net/minecraft/class_823": [ 56 | "com/stevekung/indicatia/EnchantedFoilExtender" 57 | ] 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /neoforge/src/main/java/com/stevekung/indicatia/neoforge/mixin/gui/MixinGui.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.neoforge.mixin.gui; 2 | 3 | import org.spongepowered.asm.mixin.Final; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | import com.llamalad7.mixinextras.sugar.Local; 11 | import com.stevekung.indicatia.Indicatia; 12 | import com.stevekung.indicatia.utils.RenderUtils; 13 | 14 | import net.minecraft.client.DeltaTracker; 15 | import net.minecraft.client.Minecraft; 16 | import net.minecraft.client.gui.Gui; 17 | import net.minecraft.client.gui.GuiGraphics; 18 | import net.minecraft.world.effect.MobEffectInstance; 19 | 20 | @Mixin(Gui.class) 21 | public class MixinGui 22 | { 23 | @Shadow 24 | @Final 25 | Minecraft minecraft; 26 | 27 | @Inject(method = "renderEffects", at = @At( 28 | value = "INVOKE", 29 | target = "net/minecraft/client/gui/GuiGraphics.blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIIII)V", 30 | shift = At.Shift.AFTER)) 31 | private void indicatia$addPotionTime(GuiGraphics guiGraphics, DeltaTracker deltaTracker, CallbackInfo info, @Local MobEffectInstance mobEffectInstance, @Local(index = 10, ordinal = 2) int x, @Local(index = 11, ordinal = 3) int y, @Local(index = 12) float alpha) 32 | { 33 | if (Indicatia.CONFIG.displayPotionDurationOnTopRightPotionHUD) 34 | { 35 | RenderUtils.renderPotionDurationOnTopRight(this.minecraft.font, guiGraphics, mobEffectInstance, x, y, alpha, this.minecraft.level.tickRateManager().tickrate()); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/special/MixinBedSpecialRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.special; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.Shadow; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | import com.mojang.blaze3d.vertex.PoseStack; 10 | import com.stevekung.indicatia.Indicatia; 11 | 12 | import net.minecraft.client.renderer.SubmitNodeCollector; 13 | import net.minecraft.client.renderer.blockentity.BedRenderer; 14 | import net.minecraft.client.renderer.special.BedSpecialRenderer; 15 | import net.minecraft.world.item.ItemDisplayContext; 16 | 17 | @Mixin(BedSpecialRenderer.class) 18 | public class MixinBedSpecialRenderer 19 | { 20 | @Shadow 21 | BedRenderer bedRenderer; 22 | 23 | @Inject(method = "submit", at = @At("HEAD")) 24 | private void indicatia$preHasFoil(ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, int packedOverlay, boolean hasFoil, int outlineColor, CallbackInfo info) 25 | { 26 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 27 | { 28 | this.bedRenderer.indicatia$setFoil(hasFoil); 29 | } 30 | } 31 | 32 | @Inject(method = "submit", at = @At("TAIL")) 33 | private void indicatia$postHasFoil(ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, int packedOverlay, boolean hasFoil, int outlineColor, CallbackInfo info) 34 | { 35 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 36 | { 37 | this.bedRenderer.indicatia$setFoil(false); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/special/MixinShulkerBoxSpecialRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.special; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.Shadow; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | import com.mojang.blaze3d.vertex.PoseStack; 10 | import com.stevekung.indicatia.Indicatia; 11 | 12 | import net.minecraft.client.renderer.SubmitNodeCollector; 13 | import net.minecraft.client.renderer.blockentity.ShulkerBoxRenderer; 14 | import net.minecraft.client.renderer.special.ShulkerBoxSpecialRenderer; 15 | import net.minecraft.world.item.ItemDisplayContext; 16 | 17 | @Mixin(ShulkerBoxSpecialRenderer.class) 18 | public class MixinShulkerBoxSpecialRenderer 19 | { 20 | @Shadow 21 | ShulkerBoxRenderer shulkerBoxRenderer; 22 | 23 | @Inject(method = "submit", at = @At("HEAD")) 24 | private void indicatia$preHasFoil(ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, int packedOverlay, boolean hasFoil, int outlineColor, CallbackInfo info) 25 | { 26 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 27 | { 28 | this.shulkerBoxRenderer.indicatia$setFoil(hasFoil); 29 | } 30 | } 31 | 32 | @Inject(method = "submit", at = @At("TAIL")) 33 | private void indicatia$postHasFoil(ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, int packedOverlay, boolean hasFoil, int outlineColor, CallbackInfo info) 34 | { 35 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 36 | { 37 | this.shulkerBoxRenderer.indicatia$setFoil(false); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/EnchantedSkullRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import com.mojang.blaze3d.vertex.PoseStack; 6 | 7 | import net.minecraft.client.model.object.skull.SkullModelBase; 8 | import net.minecraft.client.renderer.SubmitNodeCollector; 9 | import net.minecraft.client.renderer.feature.ModelFeatureRenderer; 10 | import net.minecraft.client.renderer.rendertype.RenderType; 11 | import net.minecraft.client.renderer.rendertype.RenderTypes; 12 | import net.minecraft.client.renderer.texture.OverlayTexture; 13 | import net.minecraft.core.Direction; 14 | 15 | public class EnchantedSkullRenderer 16 | { 17 | public static void submitSkull(@Nullable Direction direction, float yRot, float animationPos, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, SkullModelBase skullModelBase, RenderType renderType, int outlineColor, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay, boolean hasFoil) 18 | { 19 | poseStack.pushPose(); 20 | 21 | if (direction == null) 22 | { 23 | poseStack.translate(0.5F, 0.0F, 0.5F); 24 | } 25 | else 26 | { 27 | poseStack.translate(0.5F - direction.getStepX() * 0.25F, 0.25F, 0.5F - direction.getStepZ() * 0.25F); 28 | } 29 | 30 | poseStack.scale(-1.0F, -1.0F, 1.0F); 31 | var state = new SkullModelBase.State(); 32 | state.animationPos = animationPos; 33 | state.yRot = yRot; 34 | submitNodeCollector.submitModel(skullModelBase, state, poseStack, renderType, packedLight, OverlayTexture.NO_OVERLAY, outlineColor, crumblingOverlay); 35 | 36 | if (hasFoil) 37 | { 38 | submitNodeCollector.submitModel(skullModelBase, state, poseStack, RenderTypes.entityGlint(), packedLight, OverlayTexture.NO_OVERLAY, outlineColor, crumblingOverlay); 39 | } 40 | 41 | poseStack.popPose(); 42 | } 43 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/special/MixinBannerSpecialRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.special; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | import com.mojang.blaze3d.vertex.PoseStack; 11 | import com.stevekung.indicatia.Indicatia; 12 | 13 | import net.minecraft.client.renderer.SubmitNodeCollector; 14 | import net.minecraft.client.renderer.blockentity.BannerRenderer; 15 | import net.minecraft.client.renderer.special.BannerSpecialRenderer; 16 | import net.minecraft.world.item.ItemDisplayContext; 17 | import net.minecraft.world.level.block.entity.BannerPatternLayers; 18 | 19 | @Mixin(BannerSpecialRenderer.class) 20 | public class MixinBannerSpecialRenderer 21 | { 22 | @Shadow 23 | BannerRenderer bannerRenderer; 24 | 25 | @Inject(method = "submit", at = @At("HEAD")) 26 | private void indicatia$preHasFoil(@Nullable BannerPatternLayers bannerPatternLayers, ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, int packedOverlay, boolean hasFoil, int outlineColor, CallbackInfo info) 27 | { 28 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 29 | { 30 | this.bannerRenderer.indicatia$setFoil(hasFoil); 31 | } 32 | } 33 | 34 | @Inject(method = "submit", at = @At("TAIL")) 35 | private void indicatia$postHasFoil(@Nullable BannerPatternLayers bannerPatternLayers, ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, int packedOverlay, boolean hasFoil, int outlineColor, CallbackInfo info) 36 | { 37 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 38 | { 39 | this.bannerRenderer.indicatia$setFoil(false); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /common/src/main/resources/assets/indicatia/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "text.autoconfig.indicatia.title": "Indicatia Config", 3 | "text.autoconfig.indicatia.option.enableAlternateChatKey": "Enable Alternate Chat Key", 4 | "text.autoconfig.indicatia.option.enableAlternateChatKey.@Tooltip": "This option allows to use Numpad Enter key to open the chat.", 5 | "text.autoconfig.indicatia.option.displayPotionDurationOnTopRightPotionHUD": "Enable Potion Duration on the Top Right of Potion HUD", 6 | "text.autoconfig.indicatia.option.displayPotionDurationOnTopRightPotionHUD.@Tooltip": "Display potion duration time on the top right of Potion HUD.", 7 | "text.autoconfig.indicatia.option.confirmationOnDisconnect": "Enable Confirmation Screen before Disconnect", 8 | "text.autoconfig.indicatia.option.confirmationOnDisconnect.@Tooltip": "Show confirmation screen before disconnect from the server.", 9 | "text.autoconfig.indicatia.option.enableEnchantedRenderingOnSkulls": "Enable Enchanted Rendering on Skulls", 10 | "text.autoconfig.indicatia.option.enableEnchantedRenderingOnSkulls.@Tooltip": "Enable enchanting effect rendering on skulls.", 11 | "text.autoconfig.indicatia.option.enableEnchantedRenderingOnAllBlockEntities": "Enable Enchanted Rendering on all Block Entities", 12 | "text.autoconfig.indicatia.option.enableEnchantedRenderingOnAllBlockEntities.@Tooltip": "Enable enchanting effect rendering on vanilla block entities. May caused some z-fighting on certain block entities.", 13 | "text.autoconfig.indicatia.option.enableReloadResourcesButton": "Enable reload resources button", 14 | "text.autoconfig.indicatia.option.enableReloadResourcesButton.@Tooltip": "Enable reload resources button on a pack selection screen.", 15 | "text.autoconfig.indicatia.option.saveLastSearchInRecipeBook": "Save Last Search in the Recipe Book", 16 | "text.autoconfig.indicatia.option.saveLastSearchInRecipeBook.@Tooltip": "This option saves your last search in the recipe book.", 17 | "key.alt_open_chat": "Alternate Open Chat", 18 | "menu.confirm_disconnect": "Do you want to disconnect?", 19 | "menu.reload_resources": "Reload resources" 20 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/MixinLivingEntityRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Inject; 6 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 7 | 8 | import com.llamalad7.mixinextras.sugar.Local; 9 | import com.stevekung.indicatia.Indicatia; 10 | 11 | import net.minecraft.client.renderer.entity.LivingEntityRenderer; 12 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 13 | import net.minecraft.world.entity.LivingEntity; 14 | import net.minecraft.world.item.ItemStack; 15 | 16 | @Mixin(LivingEntityRenderer.class) 17 | public class MixinLivingEntityRenderer 18 | { 19 | @Inject(method = "extractRenderState", at = @At( 20 | value = "FIELD", 21 | target = "net/minecraft/client/renderer/entity/state/LivingEntityRenderState.wornHeadProfile:Lnet/minecraft/world/item/component/ResolvableProfile;", 22 | ordinal = 0)) 23 | private void indicatia$extractHeadGlintState(LivingEntity livingEntity, LivingEntityRenderState livingEntityRenderState, float partialTicks, CallbackInfo info, @Local ItemStack itemStack) 24 | { 25 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 26 | { 27 | livingEntityRenderState.indicatia$setFoil(itemStack.hasFoil()); 28 | } 29 | } 30 | 31 | @Inject(method = "extractRenderState", at = @At( 32 | value = "FIELD", 33 | target = "net/minecraft/client/renderer/entity/state/LivingEntityRenderState.wornHeadProfile:Lnet/minecraft/world/item/component/ResolvableProfile;", 34 | ordinal = 1)) 35 | private void indicatia$clearHeadGlintState(LivingEntity livingEntity, LivingEntityRenderState livingEntityRenderState, float partialTicks, CallbackInfo info) 36 | { 37 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 38 | { 39 | livingEntityRenderState.indicatia$setFoil(false); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/special/MixinDecoratedPotSpecialRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.special; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | import com.mojang.blaze3d.vertex.PoseStack; 11 | import com.stevekung.indicatia.Indicatia; 12 | 13 | import net.minecraft.client.renderer.SubmitNodeCollector; 14 | import net.minecraft.client.renderer.blockentity.DecoratedPotRenderer; 15 | import net.minecraft.client.renderer.special.DecoratedPotSpecialRenderer; 16 | import net.minecraft.world.item.ItemDisplayContext; 17 | import net.minecraft.world.level.block.entity.PotDecorations; 18 | 19 | @Mixin(DecoratedPotSpecialRenderer.class) 20 | public class MixinDecoratedPotSpecialRenderer 21 | { 22 | @Shadow 23 | DecoratedPotRenderer decoratedPotRenderer; 24 | 25 | @Inject(method = "submit", at = @At("HEAD")) 26 | private void indicatia$preHasFoil(@Nullable PotDecorations potDecorations, ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, int packedOverlay, boolean hasFoil, int outlineColor, CallbackInfo info) 27 | { 28 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 29 | { 30 | this.decoratedPotRenderer.indicatia$setFoil(hasFoil); 31 | } 32 | } 33 | 34 | @Inject(method = "submit", at = @At("TAIL")) 35 | private void indicatia$postHasFoil(@Nullable PotDecorations potDecorations, ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, int packedOverlay, boolean hasFoil, int outlineColor, CallbackInfo info) 36 | { 37 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities) 38 | { 39 | this.decoratedPotRenderer.indicatia$setFoil(false); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/special/MixinSkullSpecialRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.special; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Redirect; 7 | 8 | import com.llamalad7.mixinextras.sugar.Local; 9 | import com.mojang.blaze3d.vertex.PoseStack; 10 | import com.stevekung.indicatia.EnchantedSkullRenderer; 11 | import com.stevekung.indicatia.Indicatia; 12 | 13 | import net.minecraft.client.model.object.skull.SkullModelBase; 14 | import net.minecraft.client.renderer.SubmitNodeCollector; 15 | import net.minecraft.client.renderer.feature.ModelFeatureRenderer; 16 | import net.minecraft.client.renderer.rendertype.RenderType; 17 | import net.minecraft.client.renderer.special.SkullSpecialRenderer; 18 | import net.minecraft.core.Direction; 19 | 20 | @Mixin(SkullSpecialRenderer.class) 21 | public class MixinSkullSpecialRenderer 22 | { 23 | @Redirect(method = "submit", at = @At( 24 | value = "INVOKE", 25 | target = "net/minecraft/client/renderer/blockentity/SkullBlockRenderer.submitSkull (Lnet/minecraft/core/Direction;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/client/model/object/skull/SkullModelBase;Lnet/minecraft/client/renderer/rendertype/RenderType;ILnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;)V")) 26 | private void indicatia$useCustomEnchantedSkullRenderer(@Nullable Direction direction, float yRot, float animationPos, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, SkullModelBase skullModelBase, RenderType renderType, int outlineColor, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay, @Local(argsOnly = true) boolean hasFoil) 27 | { 28 | EnchantedSkullRenderer.submitSkull(direction, yRot, animationPos, poseStack, submitNodeCollector, packedLight, skullModelBase, renderType, outlineColor, crumblingOverlay, Indicatia.CONFIG.enableEnchantedRenderingOnSkulls && hasFoil); 29 | } 30 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/Indicatia.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia; 2 | 3 | import com.stevekung.indicatia.config.IndicatiaConfig; 4 | import me.shedaniel.autoconfig.AutoConfig; 5 | import me.shedaniel.autoconfig.serializer.GsonConfigSerializer; 6 | import net.minecraft.client.KeyMapping; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.client.gui.components.ImageButton; 9 | import net.minecraft.client.gui.components.Tooltip; 10 | import net.minecraft.client.gui.components.WidgetSprites; 11 | import net.minecraft.client.gui.screens.Screen; 12 | import net.minecraft.client.gui.screens.packs.PackSelectionScreen; 13 | import net.minecraft.network.chat.Component; 14 | import net.minecraft.resources.Identifier; 15 | 16 | public class Indicatia 17 | { 18 | public static final String MOD_ID = "indicatia"; 19 | public static KeyMapping KEY_ALT_OPEN_CHAT; 20 | public static IndicatiaConfig CONFIG; 21 | 22 | private static final WidgetSprites RELOAD_BUTTON_SPRITES = new WidgetSprites(Identifier.fromNamespaceAndPath(MOD_ID, "widget/reload"), Identifier.fromNamespaceAndPath(MOD_ID, "widget/reload_highlighted")); 23 | private static final Component RELOAD_COMPONENT = Component.translatable("menu.reload_resources"); 24 | 25 | public static void initConfig() 26 | { 27 | AutoConfig.register(IndicatiaConfig.class, GsonConfigSerializer::new); 28 | Indicatia.CONFIG = AutoConfig.getConfigHolder(IndicatiaConfig.class).getConfig(); 29 | } 30 | 31 | public static boolean canAddReloadButton(Screen screen) 32 | { 33 | return Indicatia.CONFIG.enableReloadResourcesButton && screen instanceof PackSelectionScreen && screen.getTitle().equals(Component.translatable("resourcePack.title")); 34 | } 35 | 36 | public static ImageButton getReloadResourcesButton(Screen screen, Minecraft minecraft) 37 | { 38 | var imageButton = new ImageButton(screen.width / 2 + 155, screen.height - 26, 20, 20, RELOAD_BUTTON_SPRITES, button -> minecraft.reloadResourcePacks(), Indicatia.RELOAD_COMPONENT); 39 | imageButton.setTooltip(Tooltip.create(RELOAD_COMPONENT)); 40 | return imageButton; 41 | } 42 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/special/MixinPlayerHeadSpecialRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.special; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Redirect; 7 | 8 | import com.llamalad7.mixinextras.sugar.Local; 9 | import com.mojang.blaze3d.vertex.PoseStack; 10 | import com.stevekung.indicatia.EnchantedSkullRenderer; 11 | import com.stevekung.indicatia.Indicatia; 12 | 13 | import net.minecraft.client.model.object.skull.SkullModelBase; 14 | import net.minecraft.client.renderer.SubmitNodeCollector; 15 | import net.minecraft.client.renderer.feature.ModelFeatureRenderer; 16 | import net.minecraft.client.renderer.rendertype.RenderType; 17 | import net.minecraft.client.renderer.special.PlayerHeadSpecialRenderer; 18 | import net.minecraft.core.Direction; 19 | 20 | @Mixin(PlayerHeadSpecialRenderer.class) 21 | public class MixinPlayerHeadSpecialRenderer 22 | { 23 | @Redirect(method = "submit", at = @At( 24 | value = "INVOKE", 25 | target = "net/minecraft/client/renderer/blockentity/SkullBlockRenderer.submitSkull (Lnet/minecraft/core/Direction;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/client/model/object/skull/SkullModelBase;Lnet/minecraft/client/renderer/rendertype/RenderType;ILnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;)V")) 26 | private void indicatia$useCustomEnchantedSkullRenderer(@Nullable Direction direction, float yRot, float animationPos, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, SkullModelBase skullModelBase, RenderType renderType, int outlineColor, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay, @Local(argsOnly = true) boolean hasFoil) 27 | { 28 | EnchantedSkullRenderer.submitSkull(direction, yRot, animationPos, poseStack, submitNodeCollector, packedLight, skullModelBase, renderType, outlineColor, crumblingOverlay, Indicatia.CONFIG.enableEnchantedRenderingOnSkulls && hasFoil); 29 | } 30 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/entity/layers/MixinCustomHeadLayer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.entity.layers; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Redirect; 7 | 8 | import com.llamalad7.mixinextras.sugar.Local; 9 | import com.mojang.blaze3d.vertex.PoseStack; 10 | import com.stevekung.indicatia.EnchantedSkullRenderer; 11 | 12 | import net.minecraft.client.model.object.skull.SkullModelBase; 13 | import net.minecraft.client.renderer.SubmitNodeCollector; 14 | import net.minecraft.client.renderer.entity.layers.CustomHeadLayer; 15 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 16 | import net.minecraft.client.renderer.feature.ModelFeatureRenderer; 17 | import net.minecraft.client.renderer.rendertype.RenderType; 18 | import net.minecraft.core.Direction; 19 | 20 | @Mixin(CustomHeadLayer.class) 21 | public class MixinCustomHeadLayer 22 | { 23 | @Redirect(method = "submit", at = @At( 24 | value = "INVOKE", 25 | target = "net/minecraft/client/renderer/blockentity/SkullBlockRenderer.submitSkull (Lnet/minecraft/core/Direction;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/client/model/object/skull/SkullModelBase;Lnet/minecraft/client/renderer/rendertype/RenderType;ILnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;)V")) 26 | private void indicatia$useCustomEnchantedSkullRenderer(@Nullable Direction direction, float yRot, float animationPos, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int packedLight, SkullModelBase skullModelBase, RenderType renderType, int outlineColor, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay, @Local(argsOnly = true) LivingEntityRenderState livingEntityRenderState) 27 | { 28 | EnchantedSkullRenderer.submitSkull(direction, yRot, animationPos, poseStack, submitNodeCollector, packedLight, skullModelBase, renderType, outlineColor, crumblingOverlay, livingEntityRenderState.indicatia$hasFoil()); 29 | } 30 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/EnchantedBannerRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import com.mojang.blaze3d.vertex.PoseStack; 6 | import com.mojang.math.Axis; 7 | 8 | import net.minecraft.client.model.object.banner.BannerFlagModel; 9 | import net.minecraft.client.model.object.banner.BannerModel; 10 | import net.minecraft.client.renderer.SubmitNodeCollector; 11 | import net.minecraft.client.renderer.blockentity.BannerRenderer; 12 | import net.minecraft.client.renderer.feature.ModelFeatureRenderer; 13 | import net.minecraft.client.renderer.rendertype.RenderTypes; 14 | import net.minecraft.client.resources.model.MaterialSet; 15 | import net.minecraft.client.resources.model.ModelBakery; 16 | import net.minecraft.util.Unit; 17 | import net.minecraft.world.item.DyeColor; 18 | import net.minecraft.world.level.block.entity.BannerPatternLayers; 19 | 20 | public class EnchantedBannerRenderer 21 | { 22 | public static void submitEnchantedBanner(MaterialSet materialSet, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, int overlayCoords, float rotationDegrees, BannerModel bannerModel, BannerFlagModel bannerFlagModel, float phase, DyeColor dyeColor, BannerPatternLayers bannerPatternLayers, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay, int outlineColor, boolean hasFoil) 23 | { 24 | poseStack.pushPose(); 25 | poseStack.translate(0.5F, 0.0F, 0.5F); 26 | poseStack.mulPose(Axis.YP.rotationDegrees(rotationDegrees)); 27 | poseStack.scale(0.6666667F, -0.6666667F, -0.6666667F); 28 | var material = ModelBakery.BANNER_BASE; 29 | submitNodeCollector.submitModel(bannerModel, Unit.INSTANCE, poseStack, material.renderType(RenderTypes::entitySolid), lightCoords, overlayCoords, -1, materialSet.get(material), outlineColor, crumblingOverlay); 30 | 31 | if (hasFoil) 32 | { 33 | submitNodeCollector.submitModel(bannerModel, Unit.INSTANCE, poseStack, RenderTypes.entityGlint(), lightCoords, overlayCoords, -1, materialSet.get(material), outlineColor, crumblingOverlay); 34 | } 35 | 36 | BannerRenderer.submitPatterns(materialSet, poseStack, submitNodeCollector, lightCoords, overlayCoords, bannerFlagModel, phase, material, true, dyeColor, bannerPatternLayers, hasFoil, crumblingOverlay, outlineColor); 37 | poseStack.popPose(); 38 | } 39 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/special/MixinChestSpecialRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer.special; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | 7 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 8 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 9 | import com.llamalad7.mixinextras.sugar.Local; 10 | import com.mojang.blaze3d.vertex.PoseStack; 11 | import com.stevekung.indicatia.Indicatia; 12 | 13 | import net.minecraft.client.model.Model; 14 | import net.minecraft.client.renderer.SubmitNodeCollector; 15 | import net.minecraft.client.renderer.feature.ModelFeatureRenderer; 16 | import net.minecraft.client.renderer.rendertype.RenderType; 17 | import net.minecraft.client.renderer.rendertype.RenderTypes; 18 | import net.minecraft.client.renderer.special.ChestSpecialRenderer; 19 | import net.minecraft.client.renderer.texture.TextureAtlasSprite; 20 | 21 | @Mixin(ChestSpecialRenderer.class) 22 | public class MixinChestSpecialRenderer 23 | { 24 | @WrapOperation(method = "submit", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/SubmitNodeCollector.submitModel(Lnet/minecraft/client/model/Model;Ljava/lang/Object;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/rendertype/RenderType;IIILnet/minecraft/client/renderer/texture/TextureAtlasSprite;ILnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;)V")) 25 | private void indicatia$addEnchantedGlint(SubmitNodeCollector submitNodeCollector, Model model, S object, PoseStack poseStack, RenderType renderType, int lightCoords, int overlayCoords, int tintedColor, @Nullable TextureAtlasSprite textureAtlasSprite, int outlineColor, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay, Operation operation, @Local(argsOnly = true) boolean hasFoil) 26 | { 27 | operation.call(submitNodeCollector, model, object, poseStack, renderType, lightCoords, overlayCoords, tintedColor, textureAtlasSprite, outlineColor, crumblingOverlay); 28 | 29 | if (Indicatia.CONFIG.enableEnchantedRenderingOnAllBlockEntities && hasFoil) 30 | { 31 | operation.call(submitNodeCollector, model, object, poseStack, RenderTypes.entityGlint(), lightCoords, overlayCoords, tintedColor, textureAtlasSprite, outlineColor, crumblingOverlay); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /neoforge/src/main/java/com/stevekung/indicatia/neoforge/IndicatiaNeoForge.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.neoforge; 2 | 3 | import org.lwjgl.glfw.GLFW; 4 | import com.mojang.blaze3d.platform.InputConstants; 5 | import com.stevekung.indicatia.Indicatia; 6 | import com.stevekung.indicatia.config.IndicatiaConfig; 7 | import me.shedaniel.autoconfig.AutoConfig; 8 | import net.minecraft.client.KeyMapping; 9 | import net.neoforged.bus.api.SubscribeEvent; 10 | import net.neoforged.fml.ModLoadingContext; 11 | import net.neoforged.fml.common.Mod; 12 | import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; 13 | import net.neoforged.neoforge.client.event.ScreenEvent; 14 | import net.neoforged.neoforge.client.gui.IConfigScreenFactory; 15 | import net.neoforged.neoforge.client.settings.IKeyConflictContext; 16 | import net.neoforged.neoforge.client.settings.KeyConflictContext; 17 | import net.neoforged.neoforge.client.settings.KeyModifier; 18 | import net.neoforged.neoforge.common.NeoForge; 19 | 20 | @Mod(Indicatia.MOD_ID) 21 | public class IndicatiaNeoForge 22 | { 23 | static 24 | { 25 | Indicatia.KEY_ALT_OPEN_CHAT = new KeyMapping("key.alt_open_chat", new IKeyConflictContext() 26 | { 27 | @Override 28 | public boolean isActive() 29 | { 30 | return !KeyConflictContext.GUI.isActive(); 31 | } 32 | 33 | @Override 34 | public boolean conflicts(IKeyConflictContext other) 35 | { 36 | return false; 37 | } 38 | }, KeyModifier.NONE, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_ENTER, KeyMapping.Category.MULTIPLAYER); 39 | } 40 | 41 | public IndicatiaNeoForge() 42 | { 43 | ModLoadingContext.get().getActiveContainer().getEventBus().addListener(this::onRegisterKey); 44 | NeoForge.EVENT_BUS.register(this); 45 | Indicatia.initConfig(); 46 | ModLoadingContext.get().registerExtensionPoint(IConfigScreenFactory.class, () -> (mc, screen) -> AutoConfig.getConfigScreen(IndicatiaConfig.class, screen).get()); 47 | } 48 | 49 | private void onRegisterKey(RegisterKeyMappingsEvent event) 50 | { 51 | event.register(Indicatia.KEY_ALT_OPEN_CHAT); 52 | } 53 | 54 | @SubscribeEvent 55 | public void initScreen(ScreenEvent.Init.Pre event) 56 | { 57 | var screen = event.getScreen(); 58 | 59 | if (Indicatia.canAddReloadButton(screen)) 60 | { 61 | event.addListener(Indicatia.getReloadResourcesButton(screen, screen.getMinecraft())); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/MixinBedRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Unique; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | 8 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 9 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 10 | import com.mojang.blaze3d.vertex.PoseStack; 11 | import com.stevekung.indicatia.EnchantedFoilExtender; 12 | 13 | import net.minecraft.client.model.Model; 14 | import net.minecraft.client.renderer.SubmitNodeCollector; 15 | import net.minecraft.client.renderer.blockentity.BedRenderer; 16 | import net.minecraft.client.renderer.feature.ModelFeatureRenderer; 17 | import net.minecraft.client.renderer.rendertype.RenderType; 18 | import net.minecraft.client.renderer.rendertype.RenderTypes; 19 | import net.minecraft.client.renderer.texture.TextureAtlasSprite; 20 | 21 | @Mixin(BedRenderer.class) 22 | public class MixinBedRenderer implements EnchantedFoilExtender 23 | { 24 | @Unique 25 | private boolean hasFoil; 26 | 27 | @Override 28 | public void indicatia$setFoil(boolean hasFoil) 29 | { 30 | this.hasFoil = hasFoil; 31 | } 32 | 33 | @Override 34 | public boolean indicatia$hasFoil() 35 | { 36 | return this.hasFoil; 37 | } 38 | 39 | @WrapOperation(method = "submitPiece", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/SubmitNodeCollector.submitModel(Lnet/minecraft/client/model/Model;Ljava/lang/Object;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/rendertype/RenderType;IIILnet/minecraft/client/renderer/texture/TextureAtlasSprite;ILnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;)V")) 40 | private void indicatia$addEnchantedGlint(SubmitNodeCollector submitNodeCollector, Model model, S object, PoseStack poseStack, RenderType renderType, int lightCoords, int overlayCoords, int tintedColor, @Nullable TextureAtlasSprite textureAtlasSprite, int outlineColor, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay, Operation operation) 41 | { 42 | operation.call(submitNodeCollector, model, object, poseStack, renderType, lightCoords, overlayCoords, tintedColor, textureAtlasSprite, outlineColor, crumblingOverlay); 43 | 44 | if (this.hasFoil) 45 | { 46 | operation.call(submitNodeCollector, model, object, poseStack, RenderTypes.entityGlint(), lightCoords, overlayCoords, tintedColor, textureAtlasSprite, outlineColor, crumblingOverlay); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/MixinBannerRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Unique; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | 8 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 9 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 10 | import com.mojang.blaze3d.vertex.PoseStack; 11 | import com.stevekung.indicatia.EnchantedBannerRenderer; 12 | import com.stevekung.indicatia.EnchantedFoilExtender; 13 | 14 | import net.minecraft.client.model.object.banner.BannerFlagModel; 15 | import net.minecraft.client.model.object.banner.BannerModel; 16 | import net.minecraft.client.renderer.SubmitNodeCollector; 17 | import net.minecraft.client.renderer.blockentity.BannerRenderer; 18 | import net.minecraft.client.renderer.feature.ModelFeatureRenderer; 19 | import net.minecraft.client.resources.model.MaterialSet; 20 | import net.minecraft.world.item.DyeColor; 21 | import net.minecraft.world.level.block.entity.BannerPatternLayers; 22 | 23 | @Mixin(BannerRenderer.class) 24 | public class MixinBannerRenderer implements EnchantedFoilExtender 25 | { 26 | @Unique 27 | private boolean hasFoil; 28 | 29 | @Override 30 | public void indicatia$setFoil(boolean hasFoil) 31 | { 32 | this.hasFoil = hasFoil; 33 | } 34 | 35 | @Override 36 | public boolean indicatia$hasFoil() 37 | { 38 | return this.hasFoil; 39 | } 40 | 41 | @WrapOperation(method = "submitSpecial", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/blockentity/BannerRenderer.submitBanner(Lnet/minecraft/client/resources/model/MaterialSet;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;IIFLnet/minecraft/client/model/object/banner/BannerModel;Lnet/minecraft/client/model/object/banner/BannerFlagModel;FLnet/minecraft/world/item/DyeColor;Lnet/minecraft/world/level/block/entity/BannerPatternLayers;Lnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;I)V")) 42 | private void indicatia$addEnchantedGlint(MaterialSet materialSet, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, int overlayCoords, float rotationDegrees, BannerModel bannerModel, BannerFlagModel bannerFlagModel, float phase, DyeColor dyeColor, BannerPatternLayers bannerPatternLayers, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay, int outlineColor, Operation operation) 43 | { 44 | EnchantedBannerRenderer.submitEnchantedBanner(materialSet, poseStack, submitNodeCollector, lightCoords, overlayCoords, rotationDegrees, bannerModel, bannerFlagModel, phase, dyeColor, bannerPatternLayers, crumblingOverlay, outlineColor, this.hasFoil); 45 | } 46 | } -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/renderer/MixinShulkerBoxRenderer.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.renderer; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Unique; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | 8 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 9 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 10 | import com.mojang.blaze3d.vertex.PoseStack; 11 | import com.stevekung.indicatia.EnchantedFoilExtender; 12 | 13 | import net.minecraft.client.model.Model; 14 | import net.minecraft.client.renderer.SubmitNodeCollector; 15 | import net.minecraft.client.renderer.blockentity.ShulkerBoxRenderer; 16 | import net.minecraft.client.renderer.feature.ModelFeatureRenderer; 17 | import net.minecraft.client.renderer.rendertype.RenderType; 18 | import net.minecraft.client.renderer.rendertype.RenderTypes; 19 | import net.minecraft.client.renderer.texture.TextureAtlasSprite; 20 | 21 | @Mixin(ShulkerBoxRenderer.class) 22 | public class MixinShulkerBoxRenderer implements EnchantedFoilExtender 23 | { 24 | @Unique 25 | private boolean hasFoil; 26 | 27 | @Override 28 | public void indicatia$setFoil(boolean hasFoil) 29 | { 30 | this.hasFoil = hasFoil; 31 | } 32 | 33 | @Override 34 | public boolean indicatia$hasFoil() 35 | { 36 | return this.hasFoil; 37 | } 38 | 39 | @WrapOperation(method = "submit(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;IILnet/minecraft/core/Direction;FLnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;Lnet/minecraft/client/resources/model/Material;I)V", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/SubmitNodeCollector.submitModel(Lnet/minecraft/client/model/Model;Ljava/lang/Object;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/rendertype/RenderType;IIILnet/minecraft/client/renderer/texture/TextureAtlasSprite;ILnet/minecraft/client/renderer/feature/ModelFeatureRenderer$CrumblingOverlay;)V")) 40 | private void indicatia$addEnchantedGlint(SubmitNodeCollector submitNodeCollector, Model model, S object, PoseStack poseStack, RenderType renderType, int lightCoords, int overlayCoords, int tintedColor, @Nullable TextureAtlasSprite textureAtlasSprite, int outlineColor, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay, Operation operation) 41 | { 42 | operation.call(submitNodeCollector, model, object, poseStack, renderType, lightCoords, overlayCoords, tintedColor, textureAtlasSprite, outlineColor, crumblingOverlay); 43 | 44 | if (this.hasFoil) 45 | { 46 | operation.call(submitNodeCollector, model, object, poseStack, RenderTypes.entityGlint(), lightCoords, overlayCoords, tintedColor, textureAtlasSprite, outlineColor, crumblingOverlay); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | 74 | 75 | @rem Execute Gradle 76 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 77 | 78 | :end 79 | @rem End local scope for the variables with windows NT shell 80 | if %ERRORLEVEL% equ 0 goto mainEnd 81 | 82 | :fail 83 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 84 | rem the _cmd.exe /c_ return code! 85 | set EXIT_CODE=%ERRORLEVEL% 86 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 87 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 88 | exit /b %EXIT_CODE% 89 | 90 | :mainEnd 91 | if "%OS%"=="Windows_NT" endlocal 92 | 93 | :omega 94 | -------------------------------------------------------------------------------- /common/src/main/java/com/stevekung/indicatia/mixin/gui/screens/recipebook/MixinRecipeBookComponent.java: -------------------------------------------------------------------------------- 1 | package com.stevekung.indicatia.mixin.gui.screens.recipebook; 2 | 3 | import org.objectweb.asm.Opcodes; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.Unique; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 11 | import com.llamalad7.mixinextras.sugar.Local; 12 | import com.stevekung.indicatia.Indicatia; 13 | import com.stevekung.indicatia.utils.PlatformKeyInput; 14 | import net.minecraft.client.gui.components.EditBox; 15 | import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent; 16 | import net.minecraft.client.input.KeyEvent; 17 | import net.minecraft.client.input.MouseButtonEvent; 18 | 19 | @Mixin(RecipeBookComponent.class) 20 | public abstract class MixinRecipeBookComponent 21 | { 22 | @Shadow 23 | EditBox searchBox; 24 | 25 | @Shadow 26 | String lastSearch; 27 | 28 | @SuppressWarnings("SameParameterValue") 29 | @Shadow 30 | abstract void updateCollections(boolean resetPageNumber, boolean filtering); 31 | 32 | @Shadow 33 | abstract boolean isFiltering(); 34 | 35 | @Unique 36 | private static String lastSearchStatic = ""; 37 | 38 | @Inject(method = "initVisuals", at = @At(value = "INVOKE", target = "net/minecraft/client/gui/components/EditBox.setValue(Ljava/lang/String;)V", shift = At.Shift.AFTER)) 39 | private void indicatia$initStaticLastSearch(CallbackInfo info) 40 | { 41 | if (Indicatia.CONFIG.saveLastSearchInRecipeBook) 42 | { 43 | this.searchBox.setValue(lastSearchStatic); 44 | } 45 | } 46 | 47 | @Inject(method = "checkSearchStringUpdate", at = @At(value = "FIELD", target = "net/minecraft/client/gui/screens/recipebook/RecipeBookComponent.lastSearch:Ljava/lang/String;", opcode = Opcodes.PUTFIELD)) 48 | private void indicatia$staticLastSearchUpdate(CallbackInfo info, @Local String string) 49 | { 50 | if (Indicatia.CONFIG.saveLastSearchInRecipeBook) 51 | { 52 | lastSearchStatic = string; 53 | } 54 | } 55 | 56 | @ModifyExpressionValue(method = "mouseClicked", at = @At(value = "INVOKE", target = "net/minecraft/client/gui/components/EditBox.mouseClicked(Lnet/minecraft/client/input/MouseButtonEvent;Z)Z", ordinal = 0)) 57 | private boolean indicatia$rightClickClearText(boolean original, MouseButtonEvent mouseButtonEvent, boolean doubleClicked) 58 | { 59 | var inBox = mouseButtonEvent.x() >= (double) this.searchBox.getX() && mouseButtonEvent.x() < (double) (this.searchBox.getX() + this.searchBox.getWidth()) && mouseButtonEvent.y() >= (double) this.searchBox.getY() && mouseButtonEvent.y() < (double) (this.searchBox.getY() + this.searchBox.getHeight()); 60 | 61 | if (Indicatia.CONFIG.saveLastSearchInRecipeBook && !this.searchBox.getValue().isEmpty() && inBox && mouseButtonEvent.button() == 1) 62 | { 63 | this.searchBox.setValue(""); 64 | this.lastSearch = ""; 65 | lastSearchStatic = ""; 66 | this.updateCollections(false, this.isFiltering()); 67 | } 68 | return original; 69 | } 70 | 71 | @SuppressWarnings("ConstantValue") 72 | @ModifyExpressionValue(method = "keyPressed", at = @At(value = "INVOKE", target = "net/minecraft/client/KeyMapping.matches(Lnet/minecraft/client/input/KeyEvent;)Z")) 73 | private boolean indicatia$addAltChatKey(boolean original, KeyEvent keyEvent) 74 | { 75 | return original || PlatformKeyInput.isAltChatMatches(keyEvent); 76 | } 77 | } -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | 118 | 119 | # Determine the Java command to use to start the JVM. 120 | if [ -n "$JAVA_HOME" ] ; then 121 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 122 | # IBM's JDK on AIX uses strange locations for the executables 123 | JAVACMD=$JAVA_HOME/jre/sh/java 124 | else 125 | JAVACMD=$JAVA_HOME/bin/java 126 | fi 127 | if [ ! -x "$JAVACMD" ] ; then 128 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 129 | 130 | Please set the JAVA_HOME variable in your environment to match the 131 | location of your Java installation." 132 | fi 133 | else 134 | JAVACMD=java 135 | if ! command -v java >/dev/null 2>&1 136 | then 137 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 138 | 139 | Please set the JAVA_HOME variable in your environment to match the 140 | location of your Java installation." 141 | fi 142 | fi 143 | 144 | # Increase the maximum file descriptors if we can. 145 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 146 | case $MAX_FD in #( 147 | max*) 148 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 149 | # shellcheck disable=SC2039,SC3045 150 | MAX_FD=$( ulimit -H -n ) || 151 | warn "Could not query maximum file descriptor limit" 152 | esac 153 | case $MAX_FD in #( 154 | '' | soft) :;; #( 155 | *) 156 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 157 | # shellcheck disable=SC2039,SC3045 158 | ulimit -n "$MAX_FD" || 159 | warn "Could not set maximum file descriptor limit to $MAX_FD" 160 | esac 161 | fi 162 | 163 | # Collect all arguments for the java command, stacking in reverse order: 164 | # * args from the command line 165 | # * the main class name 166 | # * -classpath 167 | # * -D...appname settings 168 | # * --module-path (only if needed) 169 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 170 | 171 | # For Cygwin or MSYS, switch paths to Windows format before running java 172 | if "$cygwin" || "$msys" ; then 173 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | --------------------------------------------------------------------------------