diff --git a/src/main/java/de/bixilon/minosoft/data/abilities/ItemCooldown.kt b/src/main/java/de/bixilon/minosoft/data/abilities/ItemCooldown.kt
new file mode 100644
index 000000000..99a51cbce
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/abilities/ItemCooldown.kt
@@ -0,0 +1,26 @@
+/*
+ * 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 .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.abilities
+
+import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
+
+data class ItemCooldown(
+ val start: Long,
+ val time: Int,
+) {
+ val end: Long = start + (time * ProtocolDefinition.TICK_TIME)
+
+ val ended: Boolean
+ get() = System.currentTimeMillis() >= end
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/BlockUsages.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/BlockUsages.kt
index b2f44701a..ebeee1142 100644
--- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/BlockUsages.kt
+++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/BlockUsages.kt
@@ -20,7 +20,7 @@ enum class BlockUsages {
CONSUME,
/**
- * Usage get consumed (like pressing a button, opening a door, right clicking on block entities) with animation
+ * Usage get consumed (like pressing a button, opening a door, right clicking on block entities, placing a block, …) with animation
*/
SUCCESS,
@@ -28,10 +28,5 @@ enum class BlockUsages {
* Nothing happens from block side (e.g. right clicking on dirt). You can maybe place a block, whatever
*/
PASS,
-
- /**
- * Nothing happens, basically `CONSUME`, but a requirement was not satisfied.
- */
- FAIL,
;
}
diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/items/BlockItem.kt b/src/main/java/de/bixilon/minosoft/data/mappings/items/BlockItem.kt
index 0b1eda526..2abe9eefb 100644
--- a/src/main/java/de/bixilon/minosoft/data/mappings/items/BlockItem.kt
+++ b/src/main/java/de/bixilon/minosoft/data/mappings/items/BlockItem.kt
@@ -14,9 +14,19 @@
package de.bixilon.minosoft.data.mappings.items
import com.google.gson.JsonObject
+import de.bixilon.minosoft.data.abilities.Gamemodes
+import de.bixilon.minosoft.data.inventory.ItemStack
import de.bixilon.minosoft.data.mappings.ResourceLocation
+import de.bixilon.minosoft.data.mappings.blocks.BlockState
+import de.bixilon.minosoft.data.mappings.blocks.BlockUsages
import de.bixilon.minosoft.data.mappings.blocks.types.Block
import de.bixilon.minosoft.data.mappings.versions.Registries
+import de.bixilon.minosoft.data.player.Hands
+import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit
+import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
+import de.bixilon.minosoft.protocol.network.connection.PlayConnection
+import de.bixilon.minosoft.protocol.packets.c2s.play.BlockPlaceC2SP
+import glm_.vec3.Vec3i
open class BlockItem(
resourceLocation: ResourceLocation,
@@ -24,4 +34,44 @@ open class BlockItem(
data: JsonObject,
) : Item(resourceLocation, registries, data) {
val block: Block = registries.blockRegistry[data["block"].asInt]
+
+ override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages {
+ if (!connection.player.entity.gamemode.canBuild) {
+ return BlockUsages.PASS
+ }
+
+ val placePosition = raycastHit.blockPosition + raycastHit.hitDirection
+ val dimension = connection.world.dimension!!
+ if (placePosition.y < dimension.minY || placePosition.y >= dimension.height) {
+ return BlockUsages.PASS
+ }
+
+ connection.world[placePosition]?.let {
+ if (!it.material.replaceable) {
+ return BlockUsages.PASS
+ }
+ }
+
+
+ val placeBlockState = block.getPlacementState(connection, raycastHit) ?: return BlockUsages.PASS
+
+
+ connection.world[placePosition] = placeBlockState
+
+ if (connection.player.entity.gamemode != Gamemodes.CREATIVE) {
+ itemStack.count--
+ connection.player.inventory.validate()
+ }
+
+
+ connection.sendPacket(BlockPlaceC2SP(
+ position = placePosition,
+ direction = raycastHit.hitDirection,
+ cursorPosition = raycastHit.hitPosition,
+ item = connection.player.inventory.getHotbarSlot(),
+ hand = Hands.MAIN_HAND,
+ insideBlock = false, // ToDo
+ ))
+ return BlockUsages.SUCCESS
+ }
}
diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/items/Item.kt b/src/main/java/de/bixilon/minosoft/data/mappings/items/Item.kt
index 3b086436e..e9b646cb3 100644
--- a/src/main/java/de/bixilon/minosoft/data/mappings/items/Item.kt
+++ b/src/main/java/de/bixilon/minosoft/data/mappings/items/Item.kt
@@ -50,7 +50,7 @@ open class Item(
return resourceLocation.toString()
}
- open fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages {
+ open fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages {
return BlockUsages.PASS
}
diff --git a/src/main/java/de/bixilon/minosoft/data/player/Player.kt b/src/main/java/de/bixilon/minosoft/data/player/Player.kt
index 1e1f0fa03..aabd8e41c 100644
--- a/src/main/java/de/bixilon/minosoft/data/player/Player.kt
+++ b/src/main/java/de/bixilon/minosoft/data/player/Player.kt
@@ -12,9 +12,11 @@
*/
package de.bixilon.minosoft.data.player
+import de.bixilon.minosoft.data.abilities.ItemCooldown
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
+import de.bixilon.minosoft.data.mappings.items.Item
import de.bixilon.minosoft.data.mappings.other.containers.Container
import de.bixilon.minosoft.data.mappings.other.containers.PlayerInventory
import de.bixilon.minosoft.gui.rendering.util.VecUtil
@@ -41,4 +43,6 @@ class Player(
val containers: MutableMap = synchronizedMapOf(
ProtocolDefinition.PLAYER_INVENTORY_ID to inventory)
var selectedHotbarSlot: Int = 0
+
+ val itemCooldown: MutableMap- = synchronizedMapOf()
}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/InteractionHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/InteractionHandler.kt
index bcc964083..01b7ca92b 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/InteractionHandler.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/InteractionHandler.kt
@@ -15,16 +15,14 @@ package de.bixilon.minosoft.gui.rendering.input
import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames
import de.bixilon.minosoft.data.Directions
-import de.bixilon.minosoft.data.abilities.Gamemodes
import de.bixilon.minosoft.data.mappings.blocks.BlockUsages
-import de.bixilon.minosoft.data.mappings.items.BlockItem
import de.bixilon.minosoft.data.player.Hands
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
-import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.protocol.packets.c2s.play.ArmSwingC2SP
import de.bixilon.minosoft.protocol.packets.c2s.play.BlockBreakC2SP
import de.bixilon.minosoft.protocol.packets.c2s.play.BlockPlaceC2SP
+import de.bixilon.minosoft.protocol.packets.c2s.play.ItemUseC2SP
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.vec3.Vec3i
@@ -104,8 +102,13 @@ class InteractionHandler(
if (raycastHit.distance > RenderConstants.MAX_BLOCK_OUTLINE_RAYCAST_DISTANCE) {
return
}
+ val itemInHand = connection.player.inventory.getHotbarSlot()
- val usage = raycastHit.blockState.block.use(renderWindow.connection, raycastHit.blockState, raycastHit.blockPosition, raycastHit, Hands.MAIN_HAND, null) // ToDo
+ val usage = if (renderWindow.inputHandler.camera.sneaking) {
+ BlockUsages.PASS
+ } else {
+ raycastHit.blockState.block.use(renderWindow.connection, raycastHit.blockState, raycastHit.blockPosition, raycastHit, Hands.MAIN_HAND, itemInHand)
+ }
lastInteractionSent = currentTime
lastInteraction = currentTime
@@ -128,47 +131,32 @@ class InteractionHandler(
}
BlockUsages.PASS -> {
// use item or place block
- if (!connection.player.entity.gamemode.canBuild) {
- return
- }
- val selectedItemStack = connection.player.inventory.getHotbarSlot() ?: return
- val blockPosition = raycastHit.blockPosition + raycastHit.hitDirection
+ itemInHand ?: return
- val dimension = connection.world.dimension!!
- if (blockPosition.y < dimension.minY || blockPosition.y >= dimension.height) {
- return
- }
+ val cooldown = connection.player.itemCooldown[itemInHand.item]
- renderWindow.connection.world[blockPosition]?.let {
- if (!it.material.replaceable) {
+ cooldown?.let {
+ if (it.ended) {
+ connection.player.itemCooldown.remove(itemInHand.item)
+ } else {
return
}
}
- val blockState = if (selectedItemStack.item is BlockItem) {
- selectedItemStack.item.block.getPlacementState(renderWindow.connection, raycastHit) ?: return
- } else {
- return
+
+ when (itemInHand.item.use(connection, raycastHit.blockState, raycastHit.blockPosition, raycastHit, Hands.MAIN_HAND, itemInHand)) {
+ BlockUsages.SUCCESS -> {
+ connection.sendPacket(ArmSwingC2SP(Hands.MAIN_HAND))
+ }
+ BlockUsages.PASS -> {
+ return
+ }
+ BlockUsages.CONSUME -> {
+ }
}
-
- renderWindow.connection.world[blockPosition] = blockState
-
- if (connection.player.entity.gamemode != Gamemodes.CREATIVE) {
- selectedItemStack.count--
- renderWindow.connection.player.inventory.validate()
- }
-
- connection.sendPacket(ArmSwingC2SP(Hands.MAIN_HAND))
-
- connection.sendPacket(BlockPlaceC2SP(
- position = blockPosition,
- direction = raycastHit.hitDirection,
- cursorPosition = raycastHit.hitPosition,
- item = connection.player.inventory.getHotbarSlot(),
- hand = Hands.MAIN_HAND,
- insideBlock = false, // ToDo
- ))
+ // ToDo: Before 1.9
+ connection.sendPacket(ItemUseC2SP(Hands.MAIN_HAND))
}
}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt
index 26a345ad6..f2ab5052e 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt
@@ -94,6 +94,8 @@ class Camera(
var viewProjectionMatrix = projectionMatrix * viewMatrix
private set
+ var sneaking: Boolean = false // ToDo: Not yet implemented
+
fun mouseCallback(xPos: Double, yPos: Double) {
var xOffset = xPos - this.lastMouseX
@@ -328,7 +330,7 @@ class Camera(
if (distance >= 0.0f && blockState != null) {
currentPosition += direction * distance
return RaycastHit(
- currentPosition ,
+ currentPosition,
getTotalDistance() + distance,
blockState = blockState,
hitDirection = currentPosition.nearestIntegerPositionDirection,
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ItemCooldownSetS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ItemCooldownSetS2CP.kt
index 2bf6048f3..3927949a2 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ItemCooldownSetS2CP.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ItemCooldownSetS2CP.kt
@@ -12,6 +12,8 @@
*/
package de.bixilon.minosoft.protocol.packets.s2c.play
+import de.bixilon.minosoft.data.abilities.ItemCooldown
+import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
import de.bixilon.minosoft.util.logging.Log
@@ -22,6 +24,10 @@ class ItemCooldownSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val item = buffer.connection.registries.itemRegistry[buffer.readVarInt()]
val time = buffer.readVarInt()
+ override fun handle(connection: PlayConnection) {
+ connection.player.itemCooldown[item] = ItemCooldown(System.currentTimeMillis(), time)
+ }
+
override fun log() {
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Item cooldown set (item=$item, time=$time)" }
}