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/.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" 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/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/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..b7efed2 --- /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.3 +mod.group=dev.imb11.shields +mod.required=mru +publish.modrinth=GPVR65Ju +publish.curseforge=1169734 +publish.dependencies.fabric=fabric-api,mru +publish.dependencies.neoforge=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..bd0aad1 --- /dev/null +++ b/shields/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,42 @@ +modLoader = "javafml" +loaderVersion = "[2,)" +license = "All-Rights-Reserved" + +[[mods]] +modId = "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="${mod_description}" + +[[mixins]] +config = "shields.mixins.json" + +[[dependencies.shields]] +modId = "neoforge" +type = "required" +versionRange="${target_loader}" +ordering = "NONE" +side = "BOTH" + +[[dependencies.shields]] +modId = "minecraft" +type = "required" +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" 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 0000000..617096e Binary files /dev/null and b/shields/src/main/resources/assets/shields/icon.png differ 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 0000000..1edc07f Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/copper_shield_base.png differ diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/copper_shield_base_nopattern.png b/shields/src/main/resources/assets/shields/textures/entity/shield/copper_shield_base_nopattern.png new file mode 100644 index 0000000..b3aa620 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/copper_shield_base_nopattern.png differ 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 0000000..8686b5d Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/diamond_shield_base.png differ diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/diamond_shield_base_nopattern.png b/shields/src/main/resources/assets/shields/textures/entity/shield/diamond_shield_base_nopattern.png new file mode 100644 index 0000000..d6e0a70 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/diamond_shield_base_nopattern.png differ 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 0000000..3c338c2 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/gold_shield_base.png differ diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/gold_shield_base_nopattern.png b/shields/src/main/resources/assets/shields/textures/entity/shield/gold_shield_base_nopattern.png new file mode 100644 index 0000000..4ec5f22 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/gold_shield_base_nopattern.png differ 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 0000000..798135c Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/netherite_shield_base.png differ diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/netherite_shield_base_nopattern.png b/shields/src/main/resources/assets/shields/textures/entity/shield/netherite_shield_base_nopattern.png new file mode 100644 index 0000000..5cccaac Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/netherite_shield_base_nopattern.png differ diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_copper_shield_base.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_copper_shield_base.png new file mode 100644 index 0000000..51621c0 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_copper_shield_base.png differ diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_copper_shield_base_nopattern.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_copper_shield_base_nopattern.png new file mode 100644 index 0000000..3e32109 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_copper_shield_base_nopattern.png differ 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 0000000..175d35a Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_diamond_shield_base.png differ diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_diamond_shield_base_nopattern.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_diamond_shield_base_nopattern.png new file mode 100644 index 0000000..fc3692a Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_diamond_shield_base_nopattern.png differ diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_gold_shield_base.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_gold_shield_base.png new file mode 100644 index 0000000..4336e24 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_gold_shield_base.png differ 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 0000000..561d79f Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_gold_shield_base_nopattern.png differ 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 0000000..1f630d8 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_netherite_shield_base.png differ diff --git a/shields/src/main/resources/assets/shields/textures/entity/shield/plated_netherite_shield_base_nopattern.png b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_netherite_shield_base_nopattern.png new file mode 100644 index 0000000..8993317 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_netherite_shield_base_nopattern.png differ 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 0000000..3cba99f Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_shield_base.png differ 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 0000000..a797095 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/entity/shield/plated_shield_base_nopattern.png differ 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 0000000..3ab62ba Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/item/copper_shield_plating.png differ diff --git a/shields/src/main/resources/assets/shields/textures/item/diamond_shield_plating.png b/shields/src/main/resources/assets/shields/textures/item/diamond_shield_plating.png new file mode 100644 index 0000000..6b6427c Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/item/diamond_shield_plating.png differ 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 0000000..e3b361b Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/item/gold_shield_plating.png differ diff --git a/shields/src/main/resources/assets/shields/textures/item/netherite_shield_plating.png b/shields/src/main/resources/assets/shields/textures/item/netherite_shield_plating.png new file mode 100644 index 0000000..46d2c1f Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/item/netherite_shield_plating.png differ diff --git a/shields/src/main/resources/assets/shields/textures/item/shield_plating.png b/shields/src/main/resources/assets/shields/textures/item/shield_plating.png new file mode 100644 index 0000000..3a69970 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/item/shield_plating.png differ 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 0000000..e1c9c07 Binary files /dev/null and b/shields/src/main/resources/assets/shields/textures/item/shield_repair_kit.png differ diff --git a/shields/src/main/resources/fabric.mod.json b/shields/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..490ecee --- /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/JavaEditionMods", + "issues": "https://github.com/IMB11-Mods/JavaEditionMods/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": "${target_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 + } +}