mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-12 17:07:55 -04:00
improved item interaction, fix entity meta data receiving
This commit is contained in:
parent
35733d907f
commit
397cfd916c
@ -84,7 +84,7 @@ abstract class Entity(
|
||||
protected val versionId: Int = connection.version.versionId
|
||||
open var attachedEntity: Int? = null
|
||||
|
||||
var entityMetaData: EntityMetaData = EntityMetaData(connection)
|
||||
val entityMetaData: EntityMetaData = EntityMetaData(connection)
|
||||
var vehicle: Entity? = null
|
||||
var passengers: MutableSet<Entity> = synchronizedSetOf()
|
||||
|
||||
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 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.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.registries.items
|
||||
|
||||
import de.bixilon.minosoft.data.abilities.Gamemodes
|
||||
import de.bixilon.minosoft.data.inventory.ItemStack
|
||||
import de.bixilon.minosoft.data.player.Hands
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
||||
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar.HotbarHungerElement
|
||||
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.util.KUtil.decide
|
||||
import de.bixilon.minosoft.util.KUtil.toBoolean
|
||||
import de.bixilon.minosoft.util.KUtil.toFloat
|
||||
import de.bixilon.minosoft.util.KUtil.toInt
|
||||
import de.bixilon.minosoft.util.logging.Log
|
||||
import de.bixilon.minosoft.util.logging.LogLevels
|
||||
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||
|
||||
open class FoodItem(
|
||||
resourceLocation: ResourceLocation,
|
||||
registries: Registries,
|
||||
data: Map<String, Any>,
|
||||
) : Item(resourceLocation, registries, data), UsableItem {
|
||||
val nutrition: Int
|
||||
val saturationModifier: Float
|
||||
val isMeat: Boolean
|
||||
val alwaysEdiable: Boolean
|
||||
val timeToEat: Int
|
||||
|
||||
init {
|
||||
val foodProperties = data["food_properties"].asCompound()
|
||||
nutrition = foodProperties["nutrition"]?.toInt() ?: 0
|
||||
saturationModifier = foodProperties["saturation_modifier"]?.toFloat() ?: 0.0f
|
||||
isMeat = foodProperties["is_meat"]?.toBoolean() ?: false
|
||||
alwaysEdiable = foodProperties["can_always_eat"]?.toBoolean() ?: false
|
||||
timeToEat = foodProperties["time_to_eat"]?.toInt() ?: foodProperties["fast_food"]?.toBoolean()?.decide(16, 32) ?: 100
|
||||
}
|
||||
|
||||
override val maxUseTime: Int = timeToEat
|
||||
|
||||
override fun interactItem(connection: PlayConnection, hand: Hands, itemStack: ItemStack): InteractionResults {
|
||||
val hunger = connection.player.healthCondition.hunger
|
||||
if (hunger < HotbarHungerElement.MAX_HUNGER || alwaysEdiable) {
|
||||
connection.player.useItem(hand)
|
||||
}
|
||||
return InteractionResults.CONSUME
|
||||
}
|
||||
|
||||
override fun finishUsing(connection: PlayConnection, itemStack: ItemStack) {
|
||||
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Finished eating: $timeToEat" }
|
||||
if (connection.player.gamemode != Gamemodes.CREATIVE) {
|
||||
itemStack.count--
|
||||
}
|
||||
// ToDo: Apply eating effect(s)
|
||||
}
|
||||
}
|
@ -81,7 +81,7 @@ open class Item(
|
||||
return InteractionResults.PASS
|
||||
}
|
||||
|
||||
open fun interactItem(connection: PlayConnection, hand: Hands, itemStack: ItemStack, ticks: Int): InteractionResults {
|
||||
open fun interactItem(connection: PlayConnection, hand: Hands, itemStack: ItemStack): InteractionResults {
|
||||
return InteractionResults.PASS
|
||||
}
|
||||
|
||||
@ -90,6 +90,9 @@ open class Item(
|
||||
|
||||
override fun deserialize(registries: Registries?, resourceLocation: ResourceLocation, data: Map<String, Any>): Item {
|
||||
check(registries != null) { "Registries is null!" }
|
||||
if (data["food_properties"] != null) {
|
||||
return FoodItem(resourceLocation, registries, data)
|
||||
}
|
||||
return when (val `class` = data["class"].unsafeCast<String>()) {
|
||||
"BlockItem" -> BlockItem(resourceLocation, registries, data)
|
||||
"Item", "AirBlockItem" -> Item(resourceLocation, registries, data)
|
||||
|
@ -24,9 +24,10 @@ open class ShieldItem(
|
||||
resourceLocation: ResourceLocation,
|
||||
registries: Registries,
|
||||
data: Map<String, Any>,
|
||||
) : Item(resourceLocation, registries, data) {
|
||||
) : Item(resourceLocation, registries, data), UsableItem {
|
||||
override val maxUseTime: Int = Int.MAX_VALUE
|
||||
|
||||
override fun interactItem(connection: PlayConnection, hand: Hands, itemStack: ItemStack, ticks: Int): InteractionResults {
|
||||
override fun interactItem(connection: PlayConnection, hand: Hands, itemStack: ItemStack): InteractionResults {
|
||||
connection.player.useItem(hand)
|
||||
return InteractionResults.CONSUME
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 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.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.registries.items
|
||||
|
||||
import de.bixilon.minosoft.data.inventory.ItemStack
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
|
||||
interface UsableItem {
|
||||
val maxUseTime: Int
|
||||
|
||||
fun finishUsing(connection: PlayConnection, itemStack: ItemStack) {}
|
||||
}
|
@ -222,7 +222,7 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : AbstractHotbarHealthElemen
|
||||
val wither = witherStatusEffect?.let { player.activeStatusEffects[it] != null } ?: false
|
||||
val frozen = player.ticksFrozen > 0
|
||||
|
||||
val absorptionsAmount = max(0.0f, player.playerAbsorptionHearts) // ToDo: This is (probably) calculated as effect instance
|
||||
val absorptionsAmount = max(0.0f, player.playerAbsorptionHearts)
|
||||
|
||||
val maxHealth = max(0.0f, player.getAttributeValue(DefaultStatusEffectAttributeNames.GENERIC_MAX_HEALTH).toFloat())
|
||||
|
||||
|
@ -160,7 +160,7 @@ class HotbarHungerElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Poll
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAX_HUNGER = 20
|
||||
const val MAX_HUNGER = 20
|
||||
private const val HUNGER_CONTAINERS = MAX_HUNGER / 2
|
||||
private val HUNGER_SIZE = Vec2i(8, 9)
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ import glm_.vec2.Vec2i
|
||||
|
||||
class BreakProgressHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TextElement>(hudRenderer), Drawable {
|
||||
override val layout: TextElement = TextElement(hudRenderer, "")
|
||||
private val leftClickHandler = hudRenderer.renderWindow.inputHandler.leftClickHandler
|
||||
private val breakInteractionHandler = hudRenderer.renderWindow.inputHandler.interactionManager.`break`
|
||||
|
||||
override val layoutOffset: Vec2i
|
||||
get() = Vec2i((hudRenderer.scaledSize.x / 2) + CrosshairHUDElement.CROSSHAIR_SIZE / 2 + 5, (hudRenderer.scaledSize.y - layout.size.y) / 2)
|
||||
@ -34,13 +34,13 @@ class BreakProgressHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<Tex
|
||||
private var percent = -1
|
||||
|
||||
override fun draw() {
|
||||
val breakProgress = leftClickHandler.breakProgress
|
||||
val breakProgress = breakInteractionHandler.breakProgress
|
||||
if (breakProgress <= 0 || breakProgress >= 1.0) {
|
||||
layout.text = ""
|
||||
this.percent = -1
|
||||
return
|
||||
}
|
||||
val percent = (leftClickHandler.breakProgress * 100).toInt()
|
||||
val percent = (breakInteractionHandler.breakProgress * 100).toInt()
|
||||
if (percent == this.percent) {
|
||||
return
|
||||
}
|
||||
|
@ -18,6 +18,4 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
@Deprecated("TODO")
|
||||
class AttackInteractionHandler(
|
||||
val renderWindow: RenderWindow,
|
||||
) {
|
||||
val isBreakingBlock: Boolean = false
|
||||
}
|
||||
)
|
||||
|
@ -11,7 +11,7 @@
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.input
|
||||
package de.bixilon.minosoft.gui.rendering.input.interaction
|
||||
|
||||
import de.bixilon.minosoft.config.key.KeyAction
|
||||
import de.bixilon.minosoft.config.key.KeyBinding
|
||||
@ -35,8 +35,7 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import glm_.pow
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
@Deprecated("Will be integrated in the InteractionManager")
|
||||
class LeftClickHandler(
|
||||
class BreakInteractionHandler(
|
||||
val renderWindow: RenderWindow,
|
||||
) {
|
||||
private val connection = renderWindow.connection
|
||||
@ -45,7 +44,8 @@ class LeftClickHandler(
|
||||
private var breakBlockState: BlockState? = null
|
||||
var breakProgress = Double.NEGATIVE_INFINITY
|
||||
private set
|
||||
|
||||
val breakingBlock: Boolean
|
||||
get() = breakPosition != null
|
||||
|
||||
private var breakSelectedSlot: Int = -1
|
||||
private var breakItemInHand: ItemStack? = null
|
@ -19,6 +19,7 @@ import de.bixilon.minosoft.config.key.KeyCodes
|
||||
import de.bixilon.minosoft.data.abilities.Gamemodes
|
||||
import de.bixilon.minosoft.data.inventory.ItemStack
|
||||
import de.bixilon.minosoft.data.player.Hands
|
||||
import de.bixilon.minosoft.data.registries.items.UsableItem
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
|
||||
import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit
|
||||
@ -41,7 +42,7 @@ class InteractInteractionHandler(
|
||||
|
||||
private var interactingItem: ItemStack? = null
|
||||
private var interactingSlot: Int = -1
|
||||
private var interactingTicks = 0
|
||||
private var interactingTicksLeft = 0
|
||||
|
||||
private var previousDown = false
|
||||
private var autoInteractionDelay = 0
|
||||
@ -66,7 +67,7 @@ class InteractInteractionHandler(
|
||||
connection.sendPacket(PlayerActionC2SP(PlayerActionC2SP.Actions.RELEASE_ITEM))
|
||||
interactingItem = null
|
||||
interactingSlot = -1
|
||||
interactingTicks = 0
|
||||
interactingTicksLeft = 0
|
||||
}
|
||||
|
||||
fun interactBlock(hit: BlockRaycastHit, item: ItemStack?, hand: Hands): InteractionResults {
|
||||
@ -118,7 +119,7 @@ class InteractInteractionHandler(
|
||||
return InteractionResults.PASS
|
||||
}
|
||||
|
||||
fun interactItem(item: ItemStack, hand: Hands, ticks: Int): InteractionResults {
|
||||
fun interactItem(item: ItemStack, hand: Hands): InteractionResults {
|
||||
if (connection.player.gamemode == Gamemodes.SPECTATOR) {
|
||||
return InteractionResults.SUCCESS
|
||||
}
|
||||
@ -133,11 +134,11 @@ class InteractInteractionHandler(
|
||||
}
|
||||
|
||||
|
||||
return item.item.interactItem(connection, hand, item, ticks)
|
||||
return item.item.interactItem(connection, hand, item)
|
||||
}
|
||||
|
||||
fun useItem() {
|
||||
if (interactionManager.attack.isBreakingBlock) {
|
||||
if (interactionManager.`break`.breakingBlock) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -180,14 +181,19 @@ class InteractInteractionHandler(
|
||||
if (item != interactingItem || interactingSlot != selectedSlot) {
|
||||
interactingItem = item
|
||||
interactingSlot = selectedSlot
|
||||
interactingTicks = 0
|
||||
val itemType = item?.item
|
||||
interactingTicksLeft = if (itemType is UsableItem) {
|
||||
itemType.maxUseTime
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
if (item == null) {
|
||||
continue
|
||||
}
|
||||
|
||||
val result = interactItem(item, hand, interactingTicks++)
|
||||
val result = interactItem(item, hand)
|
||||
|
||||
if (result == InteractionResults.SUCCESS) {
|
||||
interactionManager.swingHand(hand)
|
||||
@ -209,11 +215,22 @@ class InteractInteractionHandler(
|
||||
val keyDown = renderWindow.inputHandler.isKeyBindingDown(USE_ITEM_KEYBINDING)
|
||||
if (keyDown) {
|
||||
autoInteractionDelay++
|
||||
|
||||
val interactingItem = interactingItem
|
||||
val item = interactingItem?.item
|
||||
if (item is UsableItem) {
|
||||
interactingTicksLeft--
|
||||
if (interactingTicksLeft < 0) {
|
||||
item.finishUsing(connection, interactingItem)
|
||||
stopUsingItem()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
interactingTicksLeft = 0
|
||||
autoInteractionDelay = 0
|
||||
stopUsingItem()
|
||||
}
|
||||
if (keyDown && (!previousDown || autoInteractionDelay >= 5)) {
|
||||
if (keyDown && (!previousDown || (autoInteractionDelay >= 5 && interactingTicksLeft <= 0))) {
|
||||
useItem()
|
||||
autoInteractionDelay = 0
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ class InteractionManager(
|
||||
val hotbar = HotbarInteractionHandler(renderWindow)
|
||||
val pick = ItemPickInteractionHandler(renderWindow, this)
|
||||
val attack = AttackInteractionHandler(renderWindow)
|
||||
val `break` = BreakInteractionHandler(renderWindow)
|
||||
val use = InteractInteractionHandler(renderWindow, this)
|
||||
|
||||
private val swingArmRateLimiter = RateLimiter()
|
||||
@ -35,6 +36,7 @@ class InteractionManager(
|
||||
fun init() {
|
||||
hotbar.init()
|
||||
pick.init()
|
||||
`break`.init()
|
||||
use.init()
|
||||
}
|
||||
|
||||
@ -42,6 +44,7 @@ class InteractionManager(
|
||||
hotbar.draw(delta)
|
||||
pick.draw(delta)
|
||||
// attack.draw(delta)
|
||||
`break`.draw(delta)
|
||||
use.draw(delta)
|
||||
|
||||
swingArmRateLimiter.work()
|
||||
|
@ -20,7 +20,6 @@ import de.bixilon.minosoft.config.key.KeyCodes
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.input.LeftClickHandler
|
||||
import de.bixilon.minosoft.gui.rendering.input.camera.Camera
|
||||
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionManager
|
||||
import de.bixilon.minosoft.gui.rendering.modding.events.input.MouseMoveEvent
|
||||
@ -47,7 +46,6 @@ class RenderWindowInputHandler(
|
||||
private var skipNextCharPress = false
|
||||
|
||||
val interactionManager = InteractionManager(renderWindow)
|
||||
val leftClickHandler = LeftClickHandler(renderWindow)
|
||||
|
||||
init {
|
||||
registerKeyCallback("minosoft:debug_mouse_catch".toResourceLocation(), KeyBinding(
|
||||
@ -62,7 +60,6 @@ class RenderWindowInputHandler(
|
||||
}
|
||||
|
||||
fun init() {
|
||||
leftClickHandler.init()
|
||||
interactionManager.init()
|
||||
|
||||
connection.registerEvent(CallbackEventInvoker.of<RawCharInputEvent> { charInput(it.char) })
|
||||
@ -269,7 +266,6 @@ class RenderWindowInputHandler(
|
||||
|
||||
fun draw(delta: Double) {
|
||||
camera.draw()
|
||||
leftClickHandler.draw(delta)
|
||||
|
||||
interactionManager.draw(delta)
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class EntityMetadataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
override fun handle(connection: PlayConnection) {
|
||||
val entity = connection.world.entities[entityId] ?: return
|
||||
|
||||
entity.entityMetaData = metaData
|
||||
entity.entityMetaData.sets.putAll(metaData.sets)
|
||||
connection.fireEvent(EntityMetaDataChangeEvent(connection, this))
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ class MobSpawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
entity = entityType.build(buffer.connection, position, rotation, metaData, buffer.versionId)!!
|
||||
entity.velocity = velocity
|
||||
metaData?.let {
|
||||
entity.entityMetaData = it
|
||||
entity.entityMetaData.sets.putAll(it.sets)
|
||||
if (RunConfiguration.VERBOSE_ENTITY_META_DATA_LOGGING) {
|
||||
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Entity meta data(entityId=$entityId): ${entity.entityMetaDataAsString}" }
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ class PlayerEntitySpawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
)
|
||||
|
||||
if (metaData != null) {
|
||||
entity.entityMetaData = metaData
|
||||
entity.entityMetaData.sets.putAll(metaData.sets)
|
||||
if (RunConfiguration.VERBOSE_ENTITY_META_DATA_LOGGING) {
|
||||
Log.log(LogMessageType.OTHER, level = LogLevels.VERBOSE) { "Players metadata of $entity: ${entity.entityMetaData}" }
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user