From 333c717634c64cedca7b4cc19546971c12d53698 Mon Sep 17 00:00:00 2001 From: opekope2 Date: Sat, 20 Apr 2024 00:51:49 +0200 Subject: [PATCH 1/5] Add wither skeleton skull staff --- .../VanillaStaffItemHandlers.kt | 5 + .../WitherSkeletonSkullHandler.kt | 184 ++++++++++++++++++ .../assets/minecraft/atlases/blocks.json | 8 + 3 files changed, 197 insertions(+) create mode 100644 StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt create mode 100644 StaffMod/src/main/resources/assets/minecraft/atlases/blocks.json diff --git a/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/VanillaStaffItemHandlers.kt b/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/VanillaStaffItemHandlers.kt index 48583a945..968b98365 100644 --- a/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/VanillaStaffItemHandlers.kt +++ b/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/VanillaStaffItemHandlers.kt @@ -88,6 +88,11 @@ fun registerVanillaStaffItemHandlers() { Items.TNT.registerHandler(TntHandler(), TNT) + Items.WITHER_SKELETON_SKULL.registerHandler( + WitherSkeletonSkullHandler(), + WitherSkeletonSkullHandler.modelSupplierFactory + ) + Items.WHITE_WOOL.registerHandler(WoolHandler(WHITE_WOOL, WHITE_CARPET), WHITE_WOOL) Items.ORANGE_WOOL.registerHandler(WoolHandler(ORANGE_WOOL, ORANGE_CARPET), ORANGE_WOOL) Items.MAGENTA_WOOL.registerHandler(WoolHandler(MAGENTA_WOOL, MAGENTA_CARPET), MAGENTA_WOOL) diff --git a/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt b/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt new file mode 100644 index 000000000..c2433dfaa --- /dev/null +++ b/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt @@ -0,0 +1,184 @@ +/* + * AvM Staff Mod + * Copyright (c) 2024 opekope2 + * + * This mod is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This mod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this mod. If not, see . + */ + +package opekope2.avm_staff.internal.staff_item_handler + +import net.fabricmc.api.EnvType +import net.fabricmc.api.Environment +import net.minecraft.client.render.entity.model.SkullEntityModel +import net.minecraft.client.render.model.* +import net.minecraft.client.render.model.json.ModelOverrideList +import net.minecraft.client.render.model.json.ModelTransformation +import net.minecraft.client.render.model.json.Transformation +import net.minecraft.client.texture.Sprite +import net.minecraft.client.texture.SpriteAtlasTexture +import net.minecraft.client.util.SpriteIdentifier +import net.minecraft.entity.Entity +import net.minecraft.entity.LivingEntity +import net.minecraft.entity.effect.StatusEffectInstance +import net.minecraft.entity.effect.StatusEffects +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.entity.projectile.WitherSkullEntity +import net.minecraft.item.ItemStack +import net.minecraft.util.ActionResult +import net.minecraft.util.Hand +import net.minecraft.util.Identifier +import net.minecraft.util.TypedActionResult +import net.minecraft.util.math.Direction +import net.minecraft.world.Difficulty +import net.minecraft.world.World +import net.minecraft.world.WorldEvents +import opekope2.avm_staff.api.item.StaffItemHandler +import opekope2.avm_staff.api.item.model.IStaffItemBakedModel +import opekope2.avm_staff.api.item.model.IStaffItemUnbakedModel +import opekope2.avm_staff.api.item.model.StaffItemBakedModel +import opekope2.avm_staff.util.* +import org.joml.Vector3f +import java.util.function.Function +import java.util.function.Supplier + +class WitherSkeletonSkullHandler : StaffItemHandler() { + override val maxUseTime = 20 + + override fun use( + staffStack: ItemStack, + world: World, + user: PlayerEntity, + hand: Hand + ): TypedActionResult { + user.setCurrentHand(hand) + return TypedActionResult.pass(staffStack) + } + + override fun usageTick(staffStack: ItemStack, world: World, user: LivingEntity, remainingUseTicks: Int) { + if ((remainingUseTicks and 1) == 0) { + shootSkull(world, user) + } + } + + override fun attack(staffStack: ItemStack, world: World, attacker: LivingEntity, hand: Hand): ActionResult { + if (attacker is PlayerEntity && attacker.itemCooldownManager.isCoolingDown(staffStack.item)) return ActionResult.FAIL + + shootSkull(world, attacker) + (attacker as? PlayerEntity)?.resetLastAttackedTicks() + return ActionResult.SUCCESS + } + + private fun shootSkull(world: World, user: LivingEntity) { + if (!user.canUseStaff) return + if (user is PlayerEntity && user.isAttackCoolingDown) return + + world.syncWorldEvent(null, WorldEvents.WITHER_SHOOTS, user.blockPos, 0) + + if (world.isClient) return + + val (x, y, z) = user.rotationVector + world.spawnEntity(WitherSkullEntity(world, user, x, y, z).apply { + isCharged = Math.random() < 0.001f + setPosition(user.approximateStaffTipPosition) + }) + } + + override fun attackEntity( + staffStack: ItemStack, + world: World, + attacker: LivingEntity, + target: Entity, + hand: Hand + ): ActionResult { + if (!world.isClient) { + if (world.difficulty.id >= Difficulty.NORMAL.id) { + if (target is LivingEntity && !target.isInvulnerableTo(world.damageSources.wither())) { + val amplifier = if (world.difficulty == Difficulty.HARD) 1 else 0 + target.addStatusEffect(StatusEffectInstance(StatusEffects.WITHER, 5 * 20, amplifier)) + } + } + } + + return super.attackEntity(staffStack, world, attacker, target, hand) + } + + override fun onStoppedUsing(staffStack: ItemStack, world: World, user: LivingEntity, remainingUseTicks: Int) { + (user as? PlayerEntity)?.itemCooldownManager?.set(staffStack.item, 4 * (maxUseTime - remainingUseTicks)) + } + + override fun finishUsing(staffStack: ItemStack, world: World, user: LivingEntity): ItemStack { + onStoppedUsing(staffStack, world, user, 0) + return staffStack + } + + @Environment(EnvType.CLIENT) + private class WitherSkeletonSkullUnbakedModel : IStaffItemUnbakedModel { + override fun getModelDependencies() = setOf() + + override fun setParents(modelLoader: Function?) { + } + + override fun bake( + baker: Baker, + textureGetter: Function, + rotationContainer: ModelBakeSettings, + modelId: Identifier, + transformation: Transformation + ): IStaffItemBakedModel { + val skullSprite = textureGetter.apply(WITHER_SKELETON_SKULL_TEXTURE) + val skullModel = SkullEntityModel.getSkullTexturedModelData().createModel().getChild("head") + val quads = skullModel.getBakedQuads(skullSprite, skullTransformation) + val baked = BasicBakedModel( + quads, + createEmptyFaceQuads(), + true, + false, + false, + skullSprite, + ModelTransformation.NONE, + ModelOverrideList.EMPTY + ) + + return StaffItemBakedModel(baked.transform(null, transformation, textureGetter)) + } + + private companion object { + private val WITHER_SKELETON_SKULL_TEXTURE = SpriteIdentifier( + SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, + Identifier("entity/skeleton/wither_skeleton") + ) + + private val skullTransformation = Transformation( + Vector3f(0f, 0f, 180f), + Vector3f(.5f, 0f, .5f), + Vector3f(2f) + ) + + private fun createEmptyFaceQuads(): Map> = mapOf( + Direction.DOWN to listOf(), + Direction.UP to listOf(), + Direction.NORTH to listOf(), + Direction.SOUTH to listOf(), + Direction.WEST to listOf(), + Direction.EAST to listOf(), + ) + } + } + + companion object { + val modelSupplierFactory: Supplier> = Supplier { + Supplier(::WitherSkeletonSkullUnbakedModel) + } + } +} diff --git a/StaffMod/src/main/resources/assets/minecraft/atlases/blocks.json b/StaffMod/src/main/resources/assets/minecraft/atlases/blocks.json new file mode 100644 index 000000000..c23a49f65 --- /dev/null +++ b/StaffMod/src/main/resources/assets/minecraft/atlases/blocks.json @@ -0,0 +1,8 @@ +{ + "sources": [ + { + "type": "single", + "resource": "entity/skeleton/wither_skeleton" + } + ] +} From 23a588af2a3be2c9ce107f9c3ce2afa35e02b98f Mon Sep 17 00:00:00 2001 From: opekope2 Date: Sat, 20 Apr 2024 00:55:52 +0200 Subject: [PATCH 2/5] Bump version --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6609cd170..79d0d6e1b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] java = "17" # Don't forget to update *.mixins.json kotlin = "1.8.22" -staff-mod = "0.13.1-beta" +staff-mod = "0.14.0-beta" architectury-plugin = "3.4-SNAPSHOT" architectury-loom = "1.5-SNAPSHOT" yarn = "1.20.4+build.3" From ae1857f18f522d6d185809ae95faf102779f326d Mon Sep 17 00:00:00 2001 From: opekope2 Date: Sat, 20 Apr 2024 14:52:12 +0200 Subject: [PATCH 3/5] Update CI deps --- .github/workflows/build.yml | 14 +++++++------- .github/workflows/publish-release.yml | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 29c55223d..6ebce7bca 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -54,11 +54,11 @@ jobs: needs: prepare-build-matrix steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4.1.1 - name: Validate gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2.1.3 - name: JDK setup - uses: actions/setup-java@v3 + uses: actions/setup-java@v4.2.1 with: java-version: 17 distribution: temurin @@ -76,7 +76,7 @@ jobs: run: ./gradlew dokkaHtml -PjavaSyntax - name: Upload Fabric jars if: inputs.build-project && inputs.upload-output - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4.3.1 with: name: fabric-jars path: | @@ -84,7 +84,7 @@ jobs: if-no-files-found: error - name: Upload Forge jars if: inputs.build-project && inputs.upload-output - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4.3.1 with: name: forge-jars path: | @@ -92,14 +92,14 @@ jobs: if-no-files-found: error - name: Upload documentation output if: inputs.build-docs && inputs.upload-output - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4.3.1 with: name: kdoc path: StaffMod/build/docs/kotlinHtml if-no-files-found: error - name: Upload documentation output (Java syntax) if: inputs.build-docs && inputs.upload-output - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4.3.1 with: name: javadoc path: StaffMod/build/docs/javaHtml diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 95313aa01..ce8ffa1bd 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -21,14 +21,14 @@ jobs: needs: build steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4.1.1 - name: Download Fabric jars - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4.1.4 with: name: fabric-jars path: dist/fabric - name: Download Forge jars - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4.1.4 with: name: forge-jars path: dist/forge @@ -102,7 +102,7 @@ jobs: dist/forge/*-@(dev|sources|javadoc).jar changelog-file: CHANGELOG.g.md - name: Delete build output - uses: geekyeggo/delete-artifact@v2 + uses: geekyeggo/delete-artifact@v5.0.0 with: name: | fabric-jars @@ -118,7 +118,7 @@ jobs: VERSION: ${{ github.ref_name }} steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4.1.1 with: fetch-depth: 0 ref: docs @@ -127,12 +127,12 @@ jobs: git config user.email "41898282+github-actions@users.noreply.github.com" git config user.name "github-actions[bot]" - name: Download Kotlin documentation - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4.1.4 with: name: kdoc path: docs/kdoc/${{ github.ref_name }} - name: Download Java documentation - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4.1.4 with: name: javadoc path: docs/javadoc/${{ github.ref_name }} @@ -155,11 +155,11 @@ jobs: git add docs git commit -a -m "Add documentation for $VERSION" - name: Push documentation - uses: ad-m/github-push-action@master + uses: ad-m/github-push-action@v0.8.0 with: branch: docs - name: Delete documentation artifacts - uses: geekyeggo/delete-artifact@v2 + uses: geekyeggo/delete-artifact@v5.0.0 with: name: | kdoc @@ -173,7 +173,7 @@ jobs: needs: push-docs steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4.1.1 with: ref: docs - name: Configure git @@ -181,6 +181,6 @@ jobs: git config user.email "41898282+github-actions@users.noreply.github.com" git config user.name "github-actions[bot]" - name: Publish documentation - uses: mhausenblas/mkdocs-deploy-gh-pages@master + uses: mhausenblas/mkdocs-deploy-gh-pages@1.26 env: GITHUB_TOKEN: ${{ github.token }} From 5ce3438835a3f59311a8f4e7175cab18e42f342d Mon Sep 17 00:00:00 2001 From: opekope2 Date: Sat, 20 Apr 2024 15:31:44 +0200 Subject: [PATCH 4/5] Increase the rate of blue skulls --- .../internal/staff_item_handler/WitherSkeletonSkullHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt b/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt index c2433dfaa..bf12b787d 100644 --- a/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt +++ b/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt @@ -89,7 +89,7 @@ class WitherSkeletonSkullHandler : StaffItemHandler() { val (x, y, z) = user.rotationVector world.spawnEntity(WitherSkullEntity(world, user, x, y, z).apply { - isCharged = Math.random() < 0.001f + isCharged = Math.random() < 0.1f // TODO ratio setPosition(user.approximateStaffTipPosition) }) } From dee9586fe64e6d2e1886d65dfb2e8025a1b2e4f3 Mon Sep 17 00:00:00 2001 From: opekope2 Date: Sat, 20 Apr 2024 15:47:04 +0200 Subject: [PATCH 5/5] Only shoot blue skulls when holding right click --- .../staff_item_handler/WitherSkeletonSkullHandler.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt b/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt index bf12b787d..a84dc8068 100644 --- a/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt +++ b/StaffMod/src/main/kotlin/opekope2/avm_staff/internal/staff_item_handler/WitherSkeletonSkullHandler.kt @@ -67,19 +67,19 @@ class WitherSkeletonSkullHandler : StaffItemHandler() { override fun usageTick(staffStack: ItemStack, world: World, user: LivingEntity, remainingUseTicks: Int) { if ((remainingUseTicks and 1) == 0) { - shootSkull(world, user) + shootSkull(world, user, Math.random() < 0.1f) // TODO ratio } } override fun attack(staffStack: ItemStack, world: World, attacker: LivingEntity, hand: Hand): ActionResult { if (attacker is PlayerEntity && attacker.itemCooldownManager.isCoolingDown(staffStack.item)) return ActionResult.FAIL - shootSkull(world, attacker) + shootSkull(world, attacker, false) (attacker as? PlayerEntity)?.resetLastAttackedTicks() return ActionResult.SUCCESS } - private fun shootSkull(world: World, user: LivingEntity) { + private fun shootSkull(world: World, user: LivingEntity, charged: Boolean) { if (!user.canUseStaff) return if (user is PlayerEntity && user.isAttackCoolingDown) return @@ -89,7 +89,7 @@ class WitherSkeletonSkullHandler : StaffItemHandler() { val (x, y, z) = user.rotationVector world.spawnEntity(WitherSkullEntity(world, user, x, y, z).apply { - isCharged = Math.random() < 0.1f // TODO ratio + isCharged = charged setPosition(user.approximateStaffTipPosition) }) }