proper enchanting screen

This commit is contained in:
Bixilon 2022-05-17 18:03:21 +02:00
parent 899b838b2c
commit 56a6a3c821
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
9 changed files with 85 additions and 14 deletions

View File

@ -43,6 +43,7 @@ open class Container(
@Deprecated("Should not be accessed directly")
val slots: MutableMap<Int, ItemStack> by watchedMap(mutableMapOf())
val lock = SimpleLock()
var propertiesRevision by watched(0L)
var revision by watched(0L)
var serverRevision = 0
private var lastActionId = 0

View File

@ -22,6 +22,7 @@ import de.bixilon.minosoft.data.container.slots.SlotType
import de.bixilon.minosoft.data.container.stack.ItemStack
import de.bixilon.minosoft.data.registries.MultiResourceLocationAble
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.enchantment.Enchantment
import de.bixilon.minosoft.data.registries.items.DefaultItems
import de.bixilon.minosoft.data.registries.other.containers.ContainerFactory
import de.bixilon.minosoft.data.registries.other.containers.ContainerType
@ -29,8 +30,13 @@ import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.util.KUtil.toResourceLocation
class EnchantingContainer(connection: PlayConnection, type: ContainerType, title: ChatComponent?) : InventorySynchronizedContainer(connection, type, title, (ENCHANTING_SLOTS + 1)..(ENCHANTING_SLOTS + PlayerInventory.MAIN_SLOTS)) {
class EnchantingContainer(connection: PlayConnection, type: ContainerType, title: ChatComponent?) : InventorySynchronizedContainer(connection, type, title, ENCHANTING_SLOTS until (ENCHANTING_SLOTS + PlayerInventory.MAIN_SLOTS)) {
override val sections: Array<IntRange> = arrayOf(0 until ENCHANTING_SLOTS, ENCHANTING_SLOTS until ENCHANTING_SLOTS + PlayerInventory.MAIN_SLOTS)
val costs = IntArray(ENCHANTING_OPTIONS) { -1 }
val enchantments: Array<Enchantment?> = arrayOfNulls(ENCHANTING_OPTIONS)
var enchantmentLevels = IntArray(ENCHANTING_OPTIONS) { -1 }
var seed = -1
private set
override fun getSlotType(slotId: Int): SlotType? {
return when (slotId) {
@ -58,6 +64,15 @@ class EnchantingContainer(connection: PlayConnection, type: ContainerType, title
return 1 + ENCHANTING_SLOTS + PlayerInventory.MAIN_SLOTS_PER_ROW * 3 + slot.ordinal
}
override fun readProperty(property: Int, value: Int) {
when (property) {
0, 1, 2 -> costs[property] = value
3 -> seed = value
4, 5, 6 -> enchantments[property - 4] = connection.registries.enchantmentRegistry.getOrNull(value)
7, 8, 9 -> enchantmentLevels[property - 7] = value
}
}
private object LapislazuliSlot : SlotType {
override fun canPut(container: Container, slot: Int, stack: ItemStack): Boolean {
return stack.item.item.resourceLocation == DefaultItems.LAPISLAZULI
@ -68,7 +83,9 @@ class EnchantingContainer(connection: PlayConnection, type: ContainerType, title
companion object : ContainerFactory<EnchantingContainer>, MultiResourceLocationAble {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:enchantment".toResourceLocation()
override val ALIASES: Set<ResourceLocation> = setOf("minecraft:enchanting_table".toResourceLocation(), "EnchantTable".toResourceLocation())
const val LAPISLAZULI_SLOT = 1
const val ENCHANTING_SLOTS = 2
const val ENCHANTING_OPTIONS = 3
override fun build(connection: PlayConnection, type: ContainerType, title: ChatComponent?): EnchantingContainer {
return EnchantingContainer(connection, type, title)

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020 Moritz Zwerger
* Copyright (C) 2020-2022 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -54,6 +54,13 @@ open class ResourceLocation(
return full
}
fun toMinifiedString(): String {
if (namespace == ProtocolDefinition.DEFAULT_NAMESPACE) {
return path
}
return toString()
}
companion object {
val String.namespace: String
get() {

View File

@ -37,7 +37,7 @@ abstract class AbstractButtonElement(
text: Any,
disabled: Boolean = false,
) : Element(guiRenderer) {
protected val textElement = TextElement(guiRenderer, text, background = false).apply { parent = this@AbstractButtonElement }
protected val textElement = TextElement(guiRenderer, text, background = false, parent = this)
protected abstract val disabledAtlas: AtlasElement?
protected abstract val normalAtlas: AtlasElement?
protected abstract val hoveredAtlas: AtlasElement?

View File

@ -14,6 +14,8 @@
package de.bixilon.minosoft.gui.rendering.gui.gui.screen.container.enchanting
import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kutil.watcher.DataWatcher.Companion.observe
import de.bixilon.minosoft.data.abilities.Gamemodes
import de.bixilon.minosoft.data.container.types.EnchantingContainer
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
@ -27,8 +29,14 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation
import kotlin.reflect.KClass
class EnchantingContainerScreen(guiRenderer: GUIRenderer, container: EnchantingContainer) : LabeledContainerScreen<EnchantingContainer>(guiRenderer, container, guiRenderer.atlasManager["minecraft:enchanting_container".toResourceLocation()]) {
private val cards: Array<EnchantmentButtonElement> = Array(CARDS) { EnchantmentButtonElement(guiRenderer, this, guiRenderer.atlasManager["minecraft:level_requirement_${it}"], guiRenderer.atlasManager["minecraft:level_requirement_${it}_disabled"]) }
private val cardAreas = arrayOf(atlasElement?.areas?.get("card_0"), atlasElement?.areas?.get("card_1"), atlasElement?.areas?.get("card_2"))
private val cards: Array<EnchantmentButtonElement> = Array(EnchantingContainer.ENCHANTING_OPTIONS) { EnchantmentButtonElement(guiRenderer, this, guiRenderer.atlasManager["minecraft:level_requirement_${it}"], guiRenderer.atlasManager["minecraft:level_requirement_${it}_disabled"], it) }
private val cardAreas = Array(EnchantingContainer.ENCHANTING_OPTIONS) { atlasElement?.areas?.get("card_$it") }
init {
container::propertiesRevision.observe(this) { forceApply() }
container::revision.observe(this) { forceApply() }
}
override fun forceRenderContainerScreen(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
super.forceRenderContainerScreen(offset, consumer, options)
@ -56,9 +64,21 @@ class EnchantingContainerScreen(guiRenderer: GUIRenderer, container: EnchantingC
return super.getContainerAt(position)
}
override fun forceSilentApply() {
super.forceSilentApply()
var lapisCount = container[EnchantingContainer.LAPISLAZULI_SLOT]?.item?._count ?: 0
if (guiRenderer.connection.player.gamemode == Gamemodes.CREATIVE) {
lapisCount = 64
}
for (index in 0 until EnchantingContainer.ENCHANTING_OPTIONS) {
val card = cards[index]
card.update(lapisCount < index + 1, container.costs[index], container.enchantments[index], container.enchantmentLevels[index])
}
}
companion object : ContainerGUIFactory<EnchantingContainerScreen, EnchantingContainer> {
override val clazz: KClass<EnchantingContainer> = EnchantingContainer::class
const val CARDS = 3
override fun build(guiRenderer: GUIRenderer, container: EnchantingContainer): EnchantingContainerScreen {
return EnchantingContainerScreen(guiRenderer, container)

View File

@ -14,31 +14,46 @@
package de.bixilon.minosoft.gui.rendering.gui.gui.screen.container.enchanting
import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.minosoft.data.registries.enchantment.Enchantment
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.AtlasElement
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.VerticalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.VerticalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.input.button.AbstractButtonElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.protocol.packets.c2s.play.container.ContainerButtonC2SP
class EnchantmentButtonElement(
guiRenderer: GUIRenderer,
val container: EnchantingContainerScreen,
val levelAtlas: AtlasElement?,
val disabledLevelAtlas: AtlasElement?,
) : AbstractButtonElement(guiRenderer, "< text >", true) {
val index: Int,
) : AbstractButtonElement(guiRenderer, "", true) {
override val disabledAtlas = guiRenderer.atlasManager["enchanting_table_card_disabled"]
override val normalAtlas = guiRenderer.atlasManager["enchanting_table_card_normal"]
override val hoveredAtlas = guiRenderer.atlasManager["enchanting_table_card_hovered"]
private val levelText = TextElement(guiRenderer, ChatComponent.EMPTY, background = false)
override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
super.forceRender(offset, consumer, options)
val level = AtlasImageElement(guiRenderer, if (disabled) disabledLevelAtlas else levelAtlas)
val size = size
level.render(offset + Vec2i(5, HorizontalAlignments.CENTER.getOffset(size.y, level.size.y)), consumer, options)
level.render(offset + Vec2i(5, VerticalAlignments.CENTER.getOffset(size.y, level.size.y)), consumer, options)
if (!_disabled) {
levelText.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(size.x, levelText.size.x) - 3, VerticalAlignments.BOTTOM.getOffset(size.y, levelText.size.y) - 2), consumer, options)
}
}
init {
@ -48,6 +63,15 @@ class EnchantmentButtonElement(
}
override fun submit() {
TODO("Not yet implemented")
container.container.id?.let { guiRenderer.connection.network.send(ContainerButtonC2SP(it, index)) }
}
fun update(disabled: Boolean, cost: Int, enchantment: Enchantment?, level: Int) {
_disabled = disabled || cost <= 0
levelText.text = TextComponent(cost).color(RenderConstants.EXPERIENCE_BAR_LEVEL_COLOR)
textElement._chatComponent = if (enchantment == null) ChatComponent.EMPTY else TextComponent(enchantment.resourceLocation.toMinifiedString() + " $level").color(ChatColors.BLUE)
textElement.forceSilentApply()
forceSilentApply()
}
}

View File

@ -21,8 +21,8 @@ import de.bixilon.minosoft.util.logging.LogMessageType
@LoadPacket
class ContainerButtonC2SP(
private val containerId: Byte,
private val buttonId: Byte, // up, middle, bottom (0, 1, 2); in later versions: lectern page, etc
private val containerId: Int,
private val buttonId: Int,
) : PlayC2SPacket {
override fun write(buffer: PlayOutByteBuffer) {

View File

@ -20,14 +20,16 @@ import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
@LoadPacket
@LoadPacket(threadSafe = false)
class ContainerPropertiesS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
val containerId = buffer.readUnsignedByte()
val property = buffer.readUnsignedShort()
val value = buffer.readUnsignedShort()
override fun handle(connection: PlayConnection) {
connection.player.containers[containerId]?.readProperty(property, value)
val container = connection.player.containers[containerId] ?: return
container.readProperty(property, value)
container.propertiesRevision++
}
override fun log(reducedLog: Boolean) {

View File

@ -29,7 +29,7 @@ import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
@LoadPacket
@LoadPacket(threadSafe = false)
class OpenContainerS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
val containerId = if (buffer.versionId <= V_1_14) { // ToDo: This is completely guessed, it has changed between 1.13 and 1.14, same as #L38
buffer.readUnsignedByte()