From ca9997d3c193b84f6cf6bad1cda2c4f5f1382ee3 Mon Sep 17 00:00:00 2001 From: Cassian Date: Sun, 4 Oct 2026 14:42:50 -0400 Subject: [PATCH 1/4] port(shields): convert to multiversioned monorepo - Ports Extra Shields to multiversion, including previously unsupported NeoForge 26.3. - Moves its platform specific code to MRU, which it now depends on. - Updated maven declarationss to specify their contents to improve build times. - Code is compliant for 26.1.2, but this has been disabled as datagen cannot be shared between the two versions. Data generated files have not been commited yet. --- .gitignore | 1 + .../src/main/kotlin/imb11.mod.gradle.kts | 98 +++++++++- gradle/minecraft/26.1.2.versions.toml | 6 + gradle/minecraft/26.3.versions.toml | 6 + mru/build.fabric.gradle.kts | 2 +- .../main/java/cc/cassian/mru/Platform.java | 2 + .../mru/fabric/FabricPlatformImpl.java | 6 + .../mru/neoforge/NeoforgePlatformImpl.java | 5 + settings.gradle.kts | 3 +- shields/CHANGELOG.md | 86 +++++++++ shields/DEVELOPER_CERTIFICATE_OF_ORIGIN | 27 +++ shields/LICENSE | 13 ++ shields/README.md | 43 +++++ shields/branch.gradle.kts | 3 + shields/build.fabric.gradle.kts | 49 +++++ shields/build.neoforge.gradle.kts | 38 ++++ shields/mod.properties | 11 ++ .../main/java/dev/imb11/shields/Shields.java | 39 ++++ .../client/ExtraShieldSpecialRenderer.java | 108 +++++++++++ .../imb11/shields/client/ShieldsClient.java | 26 +++ .../dev/imb11/shields/compat/JeiCompat.java | 46 +++++ .../imb11/shields/datagen/ShieldsDatagen.java | 26 +++ .../providers/ShieldsEnchantmentProvider.java | 117 ++++++++++++ .../ShieldsEnchantmentTagProvider.java | 67 +++++++ .../providers/ShieldsItemTagProvider.java | 37 ++++ .../providers/ShieldsLangProvider.java | 62 +++++++ .../providers/ShieldsModelProvider.java | 75 ++++++++ .../providers/ShieldsRecipeProvider.java | 129 +++++++++++++ .../datagen/providers/package-info.java | 4 + .../ShieldEnchantmentLootHelper.java | 88 +++++++++ .../ShieldsEnchantmentEffects.java | 150 +++++++++++++++ .../enchantments/ShieldsEnchantmentKeys.java | 27 +++ .../imb11/shields/fabric/ShieldsFabric.java | 31 ++++ .../shields/fabric/ShieldsFabricClient.java | 15 ++ .../imb11/shields/items/ShieldCollection.java | 12 ++ .../imb11/shields/items/ShieldsItemTags.java | 15 ++ .../dev/imb11/shields/items/ShieldsItems.java | 169 +++++++++++++++++ .../items/custom/ShieldPatchKitItem.java | 85 +++++++++ .../imb11/shields/mixin/AnvilMenuMixin.java | 58 ++++++ .../imb11/shields/mixin/ItemStackMixin.java | 38 ++++ .../shields/mixin/LivingEntityMixin.java | 75 ++++++++ .../shields/neoforge/ShieldsNeoForge.java | 70 +++++++ .../neoforge/ShieldsNeoForgeClient.java | 30 +++ .../resources/META-INF/neoforge.mods.toml | 35 ++++ .../main/resources/assets/shields/.gitkeep | 0 .../main/resources/assets/shields/icon.png | Bin 0 -> 72865 bytes .../assets/shields/lang/en_us.base.json | 37 ++++ .../resources/assets/shields/lang/pt_br.json | 35 ++++ .../resources/assets/shields/lang/ru_ru.json | 174 ++++++++++++++++++ .../resources/assets/shields/lang/uk_ua.json | 34 ++++ .../shields/rrv/recipe/copper_shield.json | 6 + .../shields/rrv/recipe/diamond_shield.json | 6 + .../shields/rrv/recipe/gold_shield.json | 6 + .../shields/rrv/recipe/iron_shield.json | 6 + .../shields/rrv/recipe/netherite_shield.json | 6 + .../entity/shield/copper_shield_base.png | Bin 0 -> 737 bytes .../shield/copper_shield_base_nopattern.png | Bin 0 -> 763 bytes .../entity/shield/diamond_shield_base.png | Bin 0 -> 1102 bytes .../shield/diamond_shield_base_nopattern.png | Bin 0 -> 1144 bytes .../entity/shield/gold_shield_base.png | Bin 0 -> 1084 bytes .../shield/gold_shield_base_nopattern.png | Bin 0 -> 1093 bytes .../entity/shield/netherite_shield_base.png | Bin 0 -> 975 bytes .../netherite_shield_base_nopattern.png | Bin 0 -> 1015 bytes .../shield/plated_copper_shield_base.png | Bin 0 -> 764 bytes .../plated_copper_shield_base_nopattern.png | Bin 0 -> 1407 bytes .../shield/plated_diamond_shield_base.png | Bin 0 -> 1130 bytes .../plated_diamond_shield_base_nopattern.png | Bin 0 -> 1889 bytes .../entity/shield/plated_gold_shield_base.png | Bin 0 -> 757 bytes .../plated_gold_shield_base_nopattern.png | Bin 0 -> 1842 bytes .../shield/plated_netherite_shield_base.png | Bin 0 -> 999 bytes ...plated_netherite_shield_base_nopattern.png | Bin 0 -> 1496 bytes .../entity/shield/plated_shield_base.png | Bin 0 -> 840 bytes .../shield/plated_shield_base_nopattern.png | Bin 0 -> 1457 bytes .../textures/item/copper_shield_plating.png | Bin 0 -> 480 bytes .../textures/item/diamond_shield_plating.png | Bin 0 -> 473 bytes .../textures/item/gold_shield_plating.png | Bin 0 -> 432 bytes .../item/netherite_shield_plating.png | Bin 0 -> 442 bytes .../shields/textures/item/shield_plating.png | Bin 0 -> 406 bytes .../textures/item/shield_repair_kit.png | Bin 0 -> 479 bytes shields/src/main/resources/fabric.mod.json | 48 +++++ .../src/main/resources/shields.mixins.json | 14 ++ 81 files changed, 2393 insertions(+), 12 deletions(-) create mode 100644 shields/CHANGELOG.md create mode 100644 shields/DEVELOPER_CERTIFICATE_OF_ORIGIN create mode 100644 shields/LICENSE create mode 100644 shields/README.md create mode 100644 shields/branch.gradle.kts create mode 100644 shields/build.fabric.gradle.kts create mode 100644 shields/build.neoforge.gradle.kts create mode 100644 shields/mod.properties create mode 100644 shields/src/main/java/dev/imb11/shields/Shields.java create mode 100644 shields/src/main/java/dev/imb11/shields/client/ExtraShieldSpecialRenderer.java create mode 100644 shields/src/main/java/dev/imb11/shields/client/ShieldsClient.java create mode 100644 shields/src/main/java/dev/imb11/shields/compat/JeiCompat.java create mode 100644 shields/src/main/java/dev/imb11/shields/datagen/ShieldsDatagen.java create mode 100644 shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsEnchantmentProvider.java create mode 100644 shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsEnchantmentTagProvider.java create mode 100644 shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsItemTagProvider.java create mode 100644 shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsLangProvider.java create mode 100644 shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsModelProvider.java create mode 100644 shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsRecipeProvider.java create mode 100644 shields/src/main/java/dev/imb11/shields/datagen/providers/package-info.java create mode 100644 shields/src/main/java/dev/imb11/shields/enchantments/ShieldEnchantmentLootHelper.java create mode 100644 shields/src/main/java/dev/imb11/shields/enchantments/ShieldsEnchantmentEffects.java create mode 100644 shields/src/main/java/dev/imb11/shields/enchantments/ShieldsEnchantmentKeys.java create mode 100644 shields/src/main/java/dev/imb11/shields/fabric/ShieldsFabric.java create mode 100644 shields/src/main/java/dev/imb11/shields/fabric/ShieldsFabricClient.java create mode 100644 shields/src/main/java/dev/imb11/shields/items/ShieldCollection.java create mode 100644 shields/src/main/java/dev/imb11/shields/items/ShieldsItemTags.java create mode 100644 shields/src/main/java/dev/imb11/shields/items/ShieldsItems.java create mode 100644 shields/src/main/java/dev/imb11/shields/items/custom/ShieldPatchKitItem.java create mode 100644 shields/src/main/java/dev/imb11/shields/mixin/AnvilMenuMixin.java create mode 100644 shields/src/main/java/dev/imb11/shields/mixin/ItemStackMixin.java create mode 100644 shields/src/main/java/dev/imb11/shields/mixin/LivingEntityMixin.java create mode 100644 shields/src/main/java/dev/imb11/shields/neoforge/ShieldsNeoForge.java create mode 100644 shields/src/main/java/dev/imb11/shields/neoforge/ShieldsNeoForgeClient.java create mode 100644 shields/src/main/resources/META-INF/neoforge.mods.toml create mode 100644 shields/src/main/resources/assets/shields/.gitkeep create mode 100644 shields/src/main/resources/assets/shields/icon.png create mode 100644 shields/src/main/resources/assets/shields/lang/en_us.base.json create mode 100644 shields/src/main/resources/assets/shields/lang/pt_br.json create mode 100644 shields/src/main/resources/assets/shields/lang/ru_ru.json create mode 100644 shields/src/main/resources/assets/shields/lang/uk_ua.json create mode 100644 shields/src/main/resources/assets/shields/rrv/recipe/copper_shield.json create mode 100644 shields/src/main/resources/assets/shields/rrv/recipe/diamond_shield.json create mode 100644 shields/src/main/resources/assets/shields/rrv/recipe/gold_shield.json create mode 100644 shields/src/main/resources/assets/shields/rrv/recipe/iron_shield.json create mode 100644 shields/src/main/resources/assets/shields/rrv/recipe/netherite_shield.json create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/copper_shield_base.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/copper_shield_base_nopattern.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/diamond_shield_base.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/diamond_shield_base_nopattern.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/gold_shield_base.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/gold_shield_base_nopattern.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/netherite_shield_base.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/netherite_shield_base_nopattern.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_copper_shield_base.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_copper_shield_base_nopattern.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_diamond_shield_base.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_diamond_shield_base_nopattern.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_gold_shield_base.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_gold_shield_base_nopattern.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_netherite_shield_base.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_netherite_shield_base_nopattern.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_shield_base.png create mode 100644 shields/src/main/resources/assets/shields/textures/entity/shield/plated_shield_base_nopattern.png create mode 100644 shields/src/main/resources/assets/shields/textures/item/copper_shield_plating.png create mode 100644 shields/src/main/resources/assets/shields/textures/item/diamond_shield_plating.png create mode 100644 shields/src/main/resources/assets/shields/textures/item/gold_shield_plating.png create mode 100644 shields/src/main/resources/assets/shields/textures/item/netherite_shield_plating.png create mode 100644 shields/src/main/resources/assets/shields/textures/item/shield_plating.png create mode 100644 shields/src/main/resources/assets/shields/textures/item/shield_repair_kit.png create mode 100644 shields/src/main/resources/fabric.mod.json create mode 100644 shields/src/main/resources/shields.mixins.json diff --git a/.gitignore b/.gitignore index 8fa8401..d90f08f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ *.log .DS_Store Thumbs.db +**/.cache diff --git a/build-logic/src/main/kotlin/imb11.mod.gradle.kts b/build-logic/src/main/kotlin/imb11.mod.gradle.kts index 6a6051d..d8998f4 100644 --- a/build-logic/src/main/kotlin/imb11.mod.gradle.kts +++ b/build-logic/src/main/kotlin/imb11.mod.gradle.kts @@ -116,23 +116,101 @@ repositories { maven("https://maven.fabricmc.net/") maven("https://maven.neoforged.net/releases/") maven("https://maven.shedaniel.me/") - maven("https://maven.wispforest.io/releases/") + maven { + name = "Wisp Forest Maven" + url = uri("https://maven.wispforest.io/releases/") + content { + includeGroupAndSubgroups("io.wispforest") + } + } maven("https://api.modrinth.com/maven") { content { includeGroup("maven.modrinth") } } - maven("https://repo.sleeping.town/") - maven("https://maven.isxander.dev/releases") - maven("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") + maven { + name = "Sleeping Town Maven" + url = uri("https://repo.sleeping.town/") + content { + includeGroupAndSubgroups("folk.sisby") + includeGroupAndSubgroups("dev.emi") + } + } + maven { + name = "Xander Maven" + url = uri("https://maven.isxander.dev/releases") + content { + includeGroupAndSubgroups("dev.isxander") + includeGroupAndSubgroups("org.quiltmc.parsers") + } + } + maven { + name = "Fuzs Mod Resources" + url = uri("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") + content { + includeGroupAndSubgroups("fuzs") + } + } maven("https://maven.ladysnake.org/releases") - maven("https://mvn.devos.one/snapshots") - maven("https://mvn.devos.one/releases") + maven { + name = "Fabricators of Create (Snapshots)" + url = uri("https://mvn.devos.one/snapshots") + content { + includeGroupAndSubgroups("net.createmod") + includeGroupAndSubgroups("dev.engine-room") + includeGroupAndSubgroups("io.github.fabricators_of_create") + includeGroupAndSubgroups("com.simibubi") + } + } + maven { + name = "Fabricators of Create (Releases)" + url = uri("https://mvn.devos.one/releases") + content { + includeGroupAndSubgroups("net.createmod") + includeGroupAndSubgroups("dev.engine-room") + includeGroupAndSubgroups("io.github.fabricators_of_create") + includeGroupAndSubgroups("com.simibubi") + } + } maven("https://cursemaven.com") { content { includeGroup("curse.maven") } } - maven("https://maven.nucleoid.xyz") + maven { + name = "Nucleoid Maven" + url = uri("https://maven.nucleoid.xyz") + content { + includeGroupAndSubgroups("eu.pb4") + includeGroupAndSubgroups("xyz.nucleoid") + } + } maven("https://maven.theillusivec4.top/") - maven("https://maven.su5ed.dev/releases") + maven { + name = "Sinytra" + url = uri("https://maven.sinytra.org") + content { + includeGroupAndSubgroups("org.sinytra") + } + } maven("https://maven.terraformersmc.com/releases/") - maven("https://maven.cassian.cc/") - maven("https://maven.gegy.dev") + maven { + name = "Cassian's Maven" + url = uri("https://maven.cassian.cc") + content { + includeGroupAndSubgroups("cc.cassian") + includeGroupAndSubgroups("folk.sisby") + } + } + maven { + name = "Gegy" + url = uri("https://maven.gegy.dev/releases/") + content { + includeGroupAndSubgroups("dev.lambdaurora") + } + } + maven { + name = "Jared's maven" + url = uri("https://maven.blamejared.com/") + content { + includeGroup("mezz.jei") + includeGroup("net.mezzdev.config") + } + } } diff --git a/gradle/minecraft/26.1.2.versions.toml b/gradle/minecraft/26.1.2.versions.toml index 4db1c11..6d82c77 100644 --- a/gradle/minecraft/26.1.2.versions.toml +++ b/gradle/minecraft/26.1.2.versions.toml @@ -9,6 +9,7 @@ fabric-loader = "0.19.5" forge-config-api-port-fabric = "26.1.5" forgified-fabric-api = "0.154.0+3.2.6+26.1.2" jade-fabric = "26.1.0+fabric" +jei = "29.43.0.106" map-atlases = "6345967" mcqoy = "0.4.1+fabric-26.1" modmenu = "18.0.0-beta.1" @@ -16,6 +17,7 @@ neoforge = "26.1.2.107" ohmega-fabric = "1.5.20-mc26.1.2" ohmega-neoforge = "1.5.20-mc26.1.2" porting-lib-transfer = "2.3.9+1.20.1" +rrv = "8.10.9+26.1.2" sophisticated-backpacks-fabric = "26.1.2-3.25.55.1739" sophisticated-backpacks-neoforge = "26.1.2-3.25.55.1739" sophisticated-core-fabric = "26.1.2-1.4.45.1849" @@ -42,6 +44,8 @@ fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-l forge-config-api-port-fabric = { module = "fuzs.forgeconfigapiport:forgeconfigapiport-fabric", version.ref = "forge-config-api-port-fabric" } forgified-fabric-api = { module = "org.sinytra.forgified-fabric-api:forgified-fabric-api", version.ref = "forgified-fabric-api" } jade-fabric = { module = "maven.modrinth:jade", version.ref = "jade-fabric" } +jei-fabric = { module = "mezz.jei:jei-26.1.2-fabric", version.ref = "jei" } +jei-neoforge = { module = "mezz.jei:jei-26.1.2-neoforge", version.ref = "jei" } map-atlases = { module = "curse.maven:map-atlases-forge-519759", version.ref = "map-atlases" } mcqoy = { module = "maven.modrinth:mcqoy", version.ref = "mcqoy" } modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } @@ -49,6 +53,8 @@ neoforge = { module = "net.neoforged:neoforge", version.ref = "neoforge" } ohmega-fabric = { module = "io.github.swackyy:ohmega-fabric", version.ref = "ohmega-fabric" } ohmega-neoforge = { module = "io.github.swackyy:ohmega-neoforge", version.ref = "ohmega-neoforge" } porting-lib-transfer = { module = "io.github.fabricators_of_create.Porting-Lib:transfer", version.ref = "porting-lib-transfer" } +rrv-fabric = { module = "cc.cassian.rrv:reliable-recipe-viewer-fabric", version.ref = "rrv" } +rrv-neoforge = { module = "cc.cassian.rrv:reliable-recipe-viewer-neoforge", version.ref = "rrv" } sophisticated-backpacks-fabric = { module = "maven.modrinth:sophisticated-backpacks", version.ref = "sophisticated-backpacks-fabric" } sophisticated-backpacks-neoforge = { module = "maven.modrinth:sophisticated-backpacks", version.ref = "sophisticated-backpacks-neoforge" } sophisticated-core-fabric = { module = "maven.modrinth:sophisticated-core", version.ref = "sophisticated-core-fabric" } diff --git a/gradle/minecraft/26.3.versions.toml b/gradle/minecraft/26.3.versions.toml index 9244d7f..21c7f5f 100644 --- a/gradle/minecraft/26.3.versions.toml +++ b/gradle/minecraft/26.3.versions.toml @@ -9,6 +9,7 @@ fabric-loader = "0.19.5" forge-config-api-port-fabric = "26.2.1" forgified-fabric-api = "0.154.0+3.2.6+26.1.2" jade-fabric = "26.2.9+fabric" +jei = "31.9.0.57" map-atlases = "6345967" mcqoy = "0.4.1+fabric-26.1" modmenu = "21.0.0-alpha.1" @@ -16,6 +17,7 @@ neoforge = "26.3.0.33-beta" ohmega-fabric = "1.5.19-mc26.2" ohmega-neoforge = "1.5.21-mc26.3" porting-lib-transfer = "2.3.9+1.20.1" +rrv = "8.10.9+26.3" sophisticated-backpacks-fabric = "26.1.2-3.25.55.1739" sophisticated-backpacks-neoforge = "26.2-3.25.77.1959" sophisticated-core-fabric = "26.1.2-1.4.45.1849" @@ -42,6 +44,8 @@ fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-l forge-config-api-port-fabric = { module = "fuzs.forgeconfigapiport:forgeconfigapiport-fabric", version.ref = "forge-config-api-port-fabric" } forgified-fabric-api = { module = "org.sinytra.forgified-fabric-api:forgified-fabric-api", version.ref = "forgified-fabric-api" } jade-fabric = { module = "maven.modrinth:jade", version.ref = "jade-fabric" } +jei-fabric = { module = "mezz.jei:jei-26.3-fabric", version.ref = "jei" } +jei-neoforge = { module = "mezz.jei:jei-26.3-neoforge", version.ref = "jei" } map-atlases = { module = "curse.maven:map-atlases-forge-519759", version.ref = "map-atlases" } mcqoy = { module = "maven.modrinth:mcqoy", version.ref = "mcqoy" } modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } @@ -49,6 +53,8 @@ neoforge = { module = "net.neoforged:neoforge", version.ref = "neoforge" } ohmega-fabric = { module = "io.github.swackyy:ohmega-fabric", version.ref = "ohmega-fabric" } ohmega-neoforge = { module = "io.github.swackyy:ohmega-neoforge", version.ref = "ohmega-neoforge" } porting-lib-transfer = { module = "io.github.fabricators_of_create.Porting-Lib:transfer", version.ref = "porting-lib-transfer" } +rrv-fabric = { module = "cc.cassian.rrv:reliable-recipe-viewer-fabric", version.ref = "rrv" } +rrv-neoforge = { module = "cc.cassian.rrv:reliable-recipe-viewer-neoforge", version.ref = "rrv" } sophisticated-backpacks-fabric = { module = "maven.modrinth:sophisticated-backpacks", version.ref = "sophisticated-backpacks-fabric" } sophisticated-backpacks-neoforge = { module = "maven.modrinth:sophisticated-backpacks", version.ref = "sophisticated-backpacks-neoforge" } sophisticated-core-fabric = { module = "maven.modrinth:sophisticated-core", version.ref = "sophisticated-core-fabric" } diff --git a/mru/build.fabric.gradle.kts b/mru/build.fabric.gradle.kts index 16fa1ea..d1c1cc7 100644 --- a/mru/build.fabric.gradle.kts +++ b/mru/build.fabric.gradle.kts @@ -34,7 +34,7 @@ dependencies { runtimeOnly(mcLibrary("yacl-fabric")) runtimeOnly(mcLibrary("modmenu")) runtimeOnly(mcLibrary("mcqoy")) - runtimeOnly(mcLibrary("surveyor")) +// runtimeOnly(mcLibrary("surveyor")) } stonecutter { diff --git a/mru/src/main/java/cc/cassian/mru/Platform.java b/mru/src/main/java/cc/cassian/mru/Platform.java index bc989a7..c75ad55 100644 --- a/mru/src/main/java/cc/cassian/mru/Platform.java +++ b/mru/src/main/java/cc/cassian/mru/Platform.java @@ -26,4 +26,6 @@ public interface Platform { ArrayList getMods(); boolean isDeveloperEnvironment(); + + boolean isClient(); } diff --git a/mru/src/main/java/cc/cassian/mru/fabric/FabricPlatformImpl.java b/mru/src/main/java/cc/cassian/mru/fabric/FabricPlatformImpl.java index 5d08649..90e19f7 100644 --- a/mru/src/main/java/cc/cassian/mru/fabric/FabricPlatformImpl.java +++ b/mru/src/main/java/cc/cassian/mru/fabric/FabricPlatformImpl.java @@ -4,6 +4,7 @@ import cc.cassian.mru.client.util.Overlay; import cc.cassian.mru.Platform; +import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.resources.Identifier; @@ -42,5 +43,10 @@ public ArrayList getMods() { public boolean isDeveloperEnvironment() { return FabricLoader.getInstance().isDevelopmentEnvironment(); } + + @Override + public boolean isClient() { + return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT; + } } //?} \ No newline at end of file diff --git a/mru/src/main/java/cc/cassian/mru/neoforge/NeoforgePlatformImpl.java b/mru/src/main/java/cc/cassian/mru/neoforge/NeoforgePlatformImpl.java index 0c664ea..225151f 100644 --- a/mru/src/main/java/cc/cassian/mru/neoforge/NeoforgePlatformImpl.java +++ b/mru/src/main/java/cc/cassian/mru/neoforge/NeoforgePlatformImpl.java @@ -51,5 +51,10 @@ public boolean isDeveloperEnvironment() { ^///?} } + + @Override + public boolean isClient() { + return FMLEnvironment.getDist().isClient(); + } } *///?} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 6391b70..ccd5a10 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,7 +19,8 @@ rootProject.name = "JavaEditionMods" val modTargets = mapOf( "mru" to listOf("26.1.2", "26.3"), - "sounds" to listOf("26.1.2", "26.3") + "sounds" to listOf("26.1.2", "26.3"), + "shields" to listOf("26.3") ) dependencyResolutionManagement { diff --git a/shields/CHANGELOG.md b/shields/CHANGELOG.md new file mode 100644 index 0000000..971e462 --- /dev/null +++ b/shields/CHANGELOG.md @@ -0,0 +1,86 @@ +# Changelog + +## [1.4.2] - 2026-06-03 + +- Rendering fixes. +- Added tooltip for shield cooldowns, based on the one originally present when the mod depended on Shield Lib. +- Different shields now have different cooldowns, with plated shields now having double the cooldown of their base variant. + +## [1.4.1] - 2026-05-26 + +- NeoForge port. +- Improved compatibility with Reliable Recipe Viewer. +- Fixed crash when blocking items with Soulbound. +- Allow shields from other mods to be repaired with Patch Kits. +- General code cleanup. + +## [1.4.0] - 2026-03-24 + +- Port to 26.1 +- Dropped dependency on Shield Lib/Architectury API/MidnightLib + +## [1.3.4] - 2026-02-26 + +- Hotfixed tags not being loaded in production. + +## [1.3.3] - 2026-02-26 + +- Removed Honeycomb from Copper Shield recipe as 1.21.9+ established Copper Tools do not oxidize. +- Upgraded RRV support to 6.5.0 +- Bumped dependencies. + +## [1.3.2] - 2026-01-12 + +- Replaced recipe viewer compatibility with RRV, an updated fork of EIV with additional features. + +## [1.3.1] - 2025-12-07 + +- Fixed an issue with entrypoints on Fabric. + +## [1.3.0] - 2025-12-07 + +- Updated for Minecraft 1.21.8 +- Now supports Fabric and NeoForge thanks to Shield Lib becoming multiplatform on 1.21.8. An update to 1.21.10 will follow once Shield Lib ports. +- Now supports EIV rather than EMI, as EMI is not available on 1.21.8. + +## [1.2.5] - 2025-03-15 + +- Fixed issue with loot tables being too common. +- Reduced attack time for Evokers summoned via the evokering enchantment to make it more difficult to dodge. +- Fixed issue with missing translations for banner shields. +- Added partial EMI compatability, no default recipes yet. + +## [1.2.4] - 2025-02-04 + +- Added Ukrainian translations - thank you @StarmanMine142 +- Fixed recipe conditionals. +- Fixed issue where mod would not load on dedicated servers. + +## [1.2.3] - 2025-01-31 + +- Added various compatibility fixes for More Shield Variants. +- Added enchantment descriptions, thanks @mpustovoi! +- Added Russian translations, thanks @mpustovoi! + +## [1.2.2] - 2025-01-06 + +- Fixes anvil crafting recipe bug for diamond shields. + +## [1.2.1] - 2025-01-06 + +- Fix fabric.mod.json issue. + +## [1.2.0] - 2025-01-06 + +- Migrated to stonecutter build system. +- Fixed issue with recipes not working in certain worlds. +- Fixed issue where treasure-only enchantments were available in the enchantment table. +- Updated metadata to link to the wiki. + +## [1.1.0] - 2025-01-06 + +- Fix enchantment issues. + +## [1.0.0] - 2025-01-05 + +Initial release! Check out the mod description for more information! \ No newline at end of file diff --git a/shields/DEVELOPER_CERTIFICATE_OF_ORIGIN b/shields/DEVELOPER_CERTIFICATE_OF_ORIGIN new file mode 100644 index 0000000..763c0d2 --- /dev/null +++ b/shields/DEVELOPER_CERTIFICATE_OF_ORIGIN @@ -0,0 +1,27 @@ +Developer Certificate of Origin + +Everyone is permitted to copy and distribute verbatim copies of this document, but changing it is not allowed unless you are the owner of this project (IMB11 (Calum H.)) + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I +have the right to submit it under the "All Rights Reserved" status +of this repository and I hereby assign all rights, title, and interest +in the contribution to IMB11 (Calum H.); or + +(b) The contribution is based upon previous work that, to the best +of my knowledge, is covered under an appropriate license and I +have the right under that license to submit that work with modifications, +whether created in whole or in part by me, and I hereby assign all rights, +title, and interest in the contribution to IMB11 (Calum H.); or + +(c) The contribution was provided directly to me by some other +person who certified (a), (b), or (c) and I have not modified it, +and I hereby assign all rights, title, and interest in the contribution +to IMB11 (Calum H.). + +(d) I understand and agree that this project and the contribution +are public and that a record of the contribution (including all +personal information I submit with it, including my sign-off) is +maintained indefinitely and may be redistributed consistent with +this project's "All Rights Reserved" status. \ No newline at end of file diff --git a/shields/LICENSE b/shields/LICENSE new file mode 100644 index 0000000..e0944f6 --- /dev/null +++ b/shields/LICENSE @@ -0,0 +1,13 @@ +ALL RIGHTS RESERVED + +Copyright (c) 2024 Calum H. (IMB11) + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +All sound effects within the assets/sounds/sounds/blocks folder are obtained from Zapsplat under ZapSplat Standard License for Gold Members. diff --git a/shields/README.md b/shields/README.md new file mode 100644 index 0000000..0fa2353 --- /dev/null +++ b/shields/README.md @@ -0,0 +1,43 @@ +[![](https://cdn.imb11.dev/mineblock%20badge_64h.png)](https://discord.gg/UzHtJKqHny) [![](https://cdn.imb11.dev/modding-elite-badge.png)](https://ko-fi.com/mineblock11) + +[*A full wiki going through the features of the mod can be found here.*](https://moddedmc.wiki/en/project/extra-shields/) + +# Information + +Extra Shields is a vanilla+ expansion to shields. It adds various new shields inline with the vanilla armor system and shield plating upgrades and also includes new and improved enchantment support. + + + +Extra Shields has been carefully crafted to ensure it remains inline with vanilla progression. + +*Check out [More Shield Variants's Compatability Add-on](https://modrinth.com/mod/more-extra-shield-variants), it works well with Extra Shields.* + +## Shields & Plated Shields + +Each material in vanilla now has a shield variant! You can also plate these shields to increase the durability at the cost of a longer cooldown if you're attacked with an axe. + +![Shields and their Plating items.](https://cdn.modrinth.com/data/GPVR65Ju/images/b2bec4058b3a45a7acca7546fb1a48083add74a7.png) + +## Shield Repair Kit + +The shield repair kit can be used to quickly repair your shield whilst in combat, be careful though, as using a repair kit will **permemantly reduce the total durability of the shield it's used on.** + +## Crafting Recipes + +For more information on crafting recipes, take a look at the following wiki pages: + +- [Shields](https://moddedmc.wiki/en/project/extra-shields/docs/guides/shields) +- [Shield Platings](https://moddedmc.wiki/en/project/extra-shields/docs/guides/shield_platings) +- [Shield Repair Kit](https://moddedmc.wiki/en/project/extra-shields/docs/guides/shield_repair_kits) + +## Enchantments + +- **Bracing:** Decreases the cooldown when the shield is disabled by an axe attack. +- **Momentum:** Gives the player a brief speed boost when their shield is disabled. +- **Evokering:** Found in woodland mansions, Evokering will introduce a chance for evoker fangs to spawn underneath attackers when the player blocks an attack. +- **Launching:** Found in ominous vaults (rare loot), Launching will have a chance to launch attackers away from the player when the shield is disabled. +- **Lifebound:** Found in nether fortress bridge chests, players will have a chance to absorb health from the attacker when the player blocks an attack. + +All of these enchantments have been tested and balanced extensively, some are not compatible with others. + +For a more in depth look into enchantments and their incompatibilities, [take a look at the wiki.](https://moddedmc.wiki/en/project/extra-shields) diff --git a/shields/branch.gradle.kts b/shields/branch.gradle.kts new file mode 100644 index 0000000..f8f400d --- /dev/null +++ b/shields/branch.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("imb11.publish-mod") +} diff --git a/shields/build.fabric.gradle.kts b/shields/build.fabric.gradle.kts new file mode 100644 index 0000000..3ad7ad1 --- /dev/null +++ b/shields/build.fabric.gradle.kts @@ -0,0 +1,49 @@ +plugins { + id("imb11.fabric-mod") +} + +val mruProject = project(":mru:${project.name}") +evaluationDependsOn(mruProject.path) + +dependencies { + implementation(project(mruProject.path)) + implementation(mcLibrary("modmenu")) + implementation(mcLibrary("rrv-fabric")) + compileOnly(mcLibrary("jei-fabric")) +} + +loom { + mods { + register("mru") { + sourceSet(mruProject.extensions.getByType().getByName("main")) + } + } +} + +fabricApi { + configureDataGeneration { + outputDirectory = project.parent!!.file("src/main/generated") + addToResources = false + client = true + } +} + +loom.runs.named("datagen") { + configName = "${modMetadata.required("mod.name")} - ${project.minecraftVersion} - Fabric - Data Generation" + runDir(rootProject.file("run/${modMetadata.id}/${project.minecraftVersion}/fabric/datagen").relativeTo(project.projectDir).invariantSeparatorsPath) +} + +stonecutter { + replacements.string { + direction = true + replace("ResourceLocation", "Identifier") + } + replacements.string { + direction = true + replace("net.minecraft.Util", "net.minecraft.util.Util") + } + replacements.string { + direction = true + replace("ResourceKey::location", "ResourceKey::identifier") + } +} diff --git a/shields/build.neoforge.gradle.kts b/shields/build.neoforge.gradle.kts new file mode 100644 index 0000000..f8cf749 --- /dev/null +++ b/shields/build.neoforge.gradle.kts @@ -0,0 +1,38 @@ +plugins { + id("imb11.neoforge-mod") +} + +val mruProject = project(":mru:${project.name}") +evaluationDependsOn(mruProject.path) + +dependencies { + implementation(project(mruProject.path)) + implementation(mcLibrary("rrv-neoforge")) + compileOnly(mcLibrary("jei-neoforge")) +} + +neoForge { + interfaceInjectionData.from(mruProject.tasks.named("stonecutterGenerate").map { + mruProject.layout.buildDirectory.file("generated/stonecutter/main/resources/interfaces.json").get() + }) + mods { + register("mru") { + sourceSet(mruProject.extensions.getByType().getByName("main")) + } + } +} + +stonecutter { + replacements.string { + direction = true + replace("ResourceLocation", "Identifier") + } + replacements.string { + direction = true + replace("net.minecraft.Util", "net.minecraft.util.Util") + } + replacements.string { + direction = true + replace("ResourceKey::location", "ResourceKey::identifier") + } +} diff --git a/shields/mod.properties b/shields/mod.properties new file mode 100644 index 0000000..3e06f64 --- /dev/null +++ b/shields/mod.properties @@ -0,0 +1,11 @@ +mod.id=shields +mod.name=Shields +mod.description=A vanilla+ expansion to shields. Adds various new shields inline with the vanilla armor system and shield plating upgrades. Includes new and improved enchantment support. +mod.license=ARR +mod.version=1.4.2 +mod.group=dev.imb11.shields +mod.required=mru +publish.modrinth=GPVR65Ju +publish.curseforge=1169734 +publish.dependencies.fabric=fabric-api,yacl,mru +publish.dependencies.neoforge=yacl,mru diff --git a/shields/src/main/java/dev/imb11/shields/Shields.java b/shields/src/main/java/dev/imb11/shields/Shields.java new file mode 100644 index 0000000..a18720d --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/Shields.java @@ -0,0 +1,39 @@ +package dev.imb11.shields; + +import cc.cassian.mru.util.CommonUtils; +import dev.imb11.shields.enchantments.ShieldsEnchantmentEffects; +import net.minecraft.ChatFormatting; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Objects; + +public class Shields { + public static final Logger LOGGER = LoggerFactory.getLogger("Shields"); + public static final String MOD_ID = "shields"; + + public static Identifier of(String name) { + return CommonUtils.id(MOD_ID, name); + } + + public static void addTooltip(ItemStack itemStack, Item.TooltipContext tooltipContext, List tooltip) { + HolderLookup.Provider registries = tooltipContext.registries(); + if (itemStack.has(DataComponents.BLOCKS_ATTACKS) && registries != null) { + var blocks = Objects.requireNonNull(itemStack.get(DataComponents.BLOCKS_ATTACKS)); + tooltip.add(Component.empty()); + tooltip.add(Component.translatable("shields.attribute.axe").withStyle(ChatFormatting.GRAY)); + tooltip.add(Component.translatable("shields.attribute.seconds", ShieldsEnchantmentEffects.getModifiedCooldown(registries, itemStack, blocks.disableCooldownScale()*5)).withStyle(ChatFormatting.DARK_GREEN)); + } + } + + public static void init() { + + } +} diff --git a/shields/src/main/java/dev/imb11/shields/client/ExtraShieldSpecialRenderer.java b/shields/src/main/java/dev/imb11/shields/client/ExtraShieldSpecialRenderer.java new file mode 100644 index 0000000..57d5ed2 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/client/ExtraShieldSpecialRenderer.java @@ -0,0 +1,108 @@ +package dev.imb11.shields.client; + +import java.util.Objects; +import java.util.function.Consumer; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Transformation; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.imb11.shields.Shields; +import net.minecraft.client.model.geom.ModelLayerLocation; +import org.joml.Vector3f; +import org.joml.Vector3fc; +import org.jspecify.annotations.Nullable; + +import net.minecraft.client.model.object.equipment.ShieldModel; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.blockentity.BannerRenderer; +import net.minecraft.client.renderer.rendertype.RenderTypes; +import net.minecraft.client.renderer.special.SpecialModelRenderer; +import net.minecraft.client.resources.model.sprite.SpriteGetter; +import net.minecraft.client.resources.model.sprite.SpriteId; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponents; +import net.minecraft.resources.Identifier; +import net.minecraft.util.Unit; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BannerPatternLayers; + +public class ExtraShieldSpecialRenderer implements SpecialModelRenderer { + public static final Transformation DEFAULT_TRANSFORMATION = new Transformation(null, null, new Vector3f(1.0F, -1.0F, -1.0F), null); + + private final SpriteGetter sprites; + private final ShieldModel model; + private final SpriteId baseSprite; + private final SpriteId baseSpriteNoPattern; + + public ExtraShieldSpecialRenderer(final SpriteGetter sprites, final ShieldModel model, SpriteId baseSprite, SpriteId baseSpriteNoPattern) { + this.sprites = sprites; + this.model = model; + this.baseSprite = baseSprite; + this.baseSpriteNoPattern = baseSpriteNoPattern; + } + + @Override + public @Nullable DataComponentMap extractArgument(final ItemStack stack) { + return stack.immutableComponents(); + } + + @Override + public void submit(final @Nullable DataComponentMap components, final PoseStack poseStack, final SubmitNodeCollector submitNodeCollector, final int lightCoords, final int overlayCoords, final boolean hasFoil, final int outlineColor) { + BannerPatternLayers patterns = components != null ? components.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY) : BannerPatternLayers.EMPTY; + DyeColor baseColor = components != null ? components.get(DataComponents.BASE_COLOR) : null; + boolean hasPatterns = !patterns.layers().isEmpty() || baseColor != null; + SpriteId base = hasPatterns ? baseSprite : baseSpriteNoPattern; + //? if >=26.3 { + /*if (hasFoil && !hasPatterns) { + submitNodeCollector.submitModel(this.model, Unit.INSTANCE, poseStack, RenderTypes.entitySolidGlint(base.atlasLocation()), lightCoords, overlayCoords, -1, this.sprites.get(base), outlineColor); + } else { + submitNodeCollector.submitModel(this.model, Unit.INSTANCE, poseStack, lightCoords, overlayCoords, -1, base, this.sprites, outlineColor); + } + + if (hasPatterns) { + BannerRenderer.submitPatterns(this.sprites, poseStack, submitNodeCollector, lightCoords, overlayCoords, this.model, Unit.INSTANCE, false, (DyeColor)Objects.requireNonNullElse(baseColor, DyeColor.WHITE), patterns); + if (hasFoil) { + submitNodeCollector.order(patterns.layers().size() + 2).submitModel(this.model, Unit.INSTANCE, poseStack, RenderTypes.patternedShieldGlint(), lightCoords, overlayCoords, -1, this.sprites.get(base), 0); + } + } + *///?} else { + submitNodeCollector.submitModel(this.model, Unit.INSTANCE, poseStack, lightCoords, overlayCoords, -1, base, this.sprites, outlineColor, null); + + if (hasPatterns) { + BannerRenderer.submitPatterns(this.sprites, poseStack, submitNodeCollector, lightCoords, overlayCoords, this.model, Unit.INSTANCE, false, Objects.requireNonNullElse(baseColor, DyeColor.WHITE), patterns, null); + } + + if (hasFoil) { + submitNodeCollector.submitModel(this.model, Unit.INSTANCE, poseStack, RenderTypes.entityGlint(), lightCoords, overlayCoords, -1, this.sprites.get(base), 0, null); + } + //?} + + } + + @Override + public void getExtents(final Consumer output) { + PoseStack poseStack = new PoseStack(); + this.model.root().getExtentsForGui(poseStack, output); + } + + public record Unbaked(Identifier modelLayer, Identifier base, Identifier noPattern) implements SpecialModelRenderer.Unbaked { + public static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec((i) -> i.group( + Identifier.CODEC.fieldOf("model_layer").forGetter(Unbaked::modelLayer), + Identifier.CODEC.fieldOf("texture").forGetter(Unbaked::base), + Identifier.CODEC.fieldOf("no_pattern_texture").forGetter(Unbaked::noPattern) + ).apply(i, Unbaked::new)); + + public MapCodec type() { + return MAP_CODEC; + } + + + public @Nullable SpecialModelRenderer bake(final BakingContext context) { + return new ExtraShieldSpecialRenderer(context.sprites(), new ShieldModel(context.entityModelSet() + .bakeLayer(new ModelLayerLocation(modelLayer, "main"))), Sheets.SHIELD_MAPPER.apply(this.base), Sheets.SHIELD_MAPPER.apply(this.noPattern)); + } + } +} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/client/ShieldsClient.java b/shields/src/main/java/dev/imb11/shields/client/ShieldsClient.java new file mode 100644 index 0000000..53d222c --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/client/ShieldsClient.java @@ -0,0 +1,26 @@ +package dev.imb11.shields.client; + +//? fabric { +import net.fabricmc.fabric.api.client.rendering.v1.ModelLayerRegistry; +//?} +import dev.imb11.shields.Shields; +import net.minecraft.client.model.object.equipment.ShieldModel; +import net.minecraft.client.model.geom.ModelLayerLocation; + +import java.util.ArrayList; +import java.util.List; + +public class ShieldsClient { + + public static final List LAYERS = new ArrayList<>(); + + public static void registerDynamicShield(String id) { + ModelLayerLocation modelLayer = new ModelLayerLocation(Shields.of(id), "main"); + + LAYERS.add(modelLayer); + + //? fabric { + ModelLayerRegistry.registerModelLayer(modelLayer, ShieldModel::createLayer); + //?} + } +} diff --git a/shields/src/main/java/dev/imb11/shields/compat/JeiCompat.java b/shields/src/main/java/dev/imb11/shields/compat/JeiCompat.java new file mode 100644 index 0000000..3e04667 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/compat/JeiCompat.java @@ -0,0 +1,46 @@ +package dev.imb11.shields.compat; + +import dev.imb11.shields.Shields; +import dev.imb11.shields.items.ShieldCollection; +import dev.imb11.shields.items.ShieldsItems; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.RecipeTypes; +import mezz.jei.api.recipe.vanilla.IJeiAnvilRecipe; +import mezz.jei.api.registration.IRecipeRegistration; +import mezz.jei.library.plugins.vanilla.anvil.AnvilRecipe; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.Identifier; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +@JeiPlugin +public class JeiCompat implements IModPlugin { + @Override + public Identifier getPluginUid() { + return Identifier.fromNamespaceAndPath(Shields.MOD_ID, "jei"); + } + + @Override + public void registerRecipes(IRecipeRegistration registry) { + ArrayList recipes = new ArrayList<>(); + for (ShieldCollection itemEntry : ShieldsItems.SHIELD_COLLECTIONS.values()) { + Item shield = itemEntry.shieldItem(); + Item plating = itemEntry.plating(); + Item platedShield = itemEntry.platedShieldItem(); + recipes.add(new AnvilRecipe( + Collections.singletonList(shield.getDefaultInstance()), + Collections.singletonList(plating.getDefaultInstance()), + Collections.singletonList(platedShield.getDefaultInstance()), + BuiltInRegistries.ITEM.getKey(platedShield) + )); + + } + registry.addRecipes(RecipeTypes.ANVIL, recipes); + } +} diff --git a/shields/src/main/java/dev/imb11/shields/datagen/ShieldsDatagen.java b/shields/src/main/java/dev/imb11/shields/datagen/ShieldsDatagen.java new file mode 100644 index 0000000..1a0b991 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/datagen/ShieldsDatagen.java @@ -0,0 +1,26 @@ +//? fabric { +package dev.imb11.shields.datagen; + +import dev.imb11.shields.datagen.providers.*; +import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; +import org.jetbrains.annotations.Nullable; + +public class ShieldsDatagen implements DataGeneratorEntrypoint { + @Override + public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { + var pack = fabricDataGenerator.createPack(); + pack.addProvider(ShieldsModelProvider::new); + pack.addProvider(ShieldsItemTagProvider::new); + pack.addProvider(ShieldsEnchantmentTagProvider::new); + pack.addProvider(ShieldsEnchantmentProvider::new); + pack.addProvider(ShieldsRecipeProvider::new); + pack.addProvider(ShieldsLangProvider::new); + } + + @Override + public @Nullable String getEffectiveModId() { + return "shields"; + } +} +//?} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsEnchantmentProvider.java b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsEnchantmentProvider.java new file mode 100644 index 0000000..c86014e --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsEnchantmentProvider.java @@ -0,0 +1,117 @@ +//? fabric { +package dev.imb11.shields.datagen.providers; + +import dev.imb11.shields.enchantments.ShieldsEnchantmentKeys; +import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricDynamicRegistryProvider; +import net.fabricmc.fabric.api.resource.conditions.v1.ResourceCondition; +import net.fabricmc.fabric.api.tag.convention.v2.ConventionalItemTags; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.entity.EquipmentSlotGroup; +import net.minecraft.world.item.enchantment.Enchantment; + +import java.util.concurrent.CompletableFuture; + +public class ShieldsEnchantmentProvider extends FabricDynamicRegistryProvider { + + public ShieldsEnchantmentProvider(FabricPackOutput output, CompletableFuture registriesFuture) { + super(output, registriesFuture); + } + + @Override + protected void configure(HolderLookup.Provider provider, Entries entries) { + var enchantmentsLookup = entries.getLookup(Registries.ENCHANTMENT); + + register(entries, ShieldsEnchantmentKeys.EVOKERING, new Enchantment.Builder( + Enchantment.definition( + provider.lookupOrThrow(Registries.ITEM).getOrThrow(ConventionalItemTags.SHIELD_TOOLS), + // Weight (lowest rarity) + 1, + // Max level + 3, + // min cost for each level: 20 + (level - 1)*10 + Enchantment.dynamicCost(20, 10), + // max cost for each level: 45 + (level - 1)*15 + Enchantment.dynamicCost(45, 15), + 5, + EquipmentSlotGroup.HAND + )).exclusiveWith(enchantmentsLookup.getOrThrow(ShieldsEnchantmentTagProvider.EVOKERING_EXCLUSIVE_SET)) + ); + + register(entries, ShieldsEnchantmentKeys.LAUNCHING, new Enchantment.Builder( + Enchantment.definition( + provider.lookupOrThrow(Registries.ITEM).getOrThrow(ConventionalItemTags.SHIELD_TOOLS), + // Weight (less common) + 5, + // Max level + 3, + // min cost for each level: 10 + (level - 1)*5 + Enchantment.dynamicCost(10, 5), + // max cost for each level: 25 + (level - 1)*10 + Enchantment.dynamicCost(25, 10), + 5, + EquipmentSlotGroup.HAND + )).exclusiveWith(enchantmentsLookup.getOrThrow(ShieldsEnchantmentTagProvider.LAUNCHING_EXCLUSIVE_SET)) + ); + + register(entries, ShieldsEnchantmentKeys.LIFEBOUND, new Enchantment.Builder( + Enchantment.definition( + provider.lookupOrThrow(Registries.ITEM).getOrThrow(ConventionalItemTags.SHIELD_TOOLS), + // Weight + 3, + // Max level + 2, + // min cost for each level: 12 + (level - 1)*7 + Enchantment.dynamicCost(12, 7), + // max cost for each level: 30 + (level - 1)*10 + Enchantment.dynamicCost(30, 10), + 5, + EquipmentSlotGroup.HAND + )).exclusiveWith(enchantmentsLookup.getOrThrow(ShieldsEnchantmentTagProvider.LIFEBOUND_EXCLUSIVE_SET)) + ); + + register(entries, ShieldsEnchantmentKeys.MOMENTUM, new Enchantment.Builder( + Enchantment.definition( + provider.lookupOrThrow(Registries.ITEM).getOrThrow(ConventionalItemTags.SHIELD_TOOLS), + // Weight (common) + 12, + // Max level + 5, + // min cost for each level: 5 + (level - 1)*5 + Enchantment.dynamicCost(5, 5), + // max cost for each level: 20 + (level - 1)*8 + Enchantment.dynamicCost(20, 8), + 5, + EquipmentSlotGroup.HAND + )).exclusiveWith(enchantmentsLookup.getOrThrow(ShieldsEnchantmentTagProvider.MOMENTUM_EXCLUSIVE_SET)) + ); + + register(entries, ShieldsEnchantmentKeys.BRACING, new Enchantment.Builder( + Enchantment.definition( + provider.lookupOrThrow(Registries.ITEM).getOrThrow(ConventionalItemTags.SHIELD_TOOLS), + // Weight + 10, + // Max level + 5, + // min cost for each level: 8 + (level - 1)*6 + Enchantment.dynamicCost(8, 6), + // max cost for each level: 25 + (level - 1)*10 + Enchantment.dynamicCost(25, 10), + 5, + EquipmentSlotGroup.HAND + )).exclusiveWith(enchantmentsLookup.getOrThrow(ShieldsEnchantmentTagProvider.BRACING_EXCLUSIVE_SET)) + ); + } + + private void register(Entries entries, ResourceKey key, Enchantment.Builder builder, ResourceCondition... resourceConditions) { + entries.add(key, builder.build(key.identifier()), resourceConditions); + } + + @Override + public String getName() { + return "ExtraShields Enchantment Provider"; + } +} +//?} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsEnchantmentTagProvider.java b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsEnchantmentTagProvider.java new file mode 100644 index 0000000..ab0590c --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsEnchantmentTagProvider.java @@ -0,0 +1,67 @@ +//? fabric { +package dev.imb11.shields.datagen.providers; + +import dev.imb11.shields.enchantments.ShieldsEnchantmentKeys; +import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagsProvider; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.Identifier; +import net.minecraft.tags.EnchantmentTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.enchantment.Enchantment; + +import java.util.concurrent.CompletableFuture; + +public class ShieldsEnchantmentTagProvider extends FabricTagsProvider { + public static final TagKey EVOKERING_EXCLUSIVE_SET = TagKey.create(Registries.ENCHANTMENT, Identifier.tryParse("shields:evokering_exclusive_set")); + public static final TagKey LAUNCHING_EXCLUSIVE_SET = TagKey.create(Registries.ENCHANTMENT, Identifier.tryParse("shields:launching_exclusive_set")); + public static final TagKey LIFEBOUND_EXCLUSIVE_SET = TagKey.create(Registries.ENCHANTMENT, Identifier.tryParse("shields:lifebound_exclusive_set")); + public static final TagKey MOMENTUM_EXCLUSIVE_SET = TagKey.create(Registries.ENCHANTMENT, Identifier.tryParse("shields:momentum_exclusive_set")); + public static final TagKey BRACING_EXCLUSIVE_SET = TagKey.create(Registries.ENCHANTMENT, Identifier.tryParse("shields:bracing_exclusive_set")); + + public ShieldsEnchantmentTagProvider(FabricPackOutput output, CompletableFuture registriesFuture) { + super(output, Registries.ENCHANTMENT, registriesFuture); + } + + @Override + protected void addTags(HolderLookup.Provider provider) { + this.getOrCreateRawBuilder(EVOKERING_EXCLUSIVE_SET) + .addOptionalElement(ShieldsEnchantmentKeys.LAUNCHING.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.LIFEBOUND.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.MOMENTUM.identifier()); + + this.getOrCreateRawBuilder(LAUNCHING_EXCLUSIVE_SET) + .addOptionalElement(ShieldsEnchantmentKeys.EVOKERING.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.MOMENTUM.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.LIFEBOUND.identifier()); + + this.getOrCreateRawBuilder(LIFEBOUND_EXCLUSIVE_SET) + .addOptionalElement(ShieldsEnchantmentKeys.EVOKERING.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.LAUNCHING.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.MOMENTUM.identifier()); + + this.getOrCreateRawBuilder(MOMENTUM_EXCLUSIVE_SET) + .addOptionalElement(ShieldsEnchantmentKeys.LIFEBOUND.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.LAUNCHING.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.EVOKERING.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.BRACING.identifier()); + + this.getOrCreateRawBuilder(BRACING_EXCLUSIVE_SET) + .addOptionalElement(ShieldsEnchantmentKeys.MOMENTUM.identifier()); + + this.getOrCreateRawBuilder(EnchantmentTags.IN_ENCHANTING_TABLE) + .addOptionalElement(ShieldsEnchantmentKeys.MOMENTUM.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.BRACING.identifier()); + + this.getOrCreateRawBuilder(EnchantmentTags.TREASURE) + .addOptionalElement(ShieldsEnchantmentKeys.EVOKERING.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.LAUNCHING.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.LIFEBOUND.identifier()); + + this.getOrCreateRawBuilder(EnchantmentTags.NON_TREASURE) + .addOptionalElement(ShieldsEnchantmentKeys.MOMENTUM.identifier()) + .addOptionalElement(ShieldsEnchantmentKeys.BRACING.identifier()); + } +} +//?} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsItemTagProvider.java b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsItemTagProvider.java new file mode 100644 index 0000000..bc1c481 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsItemTagProvider.java @@ -0,0 +1,37 @@ +//? fabric { +package dev.imb11.shields.datagen.providers; + +import dev.imb11.shields.items.ShieldsItemTags; +import dev.imb11.shields.items.ShieldsItems; +import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagsProvider; +import net.fabricmc.fabric.api.tag.convention.v2.ConventionalItemTags; +import net.minecraft.core.HolderLookup; +import net.minecraft.resources.ResourceKey; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.item.Item; + +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; + +public class ShieldsItemTagProvider extends FabricTagsProvider.ItemTagsProvider { + + public ShieldsItemTagProvider(FabricPackOutput output, CompletableFuture completableFuture) { + super(output, completableFuture, null); + } + + @Override + protected void addTags(HolderLookup.Provider provider) { + ArrayList> shieldKeys = new ArrayList<>(ShieldsItems.shieldItems(false).stream().map(p->p.builtInRegistryHolder().key()).toList()); + + this.builder(ShieldsItemTags.SHIELDS) + .addAll(shieldKeys); + + this.builder(ItemTags.DURABILITY_ENCHANTABLE) + .addOptionalTag(ShieldsItemTags.SHIELDS); + + this.builder(ConventionalItemTags.SHIELD_TOOLS) + .addOptionalTag(ShieldsItemTags.SHIELDS); + } +} +//?} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsLangProvider.java b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsLangProvider.java new file mode 100644 index 0000000..adab492 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsLangProvider.java @@ -0,0 +1,62 @@ +//? fabric { +package dev.imb11.shields.datagen.providers; + +import dev.imb11.shields.Shields; +import dev.imb11.shields.items.ShieldsItemTags; +import dev.imb11.shields.items.ShieldsItems; +import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider; +import net.minecraft.core.HolderLookup; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.Item; +import org.apache.commons.lang3.text.WordUtils; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public class ShieldsLangProvider extends FabricLanguageProvider { + public ShieldsLangProvider(FabricPackOutput dataOutput, CompletableFuture registryLookup) { + super(dataOutput, registryLookup); + } + + @Override + public void generateTranslations(HolderLookup.Provider provider, TranslationBuilder translationBuilder) { + try { + Optional path = packOutput.getModContainer().findPath("assets/shields/lang/en_us.base.json"); + + if (path.isPresent()) { + translationBuilder.add(path.get()); + } else { + throw new RuntimeException("The existing language file could not be found in assets!"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + ShieldsItems.SHIELD_COLLECTIONS.forEach((s, collection) -> { + addTranslations(translationBuilder, collection.shieldItemKey()); + addTranslations(translationBuilder, collection.platedShieldItemKey()); + }); + + translationBuilder.add(ShieldsItemTags.SHIELDS, "Shields"); + } + + private void addTranslations(TranslationBuilder translationBuilder, ResourceKey itemResourceKey) { + if (itemResourceKey.identifier().getNamespace().equals(Shields.MOD_ID)) { + String shieldID = itemResourceKey.identifier().getPath(); + for (DyeColor dyeColorStringEntry : DyeColor.values()) { + String dyeID = dyeColorStringEntry.getName(); + translationBuilder.add("item.shields.%s.%s".formatted(shieldID, dyeID), toText(dyeID) + " " + toText(shieldID)); + } + } + } + + private static String toText(String shieldID) { + return WordUtils.capitalize(shieldID.replace("_", " ")); + } + +} +//?} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsModelProvider.java b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsModelProvider.java new file mode 100644 index 0000000..7459cbf --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsModelProvider.java @@ -0,0 +1,75 @@ +//? fabric { +package dev.imb11.shields.datagen.providers; + +import dev.imb11.shields.Shields; +import dev.imb11.shields.client.ExtraShieldSpecialRenderer; +import dev.imb11.shields.items.ShieldCollection; +import dev.imb11.shields.items.ShieldsItems; +import net.fabricmc.fabric.api.client.datagen.v1.provider.FabricModelProvider; +import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput; +import net.minecraft.client.data.models.BlockModelGenerators; +import net.minecraft.client.data.models.ItemModelGenerators; +import net.minecraft.client.data.models.model.*; +import net.minecraft.client.renderer.item.ItemModel; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.resources.Identifier; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.ShieldItem; + +import java.util.Map; +import java.util.Optional; + +public class ShieldsModelProvider extends FabricModelProvider { + public ShieldsModelProvider(FabricPackOutput output) { + super(output); + } + + @Override + public void generateBlockStateModels(BlockModelGenerators blockModelGenerators) { + + } + + @Override + public void generateItemModels(ItemModelGenerators itemModelGenerator) { + + + for (Map.Entry materials : ShieldsItems.SHIELD_COLLECTIONS.entrySet()) { + var collection = materials.getValue(); + + // Item models + if (collection.shieldItemKey().identifier().getNamespace().equals(Shields.MOD_ID)) { + generateShield(itemModelGenerator, collection.shieldItemKey().identifier().getPath(), collection, collection.shieldItem(), collection.shieldBaseTexture(), collection.shieldBaseNoPatternTexture()); + } + generateShield(itemModelGenerator, collection.platedShieldItemKey().identifier().getPath(), collection, collection.platedShieldItem(), collection.platedShieldBaseTexture(), collection.platedShieldBaseNoPatternTexture()); + + // Platings + itemModelGenerator.generateFlatItem(collection.plating(), ModelTemplates.FLAT_ITEM); + }; + + // Repair kit + itemModelGenerator.generateFlatItem(ShieldsItems.SHIELD_REPAIR_KIT, ModelTemplates.FLAT_ITEM); + + } + + private static void generateShield(ItemModelGenerators itemModelGenerator, String id, ShieldCollection collection, ShieldItem item, Identifier texture, Identifier noPatternTexture) { + Identifier vanillaShieldModelLocation = ModelLocationUtils.getModelLocation(Items.SHIELD); + var modelLocation = Shields.of("item/" + id); + var modelLayer = Shields.of(id); + + // Normal model + ModelTemplate shieldTemplate = new ModelTemplate(Optional.of(vanillaShieldModelLocation), Optional.empty(), TextureSlot.PARTICLE); + shieldTemplate.create(modelLocation, TextureMapping.singleSlot(TextureSlot.PARTICLE, new Material(ModelLocationUtils.getModelLocation(collection.plating()))), itemModelGenerator.modelOutput); + + // Blocking model + ModelTemplate blockingShieldTemplate = new ModelTemplate(Optional.of(vanillaShieldModelLocation.withSuffix("_blocking")), Optional.empty(), TextureSlot.PARTICLE); + blockingShieldTemplate.create(modelLocation.withSuffix("_blocking"), TextureMapping.singleSlot(TextureSlot.PARTICLE, new Material(ModelLocationUtils.getModelLocation(collection.plating()))), itemModelGenerator.modelOutput); + + // Client Items for Shields + var model = new ExtraShieldSpecialRenderer.Unbaked(modelLayer, texture, noPatternTexture); + ItemModel.Unbaked normal = ItemModelUtils.specialModel(ModelLocationUtils.getModelLocation(item), model); + ItemModel.Unbaked blocking = ItemModelUtils.specialModel(ModelLocationUtils.getModelLocation(item, "_blocking"), model); + itemModelGenerator.itemModelOutput.accept(item, ItemModelUtils.conditional(ExtraShieldSpecialRenderer.DEFAULT_TRANSFORMATION, ItemModelUtils.isUsingItem(), blocking, normal)); + } + +} +//?} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsRecipeProvider.java b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsRecipeProvider.java new file mode 100644 index 0000000..266a5d7 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/datagen/providers/ShieldsRecipeProvider.java @@ -0,0 +1,129 @@ +//? fabric { +package dev.imb11.shields.datagen.providers; + +import dev.imb11.shields.Shields; +import dev.imb11.shields.items.ShieldCollection; +import dev.imb11.shields.items.ShieldsItems; +import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.fabricmc.fabric.api.resource.conditions.v1.ResourceConditions; +import net.minecraft.advancements.Advancement; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.recipes.*; +import net.minecraft.data.worldgen.BootstrapContext; +import net.minecraft.resources.ResourceKey; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStackTemplate; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.ShieldItem; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.ShieldDecorationRecipe; + +import java.util.concurrent.CompletableFuture; + +public class ShieldsRecipeProvider extends FabricRecipeProvider { + public ShieldsRecipeProvider(FabricPackOutput output, CompletableFuture registriesFuture) { + super(output, registriesFuture); + } + + //? if >=26.3 { + /*@Override + protected RecipeProvider createRecipeProvider(HolderLookup.Provider registries, BootstrapContext> bootstrapContext, BootstrapContext bootstrapContext1) { + return new RecipeProvider(bootstrapContext, bootstrapContext1) { + *///?} else { + @Override + protected RecipeProvider createRecipeProvider(HolderLookup.Provider registryLookup, RecipeOutput recipeOutput) { + return new RecipeProvider(registryLookup, recipeOutput) { + //?} + @Override + public void buildRecipes() { + netheriteSmithing(ShieldsItems.DIAMOND.plating(), RecipeCategory.COMBAT, ShieldsItems.NETHERITE.plating()); + + SmithingTransformRecipeBuilder.smithing(Ingredient.of(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE), Ingredient.of(ShieldsItems.DIAMOND.shieldItem()), Ingredient.of(Items.NETHERITE_INGOT), RecipeCategory.COMBAT, ShieldsItems.NETHERITE.shieldItem()).unlocks("has_netherite_ingot", has(Items.NETHERITE_INGOT)) + .save(output, ShieldsItems.NETHERITE.shieldItemKey().identifier().withSuffix("_smithing").toString()); + + var conditionedRecipeOutput = withConditions(output, ResourceConditions.not(ResourceConditions.anyModsLoaded("shields-mxsv", "lolmsv"))); + + shieldPlating(Items.IRON_INGOT, ItemTags.IRON_TOOL_MATERIALS, ShieldsItems.IRON.plating()); + + shieldPlating(Items.GOLD_INGOT, ItemTags.GOLD_TOOL_MATERIALS, ShieldsItems.GOLD.plating()); + + shieldPlating(Items.DIAMOND, ItemTags.DIAMOND_TOOL_MATERIALS, ShieldsItems.DIAMOND.plating()); + + shieldPlating(Items.COPPER_INGOT, ItemTags.COPPER_TOOL_MATERIALS, ShieldsItems.COPPER.plating()); + + shield(Items.GOLD_INGOT, ItemTags.GOLD_TOOL_MATERIALS, ShieldsItems.GOLD.shieldItem(), conditionedRecipeOutput); + + shield(Items.DIAMOND, ItemTags.DIAMOND_TOOL_MATERIALS, ShieldsItems.DIAMOND.shieldItem(), conditionedRecipeOutput); + + shield(Items.COPPER_INGOT, ItemTags.COPPER_TOOL_MATERIALS, ShieldsItems.COPPER.shieldItem(), conditionedRecipeOutput); + + shaped(RecipeCategory.COMBAT, ShieldsItems.SHIELD_REPAIR_KIT, 1) + .define('i', Items.IRON_INGOT) + .define('s', Items.STICK) + .pattern(" i ") + .pattern("isi") + .pattern(" i ") + .unlockedBy(getHasName(Items.IRON_INGOT), has(Items.IRON_INGOT)) + .save(output); + + for (ShieldCollection shieldCollection : ShieldsItems.SHIELD_COLLECTIONS.values()) { + decoration(shieldCollection.shieldItem(), shieldCollection.shieldItemKey()); + decoration(shieldCollection.platedShieldItem(), shieldCollection.platedShieldItemKey()); + } + } + + private void shieldPlating(Item goldIngot, TagKey material, Item shieldItem) { + shaped(RecipeCategory.COMBAT, shieldItem, 1) + .define('p', ItemTags.PLANKS) + .define('m', material) + .pattern("mpm") + .pattern("ppp") + .pattern("mpm") + .unlockedBy(getHasName(goldIngot), has(goldIngot)) + .group("shield_platings") + .save(output); + } + + private void decoration(Item shieldItem, ResourceKey id) { + if (id.identifier().getNamespace().equals(Shields.MOD_ID)) { + SpecialRecipeBuilder.special( + () -> new ShieldDecorationRecipe(this.tag(ItemTags.BANNERS), Ingredient.of(shieldItem), new ItemStackTemplate(shieldItem)) + ) + .save(this.output, id.identifier().getPath()+"_decoration"); + } + } + + private void shield(Item material, ShieldItem shieldItem, RecipeOutput conditionedRecipeOutput) { + shaped(RecipeCategory.COMBAT, shieldItem, 1) + .define('d', material) + .define('w', ItemTags.PLANKS) + .pattern("wdw") + .pattern("www") + .pattern(" w ") + .unlockedBy(getHasName(material), has(material)) + .save(conditionedRecipeOutput); + } + + private void shield(Item material, TagKey ingredient, ShieldItem shieldItem, RecipeOutput conditionedRecipeOutput) { + shaped(RecipeCategory.COMBAT, shieldItem, 1) + .define('d', ingredient) + .define('w', ItemTags.PLANKS) + .pattern("wdw") + .pattern("www") + .pattern(" w ") + .unlockedBy(getHasName(material), has(material)) + .save(conditionedRecipeOutput); + } + }; + } + + @Override + public String getName() { + return "extrashields"; + } +} +//?} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/datagen/providers/package-info.java b/shields/src/main/java/dev/imb11/shields/datagen/providers/package-info.java new file mode 100644 index 0000000..1323328 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/datagen/providers/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package dev.imb11.shields.datagen.providers; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/enchantments/ShieldEnchantmentLootHelper.java b/shields/src/main/java/dev/imb11/shields/enchantments/ShieldEnchantmentLootHelper.java new file mode 100644 index 0000000..cce91de --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/enchantments/ShieldEnchantmentLootHelper.java @@ -0,0 +1,88 @@ +package dev.imb11.shields.enchantments; + +//? fabric +import net.fabricmc.fabric.api.loot.v3.LootTableSource; +import net.minecraft.core.HolderGetter; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.Identifier; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.storage.loot.LootPool; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.entries.*; +import net.minecraft.world.level.storage.loot.functions.EnchantRandomlyFunction; + +public class ShieldEnchantmentLootHelper { + private static final Identifier CHESTS_NETHER_BRIDGE = Identifier.withDefaultNamespace("chests/nether_bridge"); + private static final Identifier CHESTS_WOODLAND_MANSION = Identifier.withDefaultNamespace("chests/woodland_mansion"); + private static final Identifier CHESTS_OMINOUS_VAULT_RARE = Identifier.withDefaultNamespace("chests/trial_chambers/reward_ominous_rare"); + + //? if fabric { + public static void modifyLootTables(ResourceKey lootTableResourceKey, LootTable.Builder builder, LootTableSource lootTableSource, HolderLookup.Provider provider) { + var enchantmentRegistryLookup = provider.lookupOrThrow(Registries.ENCHANTMENT); + + if (lootTableSource.isBuiltin() && CHESTS_WOODLAND_MANSION.equals(lootTableResourceKey.identifier())) { + builder.modifyPools(poolBuilder -> { + poolBuilder.add(LootItem.lootTableItem(Items.BOOK) + .setWeight(6) + .apply(new EnchantRandomlyFunction.Builder().withEnchantment( + enchantmentRegistryLookup.getOrThrow(ShieldsEnchantmentKeys.EVOKERING) + ))); + }); + } + + if (lootTableSource.isBuiltin() && CHESTS_NETHER_BRIDGE.equals(lootTableResourceKey.identifier())) { + builder.modifyPools(poolBuilder -> { + poolBuilder.add(LootItem.lootTableItem(Items.BOOK) + .setWeight(5) + .apply(new EnchantRandomlyFunction.Builder().withEnchantment( + enchantmentRegistryLookup.getOrThrow(ShieldsEnchantmentKeys.LIFEBOUND) + ))); + }); + } + + if (lootTableSource.isBuiltin() && CHESTS_OMINOUS_VAULT_RARE.equals(lootTableResourceKey.identifier())) { + builder.modifyPools(poolBuilder -> { + poolBuilder.add(LootItem.lootTableItem(Items.BOOK) + .setWeight(3) + .apply(new EnchantRandomlyFunction.Builder().withEnchantment( + enchantmentRegistryLookup.getOrThrow(ShieldsEnchantmentKeys.LAUNCHING) + ))); + }); + } + } + //?} else { + + /*public static void modifyLootTables(ResourceKey lootTableResourceKey, LootTable lootTable, HolderGetter.Provider provider) { + var enchantmentRegistryLookup = provider.lookupOrThrow(Registries.ENCHANTMENT); + + if (CHESTS_WOODLAND_MANSION.equals(lootTableResourceKey.identifier())) { + lootTable.addPool(LootPool.lootPool().add(LootItem.lootTableItem(Items.BOOK) + .setWeight(6) + .apply(new EnchantRandomlyFunction.Builder().withEnchantment( + enchantmentRegistryLookup.getOrThrow(ShieldsEnchantmentKeys.EVOKERING) + ))).build() + ); + } + + if (CHESTS_NETHER_BRIDGE.equals(lootTableResourceKey.identifier())) { + lootTable.addPool(LootPool.lootPool().add(LootItem.lootTableItem(Items.BOOK) + .setWeight(5) + .apply(new EnchantRandomlyFunction.Builder().withEnchantment( + enchantmentRegistryLookup.getOrThrow(ShieldsEnchantmentKeys.LIFEBOUND) + ))).build() + ); + } + + if (CHESTS_OMINOUS_VAULT_RARE.equals(lootTableResourceKey.identifier())) { + lootTable.addPool(LootPool.lootPool().add(LootItem.lootTableItem(Items.BOOK) + .setWeight(3) + .apply(new EnchantRandomlyFunction.Builder().withEnchantment( + enchantmentRegistryLookup.getOrThrow(ShieldsEnchantmentKeys.LAUNCHING) + ))).build() + ); + } + } + *///?} +} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/enchantments/ShieldsEnchantmentEffects.java b/shields/src/main/java/dev/imb11/shields/enchantments/ShieldsEnchantmentEffects.java new file mode 100644 index 0000000..00db0f3 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/enchantments/ShieldsEnchantmentEffects.java @@ -0,0 +1,150 @@ +package dev.imb11.shields.enchantments; + +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.EvokerFangs; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +import java.util.Optional; + +public class ShieldsEnchantmentEffects { + public static void eventShieldBlock(ServerLevel serverLevel, LivingEntity livingEntity, DamageSource damageSource, ItemStack shield) { + if (shield.isEnchanted()) { + var enchantmentRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); + + // Check for our enchantments. + enchantmentRegistry.get(ShieldsEnchantmentKeys.EVOKERING).ifPresent(enchantment -> { + int evokeringLevel = EnchantmentHelper.getItemEnchantmentLevel(enchantment, shield); + if (evokeringLevel > 0 && damageSource.getEntity() instanceof LivingEntity attackerEntity) { + Handlers.handleEvokering((ServerLevel) livingEntity.level(), evokeringLevel, attackerEntity, livingEntity); + } + }); + + enchantmentRegistry.get(ShieldsEnchantmentKeys.LIFEBOUND).ifPresent(enchantment -> { + int lifeboundLevel = EnchantmentHelper.getItemEnchantmentLevel(enchantment, shield); + if (lifeboundLevel > 0 && damageSource.getEntity() instanceof LivingEntity attackerEntity) { + Handlers.handleLifebound(lifeboundLevel, (Player) livingEntity, attackerEntity); + } + }); + } + } + + public static void eventShieldDisabled(ServerLevel serverLevel, LivingEntity attacker, LivingEntity defender, ItemStack shield) { + if (shield.isEnchanted()) { + var enchantmentRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); + + Optional> launching = enchantmentRegistry.get(ShieldsEnchantmentKeys.LAUNCHING); + launching.ifPresent(enchantment -> { + int launchingLevel = EnchantmentHelper.getItemEnchantmentLevel(enchantment, shield); + if (launchingLevel > 0) { + Handlers.handleLaunching(launchingLevel, attacker, shield); + } + }); + + Optional> momentum = enchantmentRegistry.get(ShieldsEnchantmentKeys.MOMENTUM); + momentum.ifPresent(enchantment -> { + int momentumLevel = EnchantmentHelper.getItemEnchantmentLevel(enchantment, shield); + if (momentumLevel > 0) { + Handlers.handleMomentum(momentumLevel, attacker, shield); + } + }); + } + } + + public static float getModifiedCooldown(HolderLookup.Provider level, ItemStack stack, float original) { + var enchantmentLookup = level.lookupOrThrow(Registries.ENCHANTMENT); + // Check for bracing enchantment, each level decreases cooldown ticks by 10%. + if (stack != null) { + var enchantment = enchantmentLookup.get(ShieldsEnchantmentKeys.BRACING); + if (enchantment.isEmpty()) return original; + int enchantmentLevel = stack.getEnchantments().getLevel(enchantment.get()); + + if (enchantmentLevel > 0) { + return (int) (original * (1 - (0.1 * enchantmentLevel))); + } + } + + return original; + } + + public static class Handlers { + public static void handleLifebound(int enchantmentLevel, Player player, LivingEntity attacker) { + // 1/4 chance, chance increases by 5% with each level + int chance = 25 + (5 * enchantmentLevel); + if (player.level().getRandom().nextInt(100) >= chance) { + return; + } + + // 0.75 heart at lvl 1 + // 1.25 hearts at lvl 2 + float damage = 0.75f + (0.5f * (enchantmentLevel - 1)); + player.heal(damage); + + var registryLookup = player.level().registryAccess(); + var magicDamageSouce = new DamageSource(registryLookup.lookupOrThrow(Registries.DAMAGE_TYPE).getOrThrow(DamageTypes.MAGIC)); + attacker.setLastHurtByPlayer(player, 100); + attacker.hurt(magicDamageSouce, damage); + } + + public static void handleLaunching(int enchantmentLevel, LivingEntity player, ItemStack shield) { + // 20% chance of launching to actually happen, regardless of level + if (player.level().getRandom().nextInt(100) >= 20) { + return; + } + + for (int i = 0; i < enchantmentLevel + 1; i++) { + int radius = 2; + + if (enchantmentLevel == 1) { + radius = 4; + } else { + radius = 2 + (enchantmentLevel - 1); + } + + // Give all players around player resistance for 0.1s at 255 strength. + player.level().getEntities(player, player.getBoundingBox().inflate(radius), entity -> entity instanceof Player).forEach(entity -> { + ((Player) entity).addEffect(new MobEffectInstance(MobEffects.RESISTANCE, 2, 255)); + // Move them up into the air slightly as well so they get launched further. + entity.move(MoverType.SELF, new Vec3(0, 0.5, 0)); + }); + + player.level().explode(player, player.getX(), player.getY() + 0.5f, player.getZ(), 2, Level.ExplosionInteraction.NONE); + } + + // Damage the shield by 5 durability for each level + shield.hurtAndBreak(5 * enchantmentLevel, player, player.getEquipmentSlotForItem(shield)); + } + + public static void handleEvokering(ServerLevel serverLevel, int enchantmentLevel, LivingEntity attacker, LivingEntity defender) { + // 1/4 chance, chance increases by 5% with each level + int chance = 25 + (5 * enchantmentLevel); + if (serverLevel.getRandom().nextInt(100) >= chance) { + return; + } + + EvokerFangs evokerFangs = new EvokerFangs(serverLevel, attacker.getX(), attacker.getY(), attacker.getZ(), 0, -6, defender); + serverLevel.addFreshEntity(evokerFangs); + } + + public static void handleMomentum(int momentumLevel, LivingEntity player, ItemStack shield) { + // Give the player a speed III boost for 3 seconds. Each level adds 0.4s to the duration. + player.addEffect(new MobEffectInstance(MobEffects.SPEED, 60 + (8 * momentumLevel), 3, true, false)); + + // Damage the shield by 1 durability for each level + shield.hurtAndBreak(momentumLevel, player, player.getEquipmentSlotForItem(shield)); + } + } +} diff --git a/shields/src/main/java/dev/imb11/shields/enchantments/ShieldsEnchantmentKeys.java b/shields/src/main/java/dev/imb11/shields/enchantments/ShieldsEnchantmentKeys.java new file mode 100644 index 0000000..8f54647 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/enchantments/ShieldsEnchantmentKeys.java @@ -0,0 +1,27 @@ +package dev.imb11.shields.enchantments; + +import dev.imb11.shields.Shields; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.Identifier; +import net.minecraft.world.item.enchantment.Enchantment; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; + +public class ShieldsEnchantmentKeys { + @ApiStatus.Internal + public static final ArrayList> REGISTERED_ENCHANTMENTS = new ArrayList<>(); + public static final ResourceKey EVOKERING = of("evokering"); + public static final ResourceKey LAUNCHING = of("launching"); + public static final ResourceKey LIFEBOUND = of("lifebound"); + public static final ResourceKey MOMENTUM = of("momentum"); + public static final ResourceKey BRACING = of("bracing"); + + private static ResourceKey of(String path) { + Identifier id = Shields.of(path); + var key = ResourceKey.create(Registries.ENCHANTMENT, id); + REGISTERED_ENCHANTMENTS.add(key); + return key; + } +} diff --git a/shields/src/main/java/dev/imb11/shields/fabric/ShieldsFabric.java b/shields/src/main/java/dev/imb11/shields/fabric/ShieldsFabric.java new file mode 100644 index 0000000..287f95a --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/fabric/ShieldsFabric.java @@ -0,0 +1,31 @@ +package dev.imb11.shields.fabric; +//? fabric { + +import dev.imb11.shields.Shields; +import dev.imb11.shields.enchantments.ShieldEnchantmentLootHelper; +import dev.imb11.shields.enchantments.ShieldsEnchantmentEffects; +import dev.imb11.shields.items.ShieldsItems; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; +import net.fabricmc.fabric.api.loot.v3.LootTableEvents; +import net.minecraft.ChatFormatting; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +public class ShieldsFabric implements ModInitializer { + + @Override + public void onInitialize() { + Shields.init(); + ShieldsItems.initialize(); + LootTableEvents.MODIFY.register(ShieldEnchantmentLootHelper::modifyLootTables); + ItemTooltipCallback.EVENT.register((itemStack, tooltipContext, tooltipFlag, tooltip) -> { + Shields.addTooltip(itemStack, tooltipContext, tooltip); + }); + } +} +//?} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/fabric/ShieldsFabricClient.java b/shields/src/main/java/dev/imb11/shields/fabric/ShieldsFabricClient.java new file mode 100644 index 0000000..fcdadd4 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/fabric/ShieldsFabricClient.java @@ -0,0 +1,15 @@ +//? fabric { +package dev.imb11.shields.fabric; + +import dev.imb11.shields.Shields; +import dev.imb11.shields.client.ExtraShieldSpecialRenderer; +import net.fabricmc.api.ClientModInitializer; +import net.minecraft.client.renderer.special.SpecialModelRenderers; + +public class ShieldsFabricClient implements ClientModInitializer { + @Override + public void onInitializeClient() { + SpecialModelRenderers.ID_MAPPER.put(Shields.of("shields"), ExtraShieldSpecialRenderer.Unbaked.MAP_CODEC); + } +} +//?} diff --git a/shields/src/main/java/dev/imb11/shields/items/ShieldCollection.java b/shields/src/main/java/dev/imb11/shields/items/ShieldCollection.java new file mode 100644 index 0000000..9baaaea --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/items/ShieldCollection.java @@ -0,0 +1,12 @@ +package dev.imb11.shields.items; + +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ShieldItem; + +public record ShieldCollection(ShieldItem shieldItem, ShieldItem platedShieldItem, Item plating, + ResourceKey shieldItemKey, ResourceKey platedShieldItemKey, ResourceKey shieldPlatingKey, + Identifier shieldBaseTexture, Identifier shieldBaseNoPatternTexture, + Identifier platedShieldBaseTexture, Identifier platedShieldBaseNoPatternTexture) { +} diff --git a/shields/src/main/java/dev/imb11/shields/items/ShieldsItemTags.java b/shields/src/main/java/dev/imb11/shields/items/ShieldsItemTags.java new file mode 100644 index 0000000..ef40545 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/items/ShieldsItemTags.java @@ -0,0 +1,15 @@ +package dev.imb11.shields.items; + +import cc.cassian.mru.tags.CommonItemTags; +import dev.imb11.shields.Shields; +import net.minecraft.core.registries.Registries; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; + +public class ShieldsItemTags { + /// Shields from this mod. + public static TagKey SHIELDS = TagKey.create(Registries.ITEM, Shields.of("shields")); + /// Shields from any mod. + public static TagKey CONVENTIONAL_SHIELDS = CommonItemTags.SHIELD_TOOLS; + +} diff --git a/shields/src/main/java/dev/imb11/shields/items/ShieldsItems.java b/shields/src/main/java/dev/imb11/shields/items/ShieldsItems.java new file mode 100644 index 0000000..16215de --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/items/ShieldsItems.java @@ -0,0 +1,169 @@ +package dev.imb11.shields.items; + +import cc.cassian.mru.Platform; +import dev.imb11.shields.Shields; +import dev.imb11.shields.client.ShieldsClient; +import dev.imb11.shields.enchantments.ShieldsEnchantmentKeys; +import dev.imb11.shields.items.custom.ShieldPatchKitItem; +//? fabric { +import net.fabricmc.fabric.api.creativetab.v1.FabricCreativeModeTab; +//?} +import net.minecraft.core.Registry; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.Identifier; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.tags.DamageTypeTags; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.*; +import net.minecraft.world.item.component.BlocksAttacks; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import net.minecraft.world.level.block.entity.BannerPatternLayers; +import org.jetbrains.annotations.ApiStatus; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ShieldsItems { + @ApiStatus.Internal + public static final LinkedHashMap SHIELD_COLLECTIONS = new LinkedHashMap<>(); + + public static final ShieldPatchKitItem SHIELD_REPAIR_KIT = register("shield_repair_kit", (properties) -> new ShieldPatchKitItem(properties.durability(4))); + + public static final ShieldCollection IRON = createCollection("iron", (ShieldItem) Items.SHIELD, Items.SHIELD.builtInRegistryHolder().key(), 300, ItemTags.IRON_TOOL_MATERIALS, 1.0f); + public static final ShieldCollection COPPER = createCollection("copper", 240, 300, ItemTags.COPPER_TOOL_MATERIALS, 1.1f); + public static final ShieldCollection DIAMOND = createCollection("diamond", 867, 1083, ItemTags.DIAMOND_TOOL_MATERIALS, 0.75f); + public static final ShieldCollection GOLD = createCollection("gold", 451, 563, ItemTags.GOLD_TOOL_MATERIALS, 0.5f); + public static final ShieldCollection NETHERITE = createCollection("netherite", 910, 1137, ItemTags.NETHERITE_TOOL_MATERIALS, 1.1f); + + public static final ResourceKey CUSTOM_ITEM_GROUP_KEY = ResourceKey.create(Registries.CREATIVE_MODE_TAB, Identifier.fromNamespaceAndPath(Shields.MOD_ID, "item_group")); + public static final CreativeModeTab CUSTOM_ITEM_GROUP; + + static { + + CUSTOM_ITEM_GROUP = + //? fabric { + FabricCreativeModeTab.builder() + //?} else { + /*CreativeModeTab.builder() + *///?} + .icon(() -> new ItemStack(GOLD.shieldItem())) + .title(Component.translatable("itemGroup.shields.shield_group")) + .displayItems((itemDisplayParameters, output) -> { + + // Output in rows of material. + // Fill gap with enchantments. + for (ShieldCollection shieldCollection : SHIELD_COLLECTIONS.values()) { + output.accept(shieldCollection.shieldItem()); + output.accept(shieldCollection.plating()); + output.accept(shieldCollection.platedShieldItem()); + } + output.accept(SHIELD_REPAIR_KIT); + + itemDisplayParameters.holders().lookup(Registries.ENCHANTMENT).ifPresent(enchantments -> { + for (ResourceKey registeredEnchantment : ShieldsEnchantmentKeys.REGISTERED_ENCHANTMENTS) { + var reference = enchantments.get(registeredEnchantment); + if (reference.isPresent()) { + var book = EnchantmentHelper.createBook(new EnchantmentInstance(reference.get(), reference.get().value().getMaxLevel())); + output.accept(book); + } + } + }); + }) + .build(); + } + + public static void initialize() { + Shields.LOGGER.info("Initializing ShieldItems"); + + Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, CUSTOM_ITEM_GROUP_KEY, CUSTOM_ITEM_GROUP); + } + + private static ShieldCollection createCollection(String id, int durability, int platedDurability, TagKey repairIngredient, float cooldownModifier) { + var shieldKey = key(id + "_shield"); + var shield = create(shieldKey, durability, repairIngredient, cooldownModifier); + return createCollection(id, shield, shieldKey, platedDurability, repairIngredient, cooldownModifier); + } + + private static ShieldCollection createCollection(String id, ShieldItem shield, ResourceKey shieldKey, int platedDurability, TagKey repairIngredient, float cooldownModifier) { + var prefix = id; + if (id.equals("iron")) { + prefix = ""; + } + + // plated shield + var platedShieldKey = key(add("plated", prefix, "shield")); + var platedShield = create(platedShieldKey, platedDurability, repairIngredient, cooldownModifier*2); + // shield plating + var shieldPlatingKey = key(add(prefix, "shield", "plating")); + var plating = register(shieldPlatingKey, Item::new); + // textures + Identifier shieldBaseTexture = (Shields.of(add(id, "shield_base"))); + Identifier shieldBaseNoPatternTexture = (Shields.of(add(id, "shield_base_nopattern"))); + Identifier platedShieldBaseTexture = (Shields.of(add("plated", prefix, "shield_base"))); + Identifier platedShieldBaseNoPatternTexture = (Shields.of(add("plated", prefix, "shield_base_nopattern"))); + // collection + var c = new ShieldCollection(shield, platedShield, plating, shieldKey, platedShieldKey, shieldPlatingKey, shieldBaseTexture, shieldBaseNoPatternTexture, platedShieldBaseTexture, platedShieldBaseNoPatternTexture); + SHIELD_COLLECTIONS.put(id, c); + return c; + } + + private static String add(String... strings) { + return String.join("_", Arrays.stream(strings).filter(s->!s.isEmpty()).toArray(String[]::new)); + } + + private static ResourceKey key(String id) { + return ResourceKey.create(Registries.ITEM, Shields.of(id)); + } + + private static ResourceKey key(Identifier id) { + return ResourceKey.create(Registries.ITEM, id); + } + + private static ShieldItem create(ResourceKey id, int durability, TagKey repairItems, float cooldownScale) { + + var item = register(id, (settings) -> new ShieldItem(settings + .component(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY) + .enchantable(9) + .equippableUnswappable(EquipmentSlot.OFFHAND) + .delayedComponent(DataComponents.BLOCKS_ATTACKS, (context) -> new BlocksAttacks(0.25F, cooldownScale, List.of(new BlocksAttacks.DamageReduction(90.0F, Optional.empty(), 0.0F, 1.0F)), new BlocksAttacks.ItemDamageFunction(3.0F, 1.0F, 1.0F), Optional.of(context.getOrThrow(DamageTypeTags.BYPASSES_SHIELD)), Optional.of(SoundEvents.SHIELD_BLOCK), Optional.of(SoundEvents.SHIELD_BREAK))) + .component(DataComponents.BREAK_SOUND, SoundEvents.SHIELD_BREAK).durability(durability) + .durability(durability) + .repairable(repairItems) + .setId(id))); + + if (Platform.INSTANCE.isClient()) { + ShieldsClient.registerDynamicShield(id.identifier().getPath()); + } + + return item; + } + + private static T register(ResourceKey key, Function builder) { + return Registry.register(BuiltInRegistries.ITEM, key, builder.apply(new Item.Properties().setId(key))); + } + + private static T register(String id, Function builder) { + ResourceKey key = key(Identifier.fromNamespaceAndPath(Shields.MOD_ID, id)); + + return register(key, builder); + } + + public static Collection shieldItems(boolean includeVanilla) { + Collection list = new ArrayList<>(); + SHIELD_COLLECTIONS.values().forEach(c->{ + if (includeVanilla || !c.shieldItemKey().identifier().getNamespace().equals("minecraft")) + list.add(c.shieldItem()); + list.add(c.platedShieldItem()); + }); + return list; + } +} diff --git a/shields/src/main/java/dev/imb11/shields/items/custom/ShieldPatchKitItem.java b/shields/src/main/java/dev/imb11/shields/items/custom/ShieldPatchKitItem.java new file mode 100644 index 0000000..d5b2fd7 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/items/custom/ShieldPatchKitItem.java @@ -0,0 +1,85 @@ +package dev.imb11.shields.items.custom; + +import cc.cassian.mru.tags.CommonItemTags; +import dev.imb11.shields.items.ShieldsItemTags; +import net.minecraft.core.component.DataComponents; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +public class ShieldPatchKitItem extends Item { + public boolean mixin$did_flip_priorities = false; + + public ShieldPatchKitItem(Properties properties) { + super(properties); + } + + public ItemStack getResultHolderStack(Player player, InteractionHand hand) { + if (mixin$did_flip_priorities) { + mixin$did_flip_priorities = false; + InteractionHand oppositeHand = hand == InteractionHand.MAIN_HAND ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND; + return player.getItemInHand(oppositeHand); + } else { + return player.getItemInHand(hand); + } + } + + @Override + public InteractionResult use(Level level, Player player, InteractionHand usedHand) { + ItemStack repairKitStack = player.getItemInHand(usedHand); + if (!(level instanceof ServerLevel)) { + return InteractionResult.PASS; + } + + ItemStack shieldStack = canUse(player, usedHand); + + if (shieldStack != null) { + // If the shield is already at max damage, don't use the item. + if (shieldStack.getMaxDamage() == shieldStack.getDamageValue()) { + return InteractionResult.PASS; + } + + // 1 minute between uses. + player.getCooldowns().addCooldown(repairKitStack, 20 * 60); + shieldStack.set(DataComponents.MAX_DAMAGE, (int) Math.floor(shieldStack.getMaxDamage() - 0.25 * shieldStack.getMaxDamage())); + + // Repair to max durability. + shieldStack.setDamageValue(0); + + // Damage the patch kit by 1 durability. + repairKitStack.hurtAndBreak(1, player, player.getEquipmentSlotForItem(repairKitStack)); + + player.playSound(SoundEvents.UI_LOOM_TAKE_RESULT, 1.0F, 1.0F); + + return InteractionResult.SUCCESS.heldItemTransformedTo(getResultHolderStack(player, usedHand)); + } + + return InteractionResult.PASS; + } + + private static ItemStack canUse(Player player, InteractionHand usedHand) { + if (usedHand == InteractionHand.MAIN_HAND) { + // Check if shield is in off-hand, and whether shield is more than 25% damaged. + ItemStack offhandStack = player.getOffhandItem(); + if (offhandStack.is(CommonItemTags.SHIELD_TOOLS)) { + if (offhandStack.getDamageValue() > 0.25 * offhandStack.getMaxDamage()) { + return offhandStack; + } + } + } else { + // Check if shield is in main-hand, and whether shield is more than 25% damaged. + ItemStack mainhandStack = player.getMainHandItem(); + if (mainhandStack.is(CommonItemTags.SHIELD_TOOLS)) { + if (mainhandStack.getDamageValue() > 0.25 * mainhandStack.getMaxDamage()) { + return mainhandStack; + } + } + } + return null; + } +} diff --git a/shields/src/main/java/dev/imb11/shields/mixin/AnvilMenuMixin.java b/shields/src/main/java/dev/imb11/shields/mixin/AnvilMenuMixin.java new file mode 100644 index 0000000..ce9b0b9 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/mixin/AnvilMenuMixin.java @@ -0,0 +1,58 @@ +package dev.imb11.shields.mixin; + +import dev.imb11.shields.items.ShieldCollection; +import dev.imb11.shields.items.ShieldsItems; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.*; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Map; + +@Mixin(AnvilMenu.class) +public abstract class AnvilMenuMixin extends ItemCombinerMenu { + @Shadow + @Final + private DataSlot cost; + + @Shadow @Nullable private String itemName; + + public AnvilMenuMixin(@Nullable MenuType menuType, int containerId, Inventory inventory, ContainerLevelAccess access, ItemCombinerMenuSlotDefinition slotDefinition) { + super(menuType, containerId, inventory, access, slotDefinition); + } + //? fabric { + + + /** + * Credits to Infinicore's Implementation of Anvil Recipes + * for the correct mixin target. + */ + @Inject(method = "createResult", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isDamageableItem()Z", ordinal = 0), cancellable = true) + private void inject(CallbackInfo info) { + ItemStack expectedInput1 = this.inputSlots.getItem(0); + ItemStack expectedPlating = this.inputSlots.getItem(1); + + for (ShieldCollection itemEntry : ShieldsItems.SHIELD_COLLECTIONS.values()) { + var plating = itemEntry.plating(); + var input1 = itemEntry.shieldItem(); + var output = itemEntry.platedShieldItem(); + + // Check if the input items are the same as the expected items + if (expectedInput1.getItem() == input1 && expectedPlating.getItem() == plating) { + this.resultSlots.setItem(0, expectedInput1.transmuteCopy(output)); + this.itemName = expectedInput1.getHoverName().getString(); + this.cost.set(1); + info.cancel(); + return; + } + } + } + //?} +} diff --git a/shields/src/main/java/dev/imb11/shields/mixin/ItemStackMixin.java b/shields/src/main/java/dev/imb11/shields/mixin/ItemStackMixin.java new file mode 100644 index 0000000..f89c67d --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/mixin/ItemStackMixin.java @@ -0,0 +1,38 @@ +package dev.imb11.shields.mixin; + +import cc.cassian.mru.tags.CommonItemTags; +import dev.imb11.shields.items.ShieldsItemTags; +import dev.imb11.shields.items.custom.ShieldPatchKitItem; +import net.minecraft.tags.TagKey; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemInstance; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ItemStack.class) +public abstract class ItemStackMixin implements ItemInstance { + @Shadow public abstract Item getItem(); + + @Inject(method = "use", at = @At("HEAD"), cancellable = true) + public void prioritizeShieldRepairKit(Level level, Player player, InteractionHand usedHand, CallbackInfoReturnable cir) { + if (this.is(CommonItemTags.SHIELD_TOOLS)) { + // Check if alternate hand has a Shield Repair Kit + InteractionHand opposite = usedHand == InteractionHand.MAIN_HAND ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND; + ItemStack oppositeStack = player.getItemInHand(opposite); + + if (oppositeStack.getItem() instanceof ShieldPatchKitItem kitItem) { + // Swap hands + kitItem.mixin$did_flip_priorities = true; + cir.setReturnValue(kitItem.use(level, player, opposite)); + } + } + } +} diff --git a/shields/src/main/java/dev/imb11/shields/mixin/LivingEntityMixin.java b/shields/src/main/java/dev/imb11/shields/mixin/LivingEntityMixin.java new file mode 100644 index 0000000..b7ada35 --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/mixin/LivingEntityMixin.java @@ -0,0 +1,75 @@ +package dev.imb11.shields.mixin; + +import cc.cassian.mru.tags.CommonItemTags; +import dev.imb11.shields.enchantments.ShieldsEnchantmentEffects; +import dev.imb11.shields.items.ShieldsItemTags; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.BlocksAttacks; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(LivingEntity.class) +public class LivingEntityMixin { + + @Inject( + at = @At( + value = "INVOKE", + shift = At.Shift.AFTER, + target = "Lnet/minecraft/world/item/component/BlocksAttacks;resolveBlockedDamage(Lnet/minecraft/world/damagesource/DamageSource;FD)F" + ), + method = "applyItemBlocking(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;F)F" + ) + private void triggerBlockEvent(ServerLevel level, DamageSource source, float damage, CallbackInfoReturnable cir) { + LivingEntity self = (LivingEntity) (Object) this; + ShieldsEnchantmentEffects.eventShieldBlock(level, self, source, self.getItemBlockingWith()); + } + + @Inject( + at = @At("HEAD"), + method = "blockUsingItem", + cancellable = true + ) + private void triggerDisabledEvent(ServerLevel level, LivingEntity attacker, + //? if >26.2 + //DamageSource source, float damage, boolean fullyBlocked, + CallbackInfo ci) { + + LivingEntity self = (LivingEntity) (Object) this; + boolean isPlayer = self instanceof Player; + + if (isPlayer) { + + ItemStack shield = self.getItemBlockingWith(); + BlocksAttacks blocksAttacks = shield != null ? shield.get(DataComponents.BLOCKS_ATTACKS) : null; + + float secondsToDisable = attacker.getSecondsToDisableBlocking(); + + if (secondsToDisable > 0 && blocksAttacks != null) { + + ShieldsEnchantmentEffects.eventShieldDisabled(level, attacker, self, shield); + + HolderSet.Named holders = BuiltInRegistries.ITEM.get(CommonItemTags.SHIELD_TOOLS).get(); + secondsToDisable = ShieldsEnchantmentEffects.getModifiedCooldown(level.registryAccess(), shield, secondsToDisable); + + for(Holder holder : holders) { + blocksAttacks.disable(level, self, secondsToDisable, new ItemStack(holder.value())); + } + + ci.cancel(); + + } + } + } +} diff --git a/shields/src/main/java/dev/imb11/shields/neoforge/ShieldsNeoForge.java b/shields/src/main/java/dev/imb11/shields/neoforge/ShieldsNeoForge.java new file mode 100644 index 0000000..0ea08ba --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/neoforge/ShieldsNeoForge.java @@ -0,0 +1,70 @@ +//? neoforge { +/*package dev.imb11.shields.neoforge; + +import dev.imb11.shields.Shields; +import dev.imb11.shields.enchantments.ShieldEnchantmentLootHelper; +import dev.imb11.shields.items.ShieldCollection; +import dev.imb11.shields.items.ShieldsItems; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.ModList; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.neoforge.event.AnvilUpdateEvent; +import net.neoforged.neoforge.event.LootTableLoadEvent; +import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent; +import net.neoforged.neoforge.registries.RegisterEvent; + +import java.util.Map; + +@Mod(Shields.MOD_ID) +@EventBusSubscriber(modid = Shields.MOD_ID) +public class ShieldsNeoForge { + public ShieldsNeoForge(IEventBus bus) { + Shields.init(); + } + + @SubscribeEvent + public static void registerItems(RegisterEvent event) { + if (event.getRegistryKey().equals(Registries.ITEM)) { + ShieldsItems.initialize(); + } + } + + @SubscribeEvent + public static void addTooltip(ItemTooltipEvent event) { + Shields.addTooltip(event.getItemStack(), event.getContext(), event.getToolTip()); + } + + @SubscribeEvent + public static void shieldAnvilRecipes(AnvilUpdateEvent event) { + + ItemStack expectedInput1 = event.getLeft(); + ItemStack expectedPlating = event.getRight(); + + for (ShieldCollection itemEntry : ShieldsItems.SHIELD_COLLECTIONS.values()) { + var plating = itemEntry.plating(); + var input1 = itemEntry.shieldItem(); + var output = itemEntry.platedShieldItem(); + + // Check if the input items are the same as the expected items + if (expectedInput1.getItem() == input1 && expectedPlating.getItem() == plating) { + event.setOutput(expectedInput1.transmuteCopy(output)); + event.setXpCost(1); + return; + } + } + } + + @SubscribeEvent + public static void loadLootModifiers(LootTableLoadEvent event) { + ShieldEnchantmentLootHelper.modifyLootTables(event.getKey(), event.getTable(), event.getRegistries()); + } +} +*///?} \ No newline at end of file diff --git a/shields/src/main/java/dev/imb11/shields/neoforge/ShieldsNeoForgeClient.java b/shields/src/main/java/dev/imb11/shields/neoforge/ShieldsNeoForgeClient.java new file mode 100644 index 0000000..f17877c --- /dev/null +++ b/shields/src/main/java/dev/imb11/shields/neoforge/ShieldsNeoForgeClient.java @@ -0,0 +1,30 @@ +//? neoforge { +/*package dev.imb11.shields.neoforge; + +import dev.imb11.shields.Shields; +import dev.imb11.shields.client.ExtraShieldSpecialRenderer; +import dev.imb11.shields.client.ShieldsClient; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.object.equipment.ShieldModel; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.EntityRenderersEvent; +import net.neoforged.neoforge.client.event.RegisterSpecialModelRendererEvent; + +@EventBusSubscriber(modid = Shields.MOD_ID, value = Dist.CLIENT) +public class ShieldsNeoForgeClient { + + @SubscribeEvent + public static void registerSpecialModels(RegisterSpecialModelRendererEvent event) { + event.register(Shields.of("shields"), ExtraShieldSpecialRenderer.Unbaked.MAP_CODEC); + } + + @SubscribeEvent + public static void registerLayers(EntityRenderersEvent.RegisterLayerDefinitions event) { + for (ModelLayerLocation layer : ShieldsClient.LAYERS) { + event.registerLayerDefinition(layer, ShieldModel::createLayer); + } + } +} +*///?} \ No newline at end of file diff --git a/shields/src/main/resources/META-INF/neoforge.mods.toml b/shields/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..32087ea --- /dev/null +++ b/shields/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,35 @@ +modLoader = "javafml" +loaderVersion = "[2,)" +license = "All-Rights-Reserved" + +[[mods]] +modId = "shields" +displayName = "Extra Shields" +version = "${version}" +displayURL = "https://modrinth.com/mod/shields" +logoFile = "assets/shields/icon.png" +iconFile = "assets/shields/icon.png" +authors = "IMB11, cassiancc" +description = '''A vanilla+ expansion to shields. Adds various new shields inline with the vanilla armor system and shield plating upgrades. Includes new and improved enchantment support.''' + +[[mixins]] +config = "shields.mixins.json" + +[[dependencies.shields]] +modId = "neoforge" +type = "required" +versionRange = "[26,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.shields]] +modId = "minecraft" +type = "required" +versionRange = "${minecraft}" + +[[dependencies.shields]] +modId = "rrv" +type = "optional" +versionRange = "[6.5.0,)" +ordering = "NONE" +side = "BOTH" \ No newline at end of file diff --git a/shields/src/main/resources/assets/shields/.gitkeep b/shields/src/main/resources/assets/shields/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/shields/src/main/resources/assets/shields/icon.png b/shields/src/main/resources/assets/shields/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..617096ef505166f4fbb489166b9db55df743c6be GIT binary patch literal 72865 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 J3QfE4{{nMbYySWM literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/lang/en_us.base.json b/shields/src/main/resources/assets/shields/lang/en_us.base.json new file mode 100644 index 0000000..bc0f5d3 --- /dev/null +++ b/shields/src/main/resources/assets/shields/lang/en_us.base.json @@ -0,0 +1,37 @@ +{ + "item.shields.diamond_shield": "Diamond Shield", + "item.shields.plated_diamond_shield": "Plated Diamond Shield", + "item.shields.plated_shield": "Plated Shield", + "item.shields.gold_shield": "Gold Shield", + "item.shields.plated_gold_shield": "Plated Gold Shield", + "item.shields.netherite_shield": "Netherite Shield", + "item.shields.plated_netherite_shield": "Plated Netherite Shield", + "item.shields.copper_shield": "Copper Shield", + "item.shields.plated_copper_shield": "Plated Copper Shield", + + "item.shields.shield_plating": "Shield Plating", + "item.shields.gold_shield_plating": "Gold Shield Plating", + "item.shields.diamond_shield_plating": "Diamond Shield Plating", + "item.shields.netherite_shield_plating": "Netherite Shield Plating", + "item.shields.copper_shield_plating": "Copper Shield Plating", + + "item.shields.shield_repair_kit": "Shield Repair Kit", + + "enchantment.shields.launching": "Launching", + "enchantment.shields.launching.desc": "Gives a chance to launch attackers away when the shield is disabled.", + "enchantment.shields.evokering": "Evokering", + "enchantment.shields.evokering.desc": "Introduces a chance for evoker fangs to spawn underneath attackers when blocking an attack.", + "enchantment.shields.bracing": "Bracing", + "enchantment.shields.bracing.desc": "Decreases the cooldown when the shield is disabled by an axe attack.", + "enchantment.shields.lifebound": "Lifebound", + "enchantment.shields.lifebound.desc": "Gives a chance to absorb health from the attacker when blocking an attack.", + "enchantment.shields.momentum": "Momentum", + "enchantment.shields.momentum.desc": "Gives a brief speed boost when their shield is disabled.", + "enchantment.shields.momentum.tooltip_speed_for_x_seconds": "%1$ss of Speed III", + + "itemGroup.shields.shield_group": "Extra Shields", + "emi.shields.anvil": "Combine With Anvil", + "item.shields.shield_patch_kit.no_damage": "Your shield isn't damaged enough to use the repair kit!", + "shields.attribute.seconds": " %ss Cooldown", + "shields.attribute.axe": "When hit by Axe:" +} diff --git a/shields/src/main/resources/assets/shields/lang/pt_br.json b/shields/src/main/resources/assets/shields/lang/pt_br.json new file mode 100644 index 0000000..f40b20d --- /dev/null +++ b/shields/src/main/resources/assets/shields/lang/pt_br.json @@ -0,0 +1,35 @@ +{ + "item.shields.diamond_shield": "Escudo de Diamante", + "item.shields.plated_diamond_shield": "Escudo Revestido de Diamante ", + "item.shields.plated_shield": "Escudo Revestido", + "item.shields.gold_shield": "Escudo de Ouro", + "item.shields.plated_gold_shield": "Escudo Revestido de Ouro", + "item.shields.netherite_shield": "Escudo de Netherita", + "item.shields.plated_netherite_shield": "Escudo Revestido de Netherita", + "item.shields.copper_shield": "Escudo de Cobre", + "item.shields.plated_copper_shield": "Escudo Revestido de Cobre", + + "item.shields.shield_plating": "Revestimento de Escudo", + "item.shields.gold_shield_plating": "Revestimento de Escudo de Ouro", + "item.shields.diamond_shield_plating": "Revestimento de Escudo de Diamante", + "item.shields.netherite_shield_plating": "Revestimento de Escudo de Netherita", + "item.shields.copper_shield_plating": "Revestimento de Escudo de Cobre", + + "item.shields.shield_repair_kit": "Kit de Reparo de Escudo", + + "enchantment.shields.launching": "LanΓ§amento", + "enchantment.shields.launching.desc": "DΓ‘ uma chance de lanΓ§ar o atacante para longe quando o escudo estΓ‘ desativado.", + "enchantment.shields.evokering": "EvocaΓ§Γ£o", + "enchantment.shields.evokering.desc": "DΓ‘ a chance de presas do Invocador surgirem abaixo do atacante ao bloquear um ataque.", + "enchantment.shields.bracing": "ReforΓ§o", + "enchantment.shields.bracing.desc": "Reduz o tempo de recarga quando o escudo Γ© desativado por um ataque de machado.", + "enchantment.shields.lifebound": "VΓ­nculo Vital", + "enchantment.shields.lifebound.desc": "Concede uma chance de absorver saΓΊde do atacante ao bloquear um ataque.", + "enchantment.shields.momentum": "Impulso", + "enchantment.shields.momentum.desc": "Concede um breve aumento de velocidade quando o escudo Γ© desativado.", + "enchantment.shields.momentum.tooltip_speed_for_x_seconds": "%1$ss of Speed III", + + "itemGroup.shields.shield_group": "Extra Shields", + "emi.shields.anvil": "Utilize a Bigorna", + "item.shields.shield_patch_kit.no_damage": "Seu escudo nΓ£o estΓ‘ danificado o suficiente para usar o kit de reparo!" +} diff --git a/shields/src/main/resources/assets/shields/lang/ru_ru.json b/shields/src/main/resources/assets/shields/lang/ru_ru.json new file mode 100644 index 0000000..0846c93 --- /dev/null +++ b/shields/src/main/resources/assets/shields/lang/ru_ru.json @@ -0,0 +1,174 @@ +{ + "enchantment.shields.bracing": "ΠšΡ€Π΅ΠΏΠ»Π΅Π½ΠΈΠ΅", + "enchantment.shields.bracing.desc": "Π£ΠΌΠ΅Π½ΡŒΡˆΠ°Π΅Ρ‚ врСмя восстановлСния ΠΏΡ€ΠΈ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ Ρ‰ΠΈΡ‚Π° Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Π°Ρ‚Π°ΠΊΠΈ Ρ‚ΠΎΠΏΠΎΡ€ΠΎΠΌ.", + "enchantment.shields.evokering": "ЗаклятиС", + "enchantment.shields.evokering.desc": "ΠŸΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΠ΅Ρ‚ шанс появлСния ΠΊΠ»Ρ‹ΠΊΠΎΠ² заклинатСля ΠΏΠΎΠ΄ Π°Ρ‚Π°ΠΊΡƒΡŽΡ‰ΠΈΠΌΠΈ ΠΏΡ€ΠΈ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ Π°Ρ‚Π°ΠΊΠΈ.", + "enchantment.shields.launching": "ΠŸΠΎΠ΄ΠΊΠΈΠ΄Ρ‹Π²Π°Π½ΠΈΠ΅", + "enchantment.shields.launching.desc": "Π”Π°Ρ‘Ρ‚ шанс ΠΎΡ‚Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ Π°Ρ‚Π°ΠΊΡƒΡŽΡ‰ΠΈΡ…, ΠΊΠΎΠ³Π΄Π° Ρ‰ΠΈΡ‚ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½.", + "enchantment.shields.lifebound": "Π–ΠΈΠ·Π½Π΅Π³Π»ΠΎΡ‚", + "enchantment.shields.lifebound.desc": "Π”Π°Ρ‘Ρ‚ шанс ΠΏΠΎΠ³Π»ΠΎΡ‚ΠΈΡ‚ΡŒ Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΠ΅ Ρƒ Π°Ρ‚Π°ΠΊΡƒΡŽΡ‰Π΅Π³ΠΎ ΠΏΡ€ΠΈ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ Π°Ρ‚Π°ΠΊΠΈ.", + "enchantment.shields.momentum": "Π˜ΠΌΠΏΡƒΠ»ΡŒΡ", + "enchantment.shields.momentum.desc": "Π”Π°Ρ‘Ρ‚ ΠΊΡ€Π°Ρ‚ΠΊΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ прирост скорости, ΠΊΠΎΠ³Π΄Π° ΠΈΡ… Ρ‰ΠΈΡ‚ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½.", + "enchantment.shields.momentum.tooltip_speed_for_x_seconds": "Π‘ΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ III (%1$s сСк)", + "item.shields.copper_shield": "ΠœΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.black": "Π§Ρ‘Ρ€Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.blue": "Π‘ΠΈΠ½ΠΈΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.brown": "ΠšΠΎΡ€ΠΈΡ‡Π½Π΅Π²Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.cyan": "Π‘ΠΈΡ€ΡŽΠ·ΠΎΠ²Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.gray": "Π‘Π΅Ρ€Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.green": "Π—Π΅Π»Ρ‘Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.light_blue": "Π“ΠΎΠ»ΡƒΠ±ΠΎΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.light_gray": "Π‘Π²Π΅Ρ‚Π»ΠΎ-сСрый ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.lime": "Π›Π°ΠΉΠΌΠΎΠ²Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.magenta": "ΠŸΡƒΡ€ΠΏΡƒΡ€Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.orange": "ΠžΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.pink": "Π ΠΎΠ·ΠΎΠ²Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.purple": "Π€ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.red": "ΠšΡ€Π°ΡΠ½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.white": "Π‘Π΅Π»Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield.yellow": "Π–Ρ‘Π»Ρ‚Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield_plating": "МСдная латная обшивка", + "item.shields.diamond_shield": "Алмазный Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.black": "Π§Ρ‘Ρ€Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.blue": "Π‘ΠΈΠ½ΠΈΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.brown": "ΠšΠΎΡ€ΠΈΡ‡Π½Π΅Π²Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.cyan": "Π‘ΠΈΡ€ΡŽΠ·ΠΎΠ²Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.gray": "Π‘Π΅Ρ€Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.green": "Π—Π΅Π»Ρ‘Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.light_blue": "Π“ΠΎΠ»ΡƒΠ±ΠΎΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.light_gray": "Π‘Π²Π΅Ρ‚Π»ΠΎ-сСрый Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.lime": "Π›Π°ΠΉΠΌΠΎΠ²Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.magenta": "ΠŸΡƒΡ€ΠΏΡƒΡ€Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.orange": "ΠžΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.pink": "Π ΠΎΠ·ΠΎΠ²Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.purple": "Π€ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.red": "ΠšΡ€Π°ΡΠ½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.white": "Π‘Π΅Π»Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield.yellow": "Π–Ρ‘Π»Ρ‚Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.diamond_shield_plating": "Алмазная латная обшивка", + "item.shields.gold_shield": "Π—ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.black": "Π§Ρ‘Ρ€Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.blue": "Π‘ΠΈΠ½ΠΈΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.brown": "ΠšΠΎΡ€ΠΈΡ‡Π½Π΅Π²Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.cyan": "Π‘ΠΈΡ€ΡŽΠ·ΠΎΠ²Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.gray": "Π‘Π΅Ρ€Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.green": "Π—Π΅Π»Ρ‘Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.light_blue": "Π“ΠΎΠ»ΡƒΠ±ΠΎΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.light_gray": "Π‘Π²Π΅Ρ‚Π»ΠΎ-сСрый Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.lime": "Π›Π°ΠΉΠΌΠΎΠ²Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.magenta": "ΠŸΡƒΡ€ΠΏΡƒΡ€Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.orange": "ΠžΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.pink": "Π ΠΎΠ·ΠΎΠ²Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.purple": "Π€ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.red": "ΠšΡ€Π°ΡΠ½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.white": "Π‘Π΅Π»Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield.yellow": "Π–Ρ‘Π»Ρ‚Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield_plating": "Золотая латная обшивка", + "item.shields.netherite_shield": "НСзСритовый Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.black": "Π§Ρ‘Ρ€Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.blue": "Π‘ΠΈΠ½ΠΈΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.brown": "ΠšΠΎΡ€ΠΈΡ‡Π½Π΅Π²Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.cyan": "Π‘ΠΈΡ€ΡŽΠ·ΠΎΠ²Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.gray": "Π‘Π΅Ρ€Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.green": "Π—Π΅Π»Ρ‘Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.light_blue": "Π“ΠΎΠ»ΡƒΠ±ΠΎΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.light_gray": "Π‘Π²Π΅Ρ‚Π»ΠΎ-сСрый Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.lime": "Π›Π°ΠΉΠΌΠΎΠ²Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.magenta": "ΠŸΡƒΡ€ΠΏΡƒΡ€Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.orange": "ΠžΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.pink": "Π ΠΎΠ·ΠΎΠ²Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.purple": "Π€ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.red": "ΠšΡ€Π°ΡΠ½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.white": "Π‘Π΅Π»Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield.yellow": "Π–Ρ‘Π»Ρ‚Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield_plating": "НСзСритовая латная обшивка", + "item.shields.plated_copper_shield": "Π›Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.black": "Π§Ρ‘Ρ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.blue": "Π‘ΠΈΠ½ΠΈΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.brown": "ΠšΠΎΡ€ΠΈΡ‡Π½Π΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.cyan": "Π‘ΠΈΡ€ΡŽΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.gray": "Π‘Π΅Ρ€Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.green": "Π—Π΅Π»Ρ‘Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.light_blue": "Π“ΠΎΠ»ΡƒΠ±ΠΎΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.light_gray": "Π‘Π²Π΅Ρ‚Π»ΠΎ-сСрый Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.lime": "Π›Π°ΠΉΠΌΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.magenta": "ΠŸΡƒΡ€ΠΏΡƒΡ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.orange": "ΠžΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.pink": "Π ΠΎΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.purple": "Π€ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.red": "ΠšΡ€Π°ΡΠ½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.white": "Π‘Π΅Π»Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield.yellow": "Π–Ρ‘Π»Ρ‚Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π΄Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield": "Π›Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.black": "Π§Ρ‘Ρ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.blue": "Π‘ΠΈΠ½ΠΈΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.brown": "ΠšΠΎΡ€ΠΈΡ‡Π½Π΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.cyan": "Π‘ΠΈΡ€ΡŽΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.gray": "Π‘Π΅Ρ€Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.green": "Π—Π΅Π»Ρ‘Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.light_blue": "Π“ΠΎΠ»ΡƒΠ±ΠΎΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.light_gray": "Π‘Π²Π΅Ρ‚Π»ΠΎ-сСрый Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.lime": "Π›Π°ΠΉΠΌΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.magenta": "ΠŸΡƒΡ€ΠΏΡƒΡ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.orange": "ΠžΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.pink": "Π ΠΎΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.purple": "Π€ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.red": "ΠšΡ€Π°ΡΠ½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.white": "Π‘Π΅Π»Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield.yellow": "Π–Ρ‘Π»Ρ‚Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π°Π»ΠΌΠ°Π·Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield": "Π›Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.black": "Π§Ρ‘Ρ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.blue": "Π‘ΠΈΠ½ΠΈΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.brown": "ΠšΠΎΡ€ΠΈΡ‡Π½Π΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.cyan": "Π‘ΠΈΡ€ΡŽΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.gray": "Π‘Π΅Ρ€Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.green": "Π—Π΅Π»Ρ‘Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.light_blue": "Π“ΠΎΠ»ΡƒΠ±ΠΎΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.light_gray": "Π‘Π²Π΅Ρ‚Π»ΠΎ-сСрый Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.lime": "Π›Π°ΠΉΠΌΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.magenta": "ΠŸΡƒΡ€ΠΏΡƒΡ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.orange": "ΠžΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.pink": "Π ΠΎΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.purple": "Π€ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.red": "ΠšΡ€Π°ΡΠ½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.white": "Π‘Π΅Π»Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield.yellow": "Π–Ρ‘Π»Ρ‚Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield": "Π›Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.black": "Π§Ρ‘Ρ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.blue": "Π‘ΠΈΠ½ΠΈΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.brown": "ΠšΠΎΡ€ΠΈΡ‡Π½Π΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.cyan": "Π‘ΠΈΡ€ΡŽΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.gray": "Π‘Π΅Ρ€Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.green": "Π—Π΅Π»Ρ‘Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.light_blue": "Π“ΠΎΠ»ΡƒΠ±ΠΎΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.light_gray": "Π‘Π²Π΅Ρ‚Π»ΠΎ-сСрый Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.lime": "Π›Π°ΠΉΠΌΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.magenta": "ΠŸΡƒΡ€ΠΏΡƒΡ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.orange": "ΠžΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.pink": "Π ΠΎΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.purple": "Π€ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.red": "ΠšΡ€Π°ΡΠ½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.white": "Π‘Π΅Π»Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield.yellow": "Π–Ρ‘Π»Ρ‚Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠ²Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield": "Π›Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.black": "Π§Ρ‘Ρ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.blue": "Π‘ΠΈΠ½ΠΈΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.brown": "ΠšΠΎΡ€ΠΈΡ‡Π½Π΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.cyan": "Π‘ΠΈΡ€ΡŽΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.gray": "Π‘Π΅Ρ€Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.green": "Π—Π΅Π»Ρ‘Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.light_blue": "Π“ΠΎΠ»ΡƒΠ±ΠΎΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.light_gray": "Π‘Π²Π΅Ρ‚Π»ΠΎ-сСрый Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.lime": "Π›Π°ΠΉΠΌΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.magenta": "ΠŸΡƒΡ€ΠΏΡƒΡ€Π½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.orange": "ΠžΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.pink": "Π ΠΎΠ·ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.purple": "Π€ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.red": "ΠšΡ€Π°ΡΠ½Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.white": "Π‘Π΅Π»Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield.yellow": "Π–Ρ‘Π»Ρ‚Ρ‹ΠΉ Π»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‰ΠΈΡ‚", + "item.shields.shield_plating": "Латная обшивка", + "item.shields.shield_patch_kit.no_damage": "Π’Π°Ρˆ Ρ‰ΠΈΡ‚ нСдостаточно ΠΏΠΎΠ²Ρ€Π΅ΠΆΠ΄Ρ‘Π½, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅ΠΌΠΎΠ½Ρ‚Π½Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€!", + "item.shields.shield_repair_kit": "Π Π΅ΠΌΠΎΠ½Ρ‚Π½Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ для Ρ‰ΠΈΡ‚Π°", + "itemGroup.shields.shield_group": "Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Π©ΠΈΡ‚Ρ‹" +} diff --git a/shields/src/main/resources/assets/shields/lang/uk_ua.json b/shields/src/main/resources/assets/shields/lang/uk_ua.json new file mode 100644 index 0000000..245af19 --- /dev/null +++ b/shields/src/main/resources/assets/shields/lang/uk_ua.json @@ -0,0 +1,34 @@ +{ + "item.shields.diamond_shield": "Π”Ρ–Π°ΠΌΠ°Π½Ρ‚ΠΎΠ²ΠΈΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_diamond_shield": "Π£ΠΊΡ€ΠΈΡ‚ΠΈΠΉ Π΄Ρ–Π°ΠΌΠ°Π½Ρ‚ΠΎΠΌ Ρ‰ΠΈΡ‚", + "item.shields.plated_shield": "Π£ΠΊΡ€ΠΈΡ‚ΠΈΠΉ Ρ‰ΠΈΡ‚", + "item.shields.gold_shield": "Π—ΠΎΠ»ΠΎΡ‚ΠΈΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_gold_shield": "Π£ΠΊΡ€ΠΈΡ‚ΠΈΠΉ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΌ Ρ‰ΠΈΡ‚", + "item.shields.netherite_shield": "НСзСритовий Ρ‰ΠΈΡ‚", + "item.shields.plated_netherite_shield": "Π£ΠΊΡ€ΠΈΡ‚ΠΈΠΉ Π½Π΅Π·Π΅Ρ€ΠΈΡ‚ΠΎΠΌ Ρ‰ΠΈΡ‚", + "item.shields.copper_shield": "ΠœΡ–Π΄Π½ΠΈΠΉ Ρ‰ΠΈΡ‚", + "item.shields.plated_copper_shield": "Π£ΠΊΡ€ΠΈΡ‚ΠΈΠΉ ΠΌΡ–Π΄Π΄ΡŽ Ρ‰ΠΈΡ‚", + + "item.shields.shield_plating": "Укриття Ρ‰ΠΈΡ‚Π°", + "item.shields.gold_shield_plating": "Π—ΠΎΠ»ΠΎΡ‚Π΅ укриття Ρ‰ΠΈΡ‚Π°", + "item.shields.diamond_shield_plating": "Π”Ρ–Π°ΠΌΠ°Π½Ρ‚ΠΎΠ²Π΅ укриття Ρ‰ΠΈΡ‚Π°", + "item.shields.netherite_shield_plating": "НСзСритовС укриття Ρ‰ΠΈΡ‚Π°", + "item.shields.copper_shield_plating": "ΠœΡ–Π΄Π½Π΅ укрСття Ρ‰ΠΈΡ‚Π°", + + "item.shields.shield_repair_kit": "Набір лагодТСння Ρ‰ΠΈΡ‚Π°", + + "enchantment.shields.launching": "Запускач", + "enchantment.shields.launching.desc": "Π”Π°Ρ” шанс Π²Ρ–Π΄ΠΊΠΈΠ½ΡƒΡ‚ΠΈ Π½Π°ΠΏΠ°Π΄Π½ΠΈΠΊΡ–Π², ΠΊΠΎΠ»ΠΈ Ρ‰ΠΈΡ‚ Π½Π΅Π°ΠΊΡ‚ΠΈΠ²Π½ΠΈΠΉ", + "enchantment.shields.evokering": "Π—Π°ΠΊΠ»ΠΈΠ½Π°Ρ‡", + "enchantment.shields.evokering.desc": "ΠŸΡ–Π΄ час блокування Π°Ρ‚Π°ΠΊΠΈ ΠΏΡ–Π΄ Π½Π°ΠΏΠ°Π΄Π½ΠΈΠΊΠΎΠΌ Π·β€™ΡΠ²Π»ΡΡŽΡ‚ΡŒΡΡ Ρ–ΠΊΠ»Π° Π·Π°ΠΊΠ»ΠΈΠ½Π°Ρ‡Π°", + "enchantment.shields.bracing": "Антиваряг", + "enchantment.shields.bracing.desc": "Π—ΠΌΠ΅Π½ΡˆΡƒΡ” час відновлСння, нСактивности Ρ‰ΠΈΡ‚Π° Π²Ρ–Π΄ Π°Ρ‚Π°ΠΊΠΈ ΡΠΎΠΊΠΈΡ€ΠΎΡŽ", + "enchantment.shields.lifebound": "Π’Π°ΠΏΠΌΡ–Ρ€ΠΈΠ·ΠΌ", + "enchantment.shields.lifebound.desc": "Π”Π°Ρ” шанс ΠΏΠΎΠ³Π»ΠΈΠ½ΡƒΡ‚ΠΈ Π·Π΄ΠΎΡ€ΠΎΠ²'я Π½Π°ΠΏΠ°Π΄Π½ΠΈΠΊΠ° ΠΏΡ–Π΄ час блокування Π°Ρ‚Π°ΠΊΠΈ", + "enchantment.shields.momentum": "Π†ΠΌΠΏΡƒΠ»ΡŒΡ", + "enchantment.shields.momentum.desc": "Π”Π°Ρ” ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΠΉ приріст ΡˆΠ²ΠΈΠ΄ΠΊΠΎΡΡ‚ΠΈ, ΠΊΠΎΠ»ΠΈ Ρ‰ΠΈΡ‚ Π½Π΅Π°ΠΊΡ‚ΠΈΠ²Π½ΠΈΠΉ", + "enchantment.shields.momentum.tooltip_speed_for_x_seconds": "%1$s сСкунд ΡˆΠ²ΠΈΠ΄ΠΊΠΎΡΡ‚ΠΈ III", + + "itemGroup.shields.shield_group": "Extra Shields", + "item.shields.shield_patch_kit.no_damage": "Π’Π°Ρˆ Ρ‰ΠΈΡ‚ Π½Π΅Π΄ΠΎΡΡ‚Π°Ρ‚Π½ΡŒΠΎ пошкодТСний, Ρ‰ΠΎΠ± використовувати ΠΊΠΎΠΌΠΏΠ»Π΅ΠΊΡ‚!" +} diff --git a/shields/src/main/resources/assets/shields/rrv/recipe/copper_shield.json b/shields/src/main/resources/assets/shields/rrv/recipe/copper_shield.json new file mode 100644 index 0000000..149def4 --- /dev/null +++ b/shields/src/main/resources/assets/shields/rrv/recipe/copper_shield.json @@ -0,0 +1,6 @@ +{ + "type": "rrv:anvil_combining", + "left": "shields:copper_shield", + "right": "shields:copper_shield_plating", + "result": "shields:plated_copper_shield" +} \ No newline at end of file diff --git a/shields/src/main/resources/assets/shields/rrv/recipe/diamond_shield.json b/shields/src/main/resources/assets/shields/rrv/recipe/diamond_shield.json new file mode 100644 index 0000000..38f1698 --- /dev/null +++ b/shields/src/main/resources/assets/shields/rrv/recipe/diamond_shield.json @@ -0,0 +1,6 @@ +{ + "type": "rrv:anvil_combining", + "left": "shields:diamond_shield", + "right": "shields:diamond_shield_plating", + "result": "shields:plated_diamond_shield" +} \ No newline at end of file diff --git a/shields/src/main/resources/assets/shields/rrv/recipe/gold_shield.json b/shields/src/main/resources/assets/shields/rrv/recipe/gold_shield.json new file mode 100644 index 0000000..0a053fd --- /dev/null +++ b/shields/src/main/resources/assets/shields/rrv/recipe/gold_shield.json @@ -0,0 +1,6 @@ +{ + "type": "rrv:anvil_combining", + "left": "shields:gold_shield", + "right": "shields:gold_shield_plating", + "result": "shields:plated_gold_shield" +} \ No newline at end of file diff --git a/shields/src/main/resources/assets/shields/rrv/recipe/iron_shield.json b/shields/src/main/resources/assets/shields/rrv/recipe/iron_shield.json new file mode 100644 index 0000000..bf3c773 --- /dev/null +++ b/shields/src/main/resources/assets/shields/rrv/recipe/iron_shield.json @@ -0,0 +1,6 @@ +{ + "type": "rrv:anvil_combining", + "left": "minecraft:shield", + "right": "shields:shield_plating", + "result": "shields:plated_shield" +} \ No newline at end of file diff --git a/shields/src/main/resources/assets/shields/rrv/recipe/netherite_shield.json b/shields/src/main/resources/assets/shields/rrv/recipe/netherite_shield.json new file mode 100644 index 0000000..688cda6 --- /dev/null +++ b/shields/src/main/resources/assets/shields/rrv/recipe/netherite_shield.json @@ -0,0 +1,6 @@ +{ + "type": "rrv:anvil_combining", + "left": "shields:netherite_shield", + "right": "shields:netherite_shield_plating", + "result": "shields:plated_netherite_shield" +} \ No newline at end of file diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/copper_shield_base.png b/shields/src/main/resources/assets/shields/textures/entity/shield/copper_shield_base.png new file mode 100644 index 0000000000000000000000000000000000000000..1edc07f6d0bf0b65a9f7127a1601e9f34b1b8453 GIT binary patch literal 737 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e2l#}zK3Uj)u0C>Bob|3E-@9G$PoF-$efxHlt8%ElY?`n7+qZ8&efs2Y zDOv2I4AgP=?p+|6u6MT;NC}n%`33(+0}QHbXC?t9ISV`@iy0XB_Jc5^1#7ShP*9@8 zHKHUqKdq!Zu_%=xATcwqM9n999M?Mpgz! zAj=DgrJ-z)Pc;~s!QxCnwjm=Eg8-0@0^-be7O;30kPQOM$`~1500RU@qgl!Tl$yZK zzyefhU}S8-xBy}*$VS!$5R;|=*&x6KG?xjiGRV>b$b#xJG%x_kE|6KYD~#pfMqrSe zc)B=-M7Y15@^(^_0gtQjth#`Lx4-S*-rG``8hMQA_jdQWk9^)wTq2~krO|xKF_t%< z1eBi7X!V#e_xIPOxdjViWtkhlFMMRnVtCZ#vGCk44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0Z1^9%xK3Uj)u0C>Bob|3E-@9G$t(kVEQ3g@2%AxkMX};?ImXgIT%0RV1 zP<6_a6G-uu1o;L3M+OY82kx8z%5WBVL>2=T><3{+3)Wy2prAyFYeY$Kep*R+Vo@qX zKw@TIiJqTph=Qq}p`Ow2JkOkFcXkY-6T_Ce)R~XB|jlf`z@^o$kcH&NcFsl`@Ch5fCw^pk#hQKudy%@!4*$MdHf zDmp!WxtZaF<#a)Y6)QvUWKCzBl)X|iFr?|gnyWkl=M%X+CLOhMI>T6SpK(df+BDtJ zXfMupj2BGQe7ZRr#NKAEV4fwlPuX^x#P;KD**)(pRxAKuUHUrlAhJv>(x>hXiU@>^b%TT7Y`+@70-whkNBbeVE znRlR9sztrQ^oJ0`?(K#u`Hy57>Ywwy*l*0hTXy8L&+HBcop8Zx91Z(lTPYYZva~3l zeS2a5@e|RPolBQJczivofpvjc0^{o_jL7h JS?83{1OSCG@~Hp- literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/diamond_shield_base.png b/shields/src/main/resources/assets/shields/textures/entity/shield/diamond_shield_base.png new file mode 100644 index 0000000000000000000000000000000000000000..8686b5dfe50e470cb9444d547d4dad2b5ef219f7 GIT binary patch literal 1102 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`1I2=EDU4f*>r?EmYa-_Jw;y$b*TCiu?_tNZ6|9$vJ5aKZB4IrBSb^fxTk zTff9`({k-K3(d~%w>W>$;_g}Nw|DJ6JTN`8&+@_{yT_MJPVY58ci`#Mr?+q4j&fBF zwU)-H zF*>>1{^LW3PmgRLU9xzfP z3TOsrfk$L90|Vbd5N6ylG5al0P@=>&q9iy!t)x7$D3u`~F*C13&(AeP!Bo#s&*=9a z=50VV+fpMu(>y)37&w3&Rt70XRt82O%L|C5p=?krXfQH^#hHL?Lq;YB0U#X(#F_0Z zVDT&<8w75aF*3XWMiz`lvy=fSHG!Rh1*p=%$k>2!0mM|0jjRhGCQSjdL4XNpE)!T~ zkfjBX1=VF}U;vU`uCZ_3Z_$Im^uWaG>Eaj?;r@0?V)<+Zk+$`UiV|lxc!&oiE3C`C zwKR73+K>PLZ;oxbHc!TQckMS%iw_U?^($~}5jdNc;wPq}rbG;XaFc;KQ_elYuv+jZ@_hrSH87ZmqjezyAn?~&(=ld5aJ zIL_NSPg_nX-Qmv_?m8Rp?;rdE_Q}K)=vHo@l2V*#+&C*vAxvY%o&_7rtLMqq{rmN| z>cQ;8ub1v+(7MOky7!df>uC*lgI7o}u6fJabW`DgYDa(}lf=dOE*neUGyH$2It$3X zk*vSr%r4~*{Y}&3COkKL!?-OOsG&pm(Djbz4?5g``hK`6sdHwfcmwC`j<=h4J3I>B zA@Hin?Yu^YLEruY`5s0=+sxR-i`JQ{UU_PL?_IOu2d~f9XJ+?Lk44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`1I4)6(a4f*>r?EmYa-_Jw;y$b*TCiu?_tNZ6|9$vJ5aKZB4IrBSb^fxTk zTff9`({k-K3(d~%w>W>$;_g}Nw|DJ6JTN`8&+@_{yT_MJPVY58cc3-Xt~AOZ%2hek zUN+5FJ>luI#5Zqj-rci(f8XCyQg_{AjsAA^zBc1idsKT`3^pzUI>F-At;AQa&2FEz zdUMC<3CK2NWMU8i(osO1 z+0FtM&jPYRU|AU>!wX=9!Duu~8Gup~*cn)WDh-T`4Hy?dOac>#>c=~Y$U2Wm?=d5-n z>)uP*6`?d0ss`VPJ_r9GgTlk|%OFOdf@i#k5KNhBP0mikw3;h`GcuYvybI|Bg#*@~` z4F5#=CombYxk>SYjTtgX0lGVA~2=j*TUz4IfCF9w^|g4o5=gAP2@boJqI zTCg=aSV@Ip*@B=WEeBSYbbNborRyAny_L&+B{i0Z9_ABQJ@}=-6x&$OvS&$j!`^ky zs~Eo}cg+wm*wd-ZFx&o7XdUyOa&~Wje#>bWoBdsn{JW>MVb9NAbNRRI$2X_5e91UI z?H_w^Q_o{XC5HII^OEZSS8V@(aLR}2Zk!3uwrN&31I6F{TiKAQyn~4&JFjHf*Q{9M zXO(p?zs}{l^yB_4M&kw(<}`*(wlfTucxEszku+d#OO*J>!0=h?-zl}E1W*$4boFyt I=akR{03v$e$p8QV literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/gold_shield_base.png b/shields/src/main/resources/assets/shields/textures/entity/shield/gold_shield_base.png new file mode 100644 index 0000000000000000000000000000000000000000..3c338c214c1b1fe50f0f18ba6ee1870b4cbae557 GIT binary patch literal 1084 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`1o3GfMV-Pj|wu2X#fbm_fQB`>Z}yu8)&(iV#g%M}jHkU2CC@^qk@L&sFRxPW$>Z+M<+`*|$=^~kBaku8pCLT}=njU-r9zoO zOsRehDZUI>R;%2-d-v#EMWDFRAC&ooa@Ed~xC zhm}E!k(GfF$npYWX($^M>Kcs9U~wiO+mMloK>$cc0dZzK3s^i0$OeJ^WsD3jfRO{E z(JW;EN=;yAU;(N$Ffuk^TmUf@WFzYWh)Gj`Y!F}qn#%-M8DwbzWI=Tq8W@0N`D{xs zwRFX82dZQCba4!caDO}H?X=kn0&R**B}FF*BySPwU6;1e*FO0D|9e&^O3t1vydKlg zU-aPko_+F_kI z(f%4L+<>TcuDVdCtHR1H+=KEz_3HL#5G(jy<@*}^-2A8`#+S&sWzvHbX=Rn zpso}bGvTq>?zq4Auer|K|2=Qf_{q$watSvzEI4l`UDIW>zIDt} z;(*2p29E}Bfe=GxX2ZHp$q1iEwtHMw&0qwYI%`eo{04E85W~ZNr)My*yk*>`9D3%# zKh|H;*`M7HXjGJOUb}aX^#jsMKScufsiNt#@B=70%bZ^B(W{Kl(G12-rXlVA5HXPp1ZcZZ0cwJ{!0`2`Olk44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`1o4DbnYUDqkTrd{;N9EC%( z%j7R@u{gU#cK>wg-h7_^LcYEN-g8Uku5Pzp+aY#kn^kM3U1^j-l&f;6y=A@g)sb$b#xJG%x_k^4XSNYUzsG z4pb-L>Eaj?;r@2Y?V{TX0&U@J<%R<86Pr{6vbUb-e7x+PClU@x(s9eU6{K^NAmWe(-_IF+#a2o9FjE6jVR( zfcY)+eDCe{`(#dEZZ4bezdqcc;YLN=dN`h`^Ed4>w{htAL(I`k#CUdtgFB2SM}Nci#x+_Cyki*0UB=;9=9C4 z+kb1uqc8`#|IyqDj2pxbFeT_VupWqF;BMH;Aa=l_@3H@R<15+j@6A;}>BQ63&t;uc GLK6Ub;i*Uf literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/netherite_shield_base.png b/shields/src/main/resources/assets/shields/textures/entity/shield/netherite_shield_base.png new file mode 100644 index 0000000000000000000000000000000000000000..798135c1a476f7f9244d15f3e31ca4b958b30991 GIT binary patch literal 975 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 literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_diamond_shield_base.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_diamond_shield_base.png new file mode 100644 index 0000000000000000000000000000000000000000..175d35a46b89a83703c8ea7ed636dba6bfbfb965 GIT binary patch literal 1130 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 AO8@`> literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_gold_shield_base_nopattern.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_gold_shield_base_nopattern.png new file mode 100644 index 0000000000000000000000000000000000000000..561d79fd03025db7b3660e346ffa353a43d66491 GIT binary patch literal 1842 zcmdT@`BPI@6n+T_0%`;iOx}{0ptyiVz^Y)i21*L3(6CBznKFooS^`M5t&SrW6eK_h zktGQs1PHhg37aHJ79c>_Auia8T6d;cMT@mAwKul?rT;z~W4M+vTFV?#(1&aB5d~wYnjXtu z6txlC9kSFUgNJGu{nhmTDs))E9IVENYZyZc+*rq$L5y@*9P1R*jTOvJ5!N9>IwV-`*LM0cR9gb;%8*V8U0;Uj zMJO+Mc0wqmD@C=%h_)0srYWN8N>FVnsu5DPC172sFU7RQsJe)z5yBcFa;X?m3#gjY z@MR&=ei~H^XqSY*5p@yLCV(#ir2y6xAsQj5#aarS)dIjH7Yk{Zim$6t4Y|%ud9+3z?Lv;T zibqrNs7*Y$DIZqlE>z|?HJqZV3!MyQcyFa^w`@_D1aB#rKT@{>T;1iFAEQBPPY(}` zc>g~(NF0#41bm2XO3;@FAc&%~1i^}1TcB1^tmNt)&6aq}?auJm1sHjr{e`f1j4!t=v|oA0Kzy2IT29AezOp2S_> zZ=f4avKOZwi9WF+)#qpalX>?Wk~i58IXUIbfd}0E9GDL7o0i1~1%;7z>yI`#p@McG^`I4P`?Q3~M!+3<}!R>}uwwqF17N2tnv9f(c z+T!p3p2#jck3=X!#Y!YAoRjm|`Xj%!ADe9LNjG(@C0Pou_=o3jD8d51m5U~bujVh+ z+r=EMErECaWOQ|PWgmFxJS^tE@ZNPUEb50GKDl_=>-dbRtfRc9_+q2CfVK1R=v~*% zC8s@B?oiEllkKyQsuID4TkEagjwg;@>)7x{M7sN6^}g$;>sMZ=8*d2v)rrLAiDLOlG zHM2MUS#pNkp^}}s{EAjzp8;>dvE@^vGwp9)UZ3nHNHZgM)DkDM`&6+G+f;hPYp8i9 z0|GOqE3M7@*I(fzicZGaiIT>a>q`d$ZZq1j^Xt zs>I=PUCMO0Iic(k(~+*po?_Hkx$Q|-r?u4l5o?}_7JJCMN#40ZR*es?A@ysyEfZSv z!L1aB)>+Re>2qz=hji}@oi76mD%QI;%x*uPp(JoOng<`P+^HSQyUxi_h$Er*_Yvnp z>#ksK$cu?L`4saj#&?UyyO;5}@P^<0*4?2@O}!nTnS4>Ayl{KHK+dL#I$Xw%*}wjC z(Vs7_KfP1Yt+R%rvM6Kr<~u&z=p|v*o;GQ&S^D~c)OWW(dp~(^DdwZpJ8`yW rxXapzTUn`O<*~bV+x=V$gWg&ZwVzLN{B}57e)eE?Xn@lHtK)wGu)$)F literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_netherite_shield_base.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_netherite_shield_base.png new file mode 100644 index 0000000000000000000000000000000000000000..1f630d8106697404b1f490585a61f1b73cd0cea3 GIT binary patch literal 999 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0_2Ka=yD#|J<$SCM(=<2HLSQ=S`dWD2}hngFh>8NRk`-BPd3o6Me$xF*y z8CzNynm>K|^!DxBQLf6N_OfZd>Tln^{q*URfu@0+l$-#cfWM_A&{QD-Ax1_P^E#9u>s=(h^ZhOSr{&8 z03^FWX3?%NmV+CCQTfQz#W5tp{q2k90-R%y)AOpKXx$@o0SqnJNltj{^mt}fE>k?-;lvk89b`O!y6bV}jeWle@$ zEsK84vlTNlT^5tVqk75ewbq}t+-9Dx8_&scThH1R88W-act-A183h|1g_&zMA6Ghd z>gs(Hh7YeU{Sweyd-@vdq$i)1ISN^)cyZj;W2pJMOX2;l=hIhw20czW43iwO=e8lrPSfzyGbsF-f{HfU&{Bq%wKZgfEMy7+Jh) z;qdujo@U9!z}NBWe3FZhn1Gjx#k()e2AWUJ;~B!9-jA5ag%l>-@UpIV@R?T|&p25Dpb3N0! z%e)0)x27N9;+R^oBv)3UH~0kOKczJm6ZD^ckdj_J;h6S=tI8Q)3t4?$y}7T*P%(ME z+ku28wx4 LS3j3^P6j< zN1Q?{t*up2gt27+M_h1;mZ=2?C{iufYDJXdI#{7dd!zQ3{sTR8&i%f7&UeqfcjoL! zOfY!3`MN<6)W^d0YI?UY>0xIyXQXu8>e?8<0B#H+iLfzY-do* zOEjhErT$XMd~53-k*NU6x0Q859&0Xj~rWi>p-YZ+R*u0FE;p#j_O4kPJ_99Ko?b zNwR88&C@)Cs~JMAR?!Sjs~rxwnj=^eB`J)gQA(|%D1;Pyh}9THV>F476iVR;PGJF_jWi$#G19;Yt;u#8D}tQmRlHrU+CZQUsNus2n9w zLMcO3K&((9QY9)!R0>QfQDQQTKnSH2!4(81M{yttl!I?xYKpW2*jQvvNdEhOGU!ms zPRC%l7R0`@7J@uG9U)jfu)`H3eTwv!qU3yA(T428TqrSn)dxj%f<8r}p;?;y>$Ip1 zXxefuMw`)yLoQ(B4EYM2Apu}z|Kfixg+OV~Ovni+8IETJ2i|mb+~|DZO{W^b9VP^Qg|C(75FKD|Pq7T+sCq73 z*IT|bs~zYnjnR=Q7Q=167s zlcp-;WoN1CLS3Aq)STmbwExzz_JY1Oi2*0$1hC=dmcVbG{wW$oV)406#qJx*%PKs} z78LfU?oTRu(HB_?+dQ@xe4U!_6_?sj?O$PPSk`R`?MKQJXD;C2=vm>y&hmlPIfdp? z@7bN#mqEL6F4opkrcOG#_Xu~SXXWAUgq~9K$k_cUNGzNnrClF=RnROccvNxTrMt(p z{A6t%mG#*S*J01X68cHsu|0;lE_M9#%yXG=VvBv^2Y36OeT|h+uaJTDRR{0F**0nU z_#j$!`$q4x-l_3@e(sG!a*1S7bn)rY?Z%O9eBsZxirsoIjvNg0@jsD#xF@b-YU3fZ+4=~ISi9q(F!Ql} z{dn$J>Y2=Y%_)bSWTj1)vM+>w_-c5pBc^3)da>xsLq7_pt<=XZOD0w{{zA7$jA_G{ znC?b&HW(7WoA+?|(?UPP(o@6!GU(Ue8@!ks{gZheL)T7qJ)F~5d+}AP=fH70{7LBh zPx4zI?@MdUx>MsE(s-tXF%9;XyqCUtpycUr{_b`8LrI$gdP;s<;Z>EBJd{0E-Pv|3 z<|j*3c4ffe_tSaS4qrVhnc-tE^|8(o<&-AP+AfFziK5W@?&WDd+bp~CuRA6bGU^ke Jo1?5-{{i#lHWvT@ literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_shield_base.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_shield_base.png new file mode 100644 index 0000000000000000000000000000000000000000..3cba99fea0b715fbab7d45b38735acdf1a59a6dc GIT binary patch literal 840 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~q1o(uwwl80s-qIP8nm>2r_Js1fg09I=pFX{P`*xJ8a;Uv*ny>oXw{Jgv z`V^W|lGe}>Q&sP8Dd`v#1Jpfd!?ww*H)XZ=Ojx%$x2wOje@5xl*<}-EmQS2@_wL=A zY4c0^rUR8-yYmWUmqJO9U+{nYfFUME`Yli`XMsm#F#`kNVGw3Kp1&dmC@4|l8c`CQ zpH@VE}H;YrZa;ku~#e2FqhD5l( zo$|J(zr9h&%{A~ebb6> zJQKGbGZ2(c&aFDw^rb}hi1l?{i|doV9&DF8+%C;>I4`l`fWnRMiVlk`bGUZA4f>O} zo#WeLokaV)$}ghQ>~)(8zs!ldp_8P?vA5q&LD0_Rnprzr`7BcWQ092*uz6x96FJ#bvSQQ!BW$La>$O#IBR9@ou)Wr$174I-1jp63ahdTp13-l>t3`|Nw|Z&z|JT0gm%S>$ko=nR3WMU2ZI z`>;*ETJYh$;U*?VzY8qRAD#!?Z7SI}TWbZ=LatQ~E1I+fRxRLa(OS_|Iq!M?f|nbu TEE7I~VxGa%)z4*}Q$iB}SuZUE literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_shield_base_nopattern.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_shield_base_nopattern.png new file mode 100644 index 0000000000000000000000000000000000000000..a797095e857cbf0ba21609bebd656ef9b65737ec GIT binary patch literal 1457 zcmd5*`BPI@6n-xOjf&e)MpSTUDV4S(1)NT$MF^NkB9erqf{Ijjab!(GLPEmJM#9VX zl8}8*2m!Q;&Zw9Ityaa(wBi&xtyDy%Q2BY0zvg-|Y zgTbaVST&tyU8hB>v*`3zwZ@2O%o>eJr8Xd1qef#inNht%jTqF3QKK^>S`(r%DU>>e zLZ?Cu3YAW-)TuN^xm?#SQz?|4GMO4yXk{>>ROvfl4J_A6Won63DUqtg?Fx}ZE*8sW z9f+($(=JoD38X?HEELIwVswSY5+$!q0tsaTQHM|hL!u5&tBA`Jw{V3#owWcERKN9fp~lgmnUMf_)QEhgTx>jo*P z4o4oW_S_MQl+8Sh+Xg*u_&* z)>Nu`yS{7T#qj17^280QmP;)o8ZJfF*W6a@CDo?yDvRZuEnP@B9CNMyyOQZ!kN1q! z*3u7*)Q$*{%-{Q$nDIPd9t6hbupolZ?WU&3Udz<~rxa%`;04NF^ zEB_1D9}U1nU|d8K=lwP?w833A^iu>A?5}zlc(yU{$@3#Kz2Lywy4<%<nQ@iJLbFwdwEkt7@p)vqV3p)tFU>H6L0zL6C Y9}CiZro(j+$-(zQCQ=B;GY<;?0lI0gT>t<8 literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/item/copper_shield_plating.png b/shields/src/main/resources/assets/shields/textures/item/copper_shield_plating.png new file mode 100644 index 0000000000000000000000000000000000000000..3ab62ba07092ad5e16a1bc895b868d7cd698b618 GIT binary patch literal 480 zcmV<60U!Q}P)Px$nn^@KR5*=|lCetyQ5?rV7Y!~BL2qafROmo4T26u*nuMUnTiOzGXmDt4YHD?8 zOsGE~Xz?Iua&VAbE)N9{OgM0PP=XCY!8MpKPhZe)eD}T2_w#-{&`h|`^T7GdEh3Ra zByu>-w#qJDK?WYZ{y;T1>NN#x)NA;19LXz#Y9SL=N<{$tk58^1pOwwUK_1%_0K9!g z3zfl4sn;K<)Inr${kJhFY~#m9Yo#x{kv9p>Ia*-C`~+iNj4 zMI3J;I(B+~40000Px$lSxEDR5*=|kiAPnQ5=RJEh32&Lx_T?sUfH(h@6@tD7ONa(ElJpXh>TN8mwq- z(k1Kz32JDNmOzOVL6nNN2n)*a3f?H`wA_2TSFg|y&Tu~7=Y8J;7UK?ug*y}$R(H+Q zX(g^iH;Ff1Sp^CC*x9oE3jk0;CD7Rq+bi-+hc$yN0RRh?2QK&Yw9n=uIn_&Pt~Eq-c~2|R&CF}1rT`x_mNux58t1;5ipLaCBZ z?K{kC3=QO_!;QMUaqw`w*ag_0A0SNwqjF-cB5A_!j1C_v^&cdeX^4G P00000NkvXXu0mjfA|=T^ literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/item/gold_shield_plating.png b/shields/src/main/resources/assets/shields/textures/item/gold_shield_plating.png new file mode 100644 index 0000000000000000000000000000000000000000..e3b361bfe28f8b9d765ab2b58adbb20f8bbdf3ca GIT binary patch literal 432 zcmV;h0Z;ykP)Px$YDq*vR5*=|lf6qqQ5=RJKc=>eIlHz;M0-Pc(SJdQ3vLckG&YAI=n#kvMgPG? z!l6MZ5D^?rutOhc2PGw+B8i8J*% z>OGH%=|Zw+R^(p*0MwZ1+Bte9{|o+sg@INQh&__eep*CC#2$&g$hp%rG&$Ue2G?5_ z-=8MLG&HdnIT3s0138eu3b9m@eowjkhuS9no+4A9gBtVP*b2V`^>K_no}yQ>0NCTH z3;Vj$v4&mVo|GS88k#twNvlJ@r_d`|VyPs1`#Y{+Squ>MCRla^c)V!PEVlu$hFt(^ zRg2O;`$`4(;AkdrNuj8*or#Bb_W^vMswDu0q82I!`1@l3%kSPB aAK)7=TPx$bV)=(R5*=|l1)njK^%u4L!lQ|QYctaNTSgU!SE=4gRb=<>l)OlOLUhcvx(43 z9TP%ud<%u`P&@4E8vReZ%*^xre#1b(WRfW-lT0~5Yl{;OI(%|^hUzG|yETxf)_dq* z0C((!O|eu)4>Znn4B!NTRsv*QBC-NIVWT>V17IGGEP;G9H@>V(TFn>6S|joWL{ayuQ5x_>AqYLRKs0 zf6)$}cMyxk9DrOlM|?Z}bL+o{cXoFeO{O%v%4hchf19wBMUULAB k(&?qxePx$P)S5VR5*=|k}=NWFc3!Hzxq!>OX1dy)8z=%K!Gpej*1I#fpkDay4)dMXk0;z zE1<4x*6TF@A%rn33rhMTBG>CxHk*wYW2EnU8LIF5^bL3PXAF2e9sp>qi7}@2 z?RHC16ey)oN>No+>Ya@cLcn{^<#GYQd!Jx+UDI{lq(2#0Yh^gpG!47m4(~l$Yn*d9 z=XgG!yk4&fAQ=ow<3xbN;XsU$)oR82{RW_ITW+`8PXZWY#5tGdAO3*}>@$60ptZ(( zPt!ES7?bh<8)lC&ru4}jR8=)gyx;E}k4L($%cduTe?)29ma;4_{j0$@qYrqhzbt3dlS?meg#Z8m07*qoM6N<$f}_i= APyhe` literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/assets/shields/textures/item/shield_repair_kit.png b/shields/src/main/resources/assets/shields/textures/item/shield_repair_kit.png new file mode 100644 index 0000000000000000000000000000000000000000..e1c9c072416dfb432864674a77a7368b5923561f GIT binary patch literal 479 zcmV<50U-W~P)Px#1Y=1Lk}*p{Q5c3F#jP!9Z3*;(4k}vUPz|Rc zf}p9jA#aX%i24UbSbJ$yKcF_Fp*yJSy_JH3mfjiy8-%vj(@^JdFGf+l)8X(v-+90H zJMd41ek#ZbQvwVJ9spBgP3BYMY#()hWXTCr7Rwb`b$U`M8W+--9Fu>7)j1j$-#5q! zQ&yec2wW^zMjC{_f>&0TaT*cd~b0NJF$TxKc&mrl-gW91^` zhj(_jbTdB;aCh4Rz^&WlEsM?dC1Qz%4+r1bR`An<7l73$5d|yDO8du`0eCp@$Xk}q zK|iJvFP1BEae6}TZNzl?#d1aFgejwOp*K)&g;zq^Qm!8ub!D% zN54KCcw}aU9?M)SaNo9dc42^2I>F=18>dc}eW8XanGAGdCknH8kc39?B8r_mvA zS@{1!NUfyXx()pj!002ovPDHLkV1oQ_#nAu& literal 0 HcmV?d00001 diff --git a/shields/src/main/resources/fabric.mod.json b/shields/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..8293432 --- /dev/null +++ b/shields/src/main/resources/fabric.mod.json @@ -0,0 +1,48 @@ +{ + "schemaVersion": 1, + "id": "shields", + "version": "${mod_version}", + "name": "Extra Shields", + "description": "A vanilla+ expansion to shields. Adds various new shields inline with the vanilla armor system and shield plating upgrades. Includes new and improved enchantment support.", + "authors": [ + "IMB11", + "cassiancc" + ], + "contact": { + "homepage": "https://moddedmc.wiki/en/project/extra-shields", + "sources": "https://github.com/IMB11-Mods/ExtraShields", + "issues": "https://github.com/IMB11-Mods/ExtraShields/issues" + }, + "license": "All-Rights-Reserved", + "icon": "assets/shields/icon.png", + "environment": "*", + "entrypoints": { + "main": [ + "dev.imb11.shields.fabric.ShieldsFabric" + ], + "client": [ + "dev.imb11.shields.fabric.ShieldsFabricClient" + ], + "fabric-datagen": [ + "dev.imb11.shields.datagen.ShieldsDatagen" + ], + "jei_mod_plugin": [ + "dev.imb11.shields.compat.JeiCompat" + ] + }, + "mixins": [ + "shields.mixins.json" + ], + "depends": { + "fabricloader": ">=0.15.0", + "minecraft": "${target_minecraft}", + "fabric-api": "*", + "mru": "*" + }, + "recommends": { + "rrv": ">=6.5.0" + }, + "conflicts": { + "rei": "*" + } +} diff --git a/shields/src/main/resources/shields.mixins.json b/shields/src/main/resources/shields.mixins.json new file mode 100644 index 0000000..231279c --- /dev/null +++ b/shields/src/main/resources/shields.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "dev.imb11.shields.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "AnvilMenuMixin", + "ItemStackMixin", + "LivingEntityMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} From 3767682db75c69ed2cff5c22e55c1711ec6ace43 Mon Sep 17 00:00:00 2001 From: Cassian Date: Sun, 4 Oct 2026 14:45:19 -0400 Subject: [PATCH 2/4] fix(shields): update issues --- .github/ISSUE_TEMPLATE/05-shields-bug.yml | 127 ++++++++++++++++++ .github/ISSUE_TEMPLATE/05-shields-feature.yml | 86 ++++++++++++ shields/src/main/resources/fabric.mod.json | 4 +- 3 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/05-shields-bug.yml create mode 100644 .github/ISSUE_TEMPLATE/05-shields-feature.yml diff --git a/.github/ISSUE_TEMPLATE/05-shields-bug.yml b/.github/ISSUE_TEMPLATE/05-shields-bug.yml new file mode 100644 index 0000000..5407caf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/05-shields-bug.yml @@ -0,0 +1,127 @@ +name: Shields bug report +description: Report a crash, broken behaviour, or compatibility problem in Shields. +title: "[Shields] " +labels: + - "project:shields" +type: Bug +body: + - type: markdown + attributes: + value: | + Report a problem with Shields. Tell us what happened and how we can reproduce it. If you are unsure about something, say so. + + - type: markdown + attributes: + value: | + If you are on a game version or loader not listed here, we are unfortunately not supporting it anymore. + + - type: checkboxes + id: existing-issues + attributes: + label: Existing issues + options: + - label: I have [searched the existing issues](https://github.com/IMB11-Mods/JavaEditionMods/issues?q=is%3Aissue%20label%3A%22project%3AShields%22) for this problem or suggestion. + required: true + + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Describe the problem and what you expected to happen instead. Include the exact error message, if there is one. + placeholder: | + What happened: + What I expected: + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: How can we reproduce it? + description: List the steps that trigger the problem. If it happens unpredictably, describe what you were doing and how often it happens. + placeholder: | + 1. Start the game with... + 2. Open or do... + 3. The problem happens when... + validations: + required: true + + - type: dropdown + id: minecraft-version + attributes: + label: Minecraft version + description: Which Minecraft version were you using when the problem happened? + options: + - "26.1.2" + - "26.3" + validations: + required: true + + - type: dropdown + id: mod-loader + attributes: + label: Mod loader + description: Which mod loader are you using? + options: + - Fabric + - NeoForge + validations: + required: true + + - type: input + id: mod-version + attributes: + label: Shields version + description: Copy the exact version from your launcher's mod list or the mod's filename. Please avoid "latest". + validations: + required: true + + - type: dropdown + id: environment + attributes: + label: Where does it happen? + options: + - Starting the game + - Singleplayer + - Playing on a server + - Running a dedicated server + - Development/build + - Other / Not sure + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Logs or crash report + description: | + Open the affected game instance's folder in your launcher and find logs/latest.log. Upload it to [mclo.gs](https://mclo.gs/) and paste the link here, even if the game did not crash. + If the game crashed, include the matching report from the crash-reports folder too. For development issues, include the build output instead. + Review logs for personal information before sharing them. If logs are unavailable, explain why. + placeholder: Paste your log links or explain why logs are unavailable. + validations: + required: true + + - type: textarea + id: other-mods-and-settings + attributes: + label: Other mods, packs, or changed settings + description: Include relevant mods and versions, a modpack link and version, resource packs, or settings you changed. + validations: + required: false + + - type: textarea + id: troubleshooting + attributes: + label: What have you tried? + description: Mention anything you tested and whether it helped. If you tested with only this mod and its required dependencies, tell us the result. You do not need to do this before reporting. + validations: + required: false + + - type: textarea + id: additional-context + attributes: + label: Screenshots, videos, or extra details + description: Attach anything that helps demonstrate the problem. For development issues, include a small code example or example project if possible. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/05-shields-feature.yml b/.github/ISSUE_TEMPLATE/05-shields-feature.yml new file mode 100644 index 0000000..3a8a19b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/05-shields-feature.yml @@ -0,0 +1,86 @@ +name: Shields feature request +description: Suggest a new feature or improvement for Shields. +title: "[Shields] " +labels: + - "project:Shields" +type: Feature +body: + - type: markdown + attributes: + value: | + Suggest an improvement for Shields. Explain what you want to achieve and how the change would help. + + - type: markdown + attributes: + value: | + If you are on a game version or loader not listed here, we are unfortunately not supporting it anymore. + + - type: checkboxes + id: existing-issues + attributes: + label: Existing issues + options: + - label: I have [searched the existing issues](https://github.com/IMB11-Mods/JavaEditionMods/issues?q=is%3Aissue%20label%3A%22project%3AShields%22) for this problem or suggestion. + required: true + + - type: textarea + id: use-case + attributes: + label: What would this help you do? + description: Describe the problem, missing capability, or situation you want to improve. A concrete example helps. + validations: + required: true + + - type: textarea + id: proposed-feature + attributes: + label: What would you like to happen? + description: Describe how you would expect the feature to work. You do not need to explain how to implement it. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives or workarounds + description: Is there another way to achieve this today? What does not work well about it? + validations: + required: false + + - type: dropdown + id: minecraft-version + attributes: + label: Minecraft version + description: Select a version only if your request is specific to it. + options: + - "26.1.2" + - "26.3" + validations: + required: false + + - type: dropdown + id: mod-loader + attributes: + label: Mod loader + description: Select a loader only if your request is specific to it. + options: + - Fabric + - NeoForge + validations: + required: false + + - type: textarea + id: related-mods + attributes: + label: Relevant mod versions or other mods + description: Include Shields or other mod versions only if the request depends on them. + validations: + required: false + + - type: textarea + id: additional-context + attributes: + label: Examples or additional context + description: Add screenshots, mockups, links, or related requests. + validations: + required: false diff --git a/shields/src/main/resources/fabric.mod.json b/shields/src/main/resources/fabric.mod.json index 8293432..a53859c 100644 --- a/shields/src/main/resources/fabric.mod.json +++ b/shields/src/main/resources/fabric.mod.json @@ -10,8 +10,8 @@ ], "contact": { "homepage": "https://moddedmc.wiki/en/project/extra-shields", - "sources": "https://github.com/IMB11-Mods/ExtraShields", - "issues": "https://github.com/IMB11-Mods/ExtraShields/issues" + "sources": "https://github.com/IMB11-Mods/JavaEditionMods", + "issues": "https://github.com/IMB11-Mods/JavaEditionMods/issues" }, "license": "All-Rights-Reserved", "icon": "assets/shields/icon.png", From 7bc809c06f1b3ec8f2fc50fb19bfc0b117922106 Mon Sep 17 00:00:00 2001 From: Cassian Date: Sun, 4 Oct 2026 14:49:37 -0400 Subject: [PATCH 3/4] fix(shields): add missing github meta --- .github/scripts/changelog-comment.cjs | 2 +- .github/scripts/prepare-release.mjs | 2 +- .github/workflows/prepare-release.yml | 2 +- .github/workflows/release.yml | 7 ++++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/scripts/changelog-comment.cjs b/.github/scripts/changelog-comment.cjs index 8877bb4..81abb01 100644 --- a/.github/scripts/changelog-comment.cjs +++ b/.github/scripts/changelog-comment.cjs @@ -17,7 +17,7 @@ module.exports = async ({ github, context }) => { const issue_number = pull.number; const repo = { ...context.repo, issue_number }; const comments = await github.paginate(github.rest.issues.listComments, repo); - for (const project of ['sounds', 'mru']) { + for (const project of ['sounds', 'mru', 'shields']) { if (!pull.labels.some(label => label.name === `project:${project}`)) continue; const marker = `[release-changelog-${project}]: #`; if (comments.some(comment => comment.user.type === 'Bot' && comment.body.split(/\r?\n/).includes(marker))) continue; diff --git a/.github/scripts/prepare-release.mjs b/.github/scripts/prepare-release.mjs index 9d3bfe5..1bde467 100644 --- a/.github/scripts/prepare-release.mjs +++ b/.github/scripts/prepare-release.mjs @@ -11,7 +11,7 @@ const git = (...values) => run('git', values); const project = option('project'); const version = option('version'); const versionPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/; -if (!['sounds', 'mru'].includes(project) || !versionPattern.test(version ?? '')) throw new Error('Provide --project sounds|mru and --version X.Y.Z. Optional: --from REF, --write.'); +if (!['sounds', 'mru', 'shields'].includes(project) || !versionPattern.test(version ?? '')) throw new Error('Provide --project sounds|mru|shields and --version X.Y.Z. Optional: --from REF, --write.'); const suffix = version.match(/^[^-+]+(?:-([^+]+))?(?:\+(.+))?$/); if ([suffix?.[1], suffix?.[2]].filter(Boolean).some(value => value.split('.').some(part => !part)) || suffix?.[1]?.split('.').some(part => /^0\d+$/.test(part))) throw new Error('Invalid semantic version suffix'); const head = git('rev-parse', 'HEAD'); diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 4c95401..d5dc4df 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -7,7 +7,7 @@ on: description: project type: choice required: true - options: [sounds, mru] + options: [sounds, mru, shields] version: description: version type: string diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 73f563c..e25b670 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,6 +5,7 @@ on: tags: - mru/v* - sounds/v* + - shields/v* workflow_dispatch: inputs: tag: @@ -31,8 +32,8 @@ jobs: RELEASE_TAG: ${{ inputs.tag || github.ref_name }} run: | case "$RELEASE_TAG" in - sounds/v*|mru/v*) ;; - *) echo 'Expected a sounds/v or mru/v release tag'; exit 1 ;; + sounds/v*|mru/v*|shields/v*) ;; + *) echo 'Expected a sounds/v, mru/v, or shields/v release tag'; exit 1 ;; esac test "$(git rev-parse HEAD)" = "$(git rev-parse "refs/tags/$RELEASE_TAG^{commit}")" echo "RELEASE_MOD=${RELEASE_TAG%%/*}" >> "$GITHUB_ENV" @@ -49,7 +50,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: | case "$RELEASE_MOD" in - mru|sounds) task=":$RELEASE_MOD:publishMods" ;; + mru|sounds|shields) task=":$RELEASE_MOD:publishMods" ;; *) exit 1 ;; esac GITHUB_REF_TYPE=tag GITHUB_REF_NAME="$RELEASE_TAG" GITHUB_SHA="$(git rev-parse HEAD)" bash ./gradlew --no-daemon --build-cache "$task" From 21bb61a0a6639a41d55016b704f8d947dc6c5c9b Mon Sep 17 00:00:00 2001 From: Cassian Date: Sun, 4 Oct 2026 16:17:13 -0400 Subject: [PATCH 4/4] chore: version bumps --- mru/mod.properties | 2 +- shields/mod.properties | 6 +++--- .../main/resources/META-INF/neoforge.mods.toml | 17 ++++++++++++----- shields/src/main/resources/fabric.mod.json | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/mru/mod.properties b/mru/mod.properties index 7facc5b..22ec1e4 100644 --- a/mru/mod.properties +++ b/mru/mod.properties @@ -2,7 +2,7 @@ mod.id=mru mod.name=MRU mod.description=A library mod which provides various utilities for Cassian and IMB11's mods. mod.license=MIT -mod.version=1.0.41 +mod.version=1.0.42 mod.group=cc.cassian.mru publish.modrinth=SNVQ2c0g publish.curseforge=669659 diff --git a/shields/mod.properties b/shields/mod.properties index 3e06f64..b7efed2 100644 --- a/shields/mod.properties +++ b/shields/mod.properties @@ -2,10 +2,10 @@ mod.id=shields mod.name=Shields mod.description=A vanilla+ expansion to shields. Adds various new shields inline with the vanilla armor system and shield plating upgrades. Includes new and improved enchantment support. mod.license=ARR -mod.version=1.4.2 +mod.version=1.4.3 mod.group=dev.imb11.shields mod.required=mru publish.modrinth=GPVR65Ju publish.curseforge=1169734 -publish.dependencies.fabric=fabric-api,yacl,mru -publish.dependencies.neoforge=yacl,mru +publish.dependencies.fabric=fabric-api,mru +publish.dependencies.neoforge=mru diff --git a/shields/src/main/resources/META-INF/neoforge.mods.toml b/shields/src/main/resources/META-INF/neoforge.mods.toml index 32087ea..bd0aad1 100644 --- a/shields/src/main/resources/META-INF/neoforge.mods.toml +++ b/shields/src/main/resources/META-INF/neoforge.mods.toml @@ -4,13 +4,13 @@ license = "All-Rights-Reserved" [[mods]] modId = "shields" -displayName = "Extra Shields" +displayName="${mod_name}" version = "${version}" displayURL = "https://modrinth.com/mod/shields" logoFile = "assets/shields/icon.png" iconFile = "assets/shields/icon.png" authors = "IMB11, cassiancc" -description = '''A vanilla+ expansion to shields. Adds various new shields inline with the vanilla armor system and shield plating upgrades. Includes new and improved enchantment support.''' +description="${mod_description}" [[mixins]] config = "shields.mixins.json" @@ -18,18 +18,25 @@ config = "shields.mixins.json" [[dependencies.shields]] modId = "neoforge" type = "required" -versionRange = "[26,)" +versionRange="${target_loader}" ordering = "NONE" side = "BOTH" [[dependencies.shields]] modId = "minecraft" type = "required" -versionRange = "${minecraft}" +versionRange="${target_minecraft}" + +[[dependencies.shields]] +modId="mru" +type="required" +versionRange="[${target_mru},)" +ordering="NONE" +side="CLIENT" [[dependencies.shields]] modId = "rrv" type = "optional" versionRange = "[6.5.0,)" ordering = "NONE" -side = "BOTH" \ No newline at end of file +side = "BOTH" diff --git a/shields/src/main/resources/fabric.mod.json b/shields/src/main/resources/fabric.mod.json index a53859c..490ecee 100644 --- a/shields/src/main/resources/fabric.mod.json +++ b/shields/src/main/resources/fabric.mod.json @@ -37,7 +37,7 @@ "fabricloader": ">=0.15.0", "minecraft": "${target_minecraft}", "fabric-api": "*", - "mru": "*" + "mru": "${target_mru}" }, "recommends": { "rrv": ">=6.5.0"