Skip to content

Commit e5630bf

Browse files
committed
ability activation and utils
1 parent 1730613 commit e5630bf

File tree

9 files changed

+154
-38
lines changed

9 files changed

+154
-38
lines changed

Diff for: src/main/kotlin/dev/sterner/api/VoidBoundApi.kt

+34-10
Original file line numberDiff line numberDiff line change
@@ -142,39 +142,63 @@ object VoidBoundApi {
142142
return false
143143
}
144144

145-
fun getItemAbility(stack: ItemStack): List<ItemAbility> {
146-
val abilities = mutableListOf<ItemAbility>()
145+
// Function to retrieve abilities from the ItemStack's NBT, returns a Set
146+
fun getItemAbilities(stack: ItemStack): Set<ItemAbility> {
147+
val abilities = mutableSetOf<ItemAbility>()
147148
val tag = stack.tag ?: return abilities // Return empty if no NBT
148149

149150
val abilitiesTag = tag.getList("Abilities", 10) // 10 is the NBT type for CompoundTag
150151
for (i in 0 until abilitiesTag.size) {
151152
val abilityTag = abilitiesTag.getCompound(i)
152153
val ability = ItemAbility.readNbt(abilityTag)
153-
abilities.add(ability)
154+
abilities.add(ability) // Add to the set, prevents duplicates
154155
}
156+
155157
return abilities
156158
}
157159

158-
// Function to add an ItemAbilityWithLevel to an ItemStack's NBT
159-
fun addItemAbility(stack: ItemStack, abilityWithLevel: ItemAbility) {
160+
// Function to add an ItemAbility to the ItemStack's NBT
161+
fun addItemAbility(stack: ItemStack, ability: ItemAbility, makeActive: Boolean = false) {
160162
val tag = stack.orCreateTag // Ensures the stack has NBT
161163
val abilitiesTag = tag.getList("Abilities", 10) // Fetch or create list
162164

163-
// Check if ability already exists, if so, skip adding a duplicate
165+
// Check if ability already exists, if so, exit
164166
for (i in 0 until abilitiesTag.size) {
165167
val abilityTag = abilitiesTag.getCompound(i)
166168
val existingAbility = ItemAbility.readNbt(abilityTag)
167-
if (existingAbility == abilityWithLevel) {
169+
if (existingAbility == ability) {
168170
return // Ability already exists, exit without adding
169171
}
170172
}
171173

172174
// Add new ability
173-
abilitiesTag.add(abilityWithLevel.writeNbt())
175+
abilitiesTag.add(ability.writeNbt())
174176
tag.put("Abilities", abilitiesTag)
177+
178+
// Optionally set the new ability as the active one
179+
if (makeActive) {
180+
setActiveAbility(stack, ability)
181+
}
182+
}
183+
184+
// Function to set the active ability in NBT
185+
fun setActiveAbility(stack: ItemStack, ability: ItemAbility) {
186+
val tag = stack.orCreateTag
187+
val abilities = getItemAbilities(stack)
188+
189+
if (abilities.contains(ability)) {
190+
// Store the active ability as a string in NBT
191+
tag.putString("ActiveAbility", ability.name)
192+
}
175193
}
176194

177-
fun hasItemAbility(stack: ItemStack, ability: ItemAbility): Boolean {
178-
return !getItemAbility(stack).none { it == ability }
195+
// Function to get the active ability from the ItemStack's NBT
196+
fun getActiveAbility(stack: ItemStack): ItemAbility? {
197+
val tag = stack.tag ?: return null
198+
val activeAbilityName = tag.getString("ActiveAbility")
199+
200+
// Check if the active ability is one of the stored abilities
201+
val abilities = getItemAbilities(stack)
202+
return abilities.firstOrNull { it.name == activeAbilityName }
179203
}
180204
}

Diff for: src/main/kotlin/dev/sterner/client/screen/ItemAbilityScreen.kt

+28-15
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,44 @@ import com.mojang.blaze3d.systems.RenderSystem
44
import dev.sterner.VoidBound
55
import dev.sterner.api.VoidBoundApi
66
import dev.sterner.api.item.ItemAbility
7+
import dev.sterner.networking.AbilityUpdatePacket
8+
import dev.sterner.registry.VoidBoundComponentRegistry
9+
import dev.sterner.registry.VoidBoundPacketRegistry
710
import net.minecraft.client.Minecraft
811
import net.minecraft.client.gui.GuiGraphics
912
import net.minecraft.client.gui.screens.Screen
1013
import net.minecraft.network.chat.Component
1114
import net.minecraft.world.item.ItemStack
12-
import kotlin.math.max
1315

1416
class ItemAbilityScreen(stack: ItemStack) : Screen(Component.literal("Ability Selection")) {
1517

1618
var focus: Boolean = false
1719
private var yOffset = 0f
1820
private var selection: Int = 0
1921
private var initialized = false
20-
var abilities: List<ItemAbility>? = null
22+
var abilities: Set<ItemAbility>? = null
2123

2224
private var w: Int = 0
2325
private var h: Int = 0
2426

2527
init {
2628
this.minecraft = Minecraft.getInstance()
27-
abilities = VoidBoundApi.getItemAbility(stack)
29+
2830
focus = false
2931
yOffset = 0f
3032
selection = 0
3133
initialized = false
3234

3335
w = 180
3436
h = 37
37+
abilities = VoidBoundComponentRegistry.VOID_BOUND_REVELATION_COMPONENT.get(minecraft!!.player!!).unlockedItemAbilities
3538
}
3639

3740
fun cycle(direction: Int) {
38-
selection += if ((direction < 0)) 1 else -1
39-
selection = (selection + abilities!!.size) % abilities!!.size
41+
if (abilities!!.isNotEmpty()) {
42+
selection += if ((direction < 0)) 1 else -1
43+
selection = (selection + abilities!!.size) % abilities!!.size
44+
}
4045
}
4146

4247
fun update() {
@@ -49,7 +54,7 @@ class ItemAbilityScreen(stack: ItemStack) : Screen(Component.literal("Ability Se
4954

5055
fun render(guiGraphics: GuiGraphics, partialTick: Float) {
5156

52-
if (abilities == null) {
57+
if (abilities?.isEmpty() == true) {
5358
return
5459
}
5560

@@ -59,7 +64,7 @@ class ItemAbilityScreen(stack: ItemStack) : Screen(Component.literal("Ability Se
5964
val y = mainWindow.guiScaledHeight - h + 20
6065

6166
matrixStack.pushPose()
62-
matrixStack.translate(0f, 20 - yOffset, (if (focus) 100 else 0).toFloat())
67+
matrixStack.translate(0f, 20 - yOffset, -100f)
6368

6469
val gray = VoidBound.id("textures/gui/ability_selection.png")
6570
RenderSystem.enableBlend()
@@ -82,39 +87,47 @@ class ItemAbilityScreen(stack: ItemStack) : Screen(Component.literal("Ability Se
8287

8388
val startX = (mainWindow.guiScaledWidth - totalWidth) / 2
8489

85-
for (i in abilities!!.indices) {
90+
for ((index, ability) in abilities!!.withIndex()) { // Loop through the Set directly
8691
RenderSystem.enableBlend()
8792
matrixStack.pushPose()
8893

8994
val alpha = if (focus) 1f else 0.2f
9095

91-
if (i == selection) {
92-
matrixStack.translate(0f, -10f, 0f)
96+
if (index == selection) {
97+
matrixStack.translate(0f, -10f, 0f) // Move selected ability
9398
} else {
94-
matrixStack.translate(0f, -5f, 0f)
99+
matrixStack.translate(0f, -5f, 0f) // Move unselected abilities
95100
}
96101

97102
RenderSystem.setShaderColor(1f, 1f, 1f, alpha)
98103

99-
val abilityX = startX + i * abilityWidth
104+
val abilityX = startX + index * abilityWidth
100105

101-
if (i == selection) {
106+
if (index == selection) {
102107
guiGraphics.drawCenteredString(
103108
minecraft!!.font,
104-
abilities!![i].name.lowercase().replaceFirstChar { it.uppercase() },
109+
ability.name.lowercase().replaceFirstChar { it.uppercase() }, // Access ability directly
105110
abilityX + 24,
106111
y + 32,
107112
0xDDCCFF
108113
)
109114
}
110115

111-
val texture = VoidBound.id("textures/gui/" + abilities!![i].name.lowercase() + ".png")
116+
val texture = VoidBound.id("textures/gui/" + ability.name.lowercase() + ".png")
112117
guiGraphics.blit(texture, abilityX + 16, y + 16, 0, 0f, 0f, 16, 16, 16, 16)
113118

114119
matrixStack.popPose()
120+
121+
// Increment index manually
115122
}
116123

117124
RenderSystem.disableBlend()
118125
matrixStack.popPose()
119126
}
127+
128+
override fun onClose() {
129+
if (Minecraft.getInstance().player != null && abilities!!.elementAtOrNull(selection) != null) {
130+
VoidBoundPacketRegistry.VOID_BOUND_CHANNEL.sendToServer(AbilityUpdatePacket(Minecraft.getInstance().player!!.uuid, abilities!!.elementAt(selection)))
131+
}
132+
}
120133
}

Diff for: src/main/kotlin/dev/sterner/common/ItemAbilityHandler.kt

+18-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dev.sterner.common
22

3+
import dev.sterner.VoidBound
34
import dev.sterner.api.item.ItemAbility
45
import dev.sterner.client.screen.ItemAbilityScreen
56
import net.minecraft.client.Minecraft
@@ -11,10 +12,14 @@ import org.lwjgl.glfw.GLFW
1112

1213
class ItemAbilityHandler {
1314

14-
var selectionScreen: ItemAbilityScreen = ItemAbilityScreen(ItemStack.EMPTY)
15+
var selectionScreen: ItemAbilityScreen? = null
1516
var currentAbility: ItemAbility? = ItemAbility.NONE
1617
var active: Boolean = false
1718

19+
init {
20+
currentAbility = ItemAbility.NONE
21+
22+
}
1823

1924
fun tick() {
2025
val mc = Minecraft.getInstance()
@@ -25,6 +30,9 @@ class ItemAbilityHandler {
2530
return
2631
}
2732
val player = mc.player
33+
if (player != null && selectionScreen == null) {
34+
selectionScreen = ItemAbilityScreen(player.mainHandItem)
35+
}
2836
val stack = player?.mainHandItem
2937
if (stack == null) {
3038
active = false
@@ -35,15 +43,15 @@ class ItemAbilityHandler {
3543
return
3644
}
3745

38-
selectionScreen.update()
46+
selectionScreen?.update()
3947
}
4048

4149
fun render(graphics: GuiGraphics, partialTicks: Float, width: Int, height: Int) {
4250
if (Minecraft.getInstance().options.hideGui || !active) {
4351
return
4452
}
4553

46-
selectionScreen.render(graphics, partialTicks)
54+
selectionScreen?.render(graphics, partialTicks)
4755
}
4856

4957
private fun init(player: LocalPlayer?) {
@@ -59,12 +67,12 @@ class ItemAbilityHandler {
5967
return
6068
}
6169

62-
if (pressed && !selectionScreen.focus) {
63-
selectionScreen.focus = true
70+
if (pressed && selectionScreen?.focus != true) {
71+
selectionScreen?.focus = true
6472
}
65-
if (!pressed && selectionScreen.focus) {
66-
selectionScreen.focus = false
67-
selectionScreen.onClose()
73+
if (!pressed && selectionScreen?.focus == true) {
74+
selectionScreen!!.focus = false
75+
selectionScreen!!.onClose()
6876
}
6977
}
7078

@@ -73,8 +81,8 @@ class ItemAbilityHandler {
7381
return false
7482
}
7583

76-
if (selectionScreen.focus) {
77-
selectionScreen.cycle(delta.toInt())
84+
if (selectionScreen?.focus == true) {
85+
selectionScreen?.cycle(delta.toInt())
7886
return true
7987
}
8088
return false

Diff for: src/main/kotlin/dev/sterner/common/VoidBoundLootModifier.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class VoidBoundLootModifier(conditionsIn: Array<out LootItemCondition>?) : LootM
3131
): ObjectArrayList<ItemStack> {
3232

3333
val stack = context?.getParamOrNull(LootContextParams.TOOL)
34-
if (stack != null && VoidBoundApi.hasItemAbility(stack, ItemAbility.AUTOSMELT)) {
34+
if (stack != null && VoidBoundApi.getActiveAbility(stack) == ItemAbility.AUTOSMELT) {
3535

3636
val level = context.level
3737
val smeltedItems = generatedLoot?.asSequence()?.map { originalStack ->

Diff for: src/main/kotlin/dev/sterner/common/components/VoidBoundRevelationComponent.kt

+26
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package dev.sterner.common.components
22

33
import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent
44
import dev.onyxstudios.cca.api.v3.component.tick.CommonTickingComponent
5+
import dev.sterner.api.VoidBoundApi
6+
import dev.sterner.api.item.ItemAbility
57
import dev.sterner.registry.VoidBoundComponentRegistry
68
import dev.sterner.registry.VoidBoundSoundEvents
79
import net.minecraft.nbt.CompoundTag
@@ -15,6 +17,13 @@ class VoidBoundRevelationComponent(private val player: Player) : AutoSyncedCompo
1517

1618
var thoughtsQueue: MutableMap<Component, ThoughtData> = mutableMapOf()
1719

20+
var unlockedItemAbilities = mutableSetOf<ItemAbility>(ItemAbility.VAMPIRISM, ItemAbility.AUTOSMELT)
21+
22+
fun addUnlockedItemAbility(ability: ItemAbility) {
23+
unlockedItemAbilities.add(ability)
24+
sync()
25+
}
26+
1827
override fun tick() {
1928
// Ensure the queue does not exceed 16 elements
2029
while (thoughtsQueue.size > 16) {
@@ -140,6 +149,15 @@ class VoidBoundRevelationComponent(private val player: Player) : AutoSyncedCompo
140149
thoughtsQueue[thought] = ThoughtData(duration, delay)
141150
}
142151
}
152+
153+
unlockedItemAbilities.clear()
154+
val unlockedList = tag.getList("UnlockedItems", 10)
155+
for (i in 0 until unlockedList.size) {
156+
val item = unlockedList.getCompound(i)
157+
val itemAbility = ItemAbility.readNbt(item)
158+
println("TT: $itemAbility")
159+
unlockedItemAbilities.add(itemAbility)
160+
}
143161
}
144162

145163
override fun writeToNbt(tag: CompoundTag) {
@@ -164,5 +182,13 @@ class VoidBoundRevelationComponent(private val player: Player) : AutoSyncedCompo
164182
thoughtsList.add(thoughtTag)
165183
}
166184
tag.put("ThoughtsQueue", thoughtsList)
185+
186+
val unlockedList = ListTag()
187+
unlockedItemAbilities.forEach { unlockedTag ->
188+
println(unlockedTag)
189+
val abilityTag = unlockedTag.writeNbt()
190+
unlockedList.add(abilityTag)
191+
}
192+
tag.put("UnlockedItems", unlockedList)
167193
}
168194
}

Diff for: src/main/kotlin/dev/sterner/common/item/tool/ichor/IchoriumPickaxeItem.kt

+5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package dev.sterner.common.item.tool.ichor
22

3+
import dev.sterner.api.item.ItemAbility
34
import dev.sterner.common.item.tool.CragbreakerItem
5+
import dev.sterner.registry.VoidBoundComponentRegistry
46
import net.minecraft.ChatFormatting
57
import net.minecraft.network.chat.Component
68
import net.minecraft.network.chat.Style
9+
import net.minecraft.world.InteractionHand
10+
import net.minecraft.world.InteractionResultHolder
11+
import net.minecraft.world.entity.player.Player
712
import net.minecraft.world.item.ItemStack
813
import net.minecraft.world.item.Tier
914
import net.minecraft.world.item.TooltipFlag
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package dev.sterner.networking
2+
3+
import dev.sterner.api.VoidBoundApi
4+
import dev.sterner.api.item.ItemAbility
5+
import me.pepperbell.simplenetworking.SimpleChannel
6+
import net.fabricmc.fabric.api.networking.v1.PacketSender
7+
import net.minecraft.network.FriendlyByteBuf
8+
import net.minecraft.server.MinecraftServer
9+
import net.minecraft.server.level.ServerPlayer
10+
import net.minecraft.server.network.ServerGamePacketListenerImpl
11+
import team.lodestar.lodestone.systems.network.LodestoneServerPacket
12+
import java.util.UUID
13+
14+
class AbilityUpdatePacket(val uuid: UUID, val itemAbility: ItemAbility) : LodestoneServerPacket() {
15+
16+
override fun encode(buf: FriendlyByteBuf) {
17+
buf.writeUUID(uuid)
18+
buf.writeUtf(itemAbility.name)
19+
}
20+
21+
constructor(buf: FriendlyByteBuf) : this(buf.readUUID(), ItemAbility.valueOf(buf.readUtf()))
22+
23+
24+
override fun executeServer(
25+
server: MinecraftServer?,
26+
player: ServerPlayer?,
27+
listener: ServerGamePacketListenerImpl?,
28+
responseSender: PacketSender?,
29+
channel: SimpleChannel?
30+
) {
31+
server?.execute {
32+
if (player?.uuid == uuid) {
33+
val item = player.mainHandItem
34+
VoidBoundApi.addItemAbility(item, itemAbility, true)
35+
}
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)