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 }}
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..a84dc8068
--- /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, 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, false)
+ (attacker as? PlayerEntity)?.resetLastAttackedTicks()
+ return ActionResult.SUCCESS
+ }
+
+ private fun shootSkull(world: World, user: LivingEntity, charged: Boolean) {
+ 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 = charged
+ 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"
+ }
+ ]
+}
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"