bump pixlyzer, physics: jump and velocity multipliers (soul sand, honey), climbing

This commit is contained in:
Bixilon 2021-06-06 21:31:58 +02:00
parent fb1f9ec6c9
commit 864c1f50f0
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
10 changed files with 179 additions and 22 deletions

View File

@ -24,6 +24,7 @@ import de.bixilon.minosoft.data.mappings.effects.StatusEffect
import de.bixilon.minosoft.data.mappings.effects.attributes.StatusEffectAttribute import de.bixilon.minosoft.data.mappings.effects.attributes.StatusEffectAttribute
import de.bixilon.minosoft.data.mappings.effects.attributes.StatusEffectAttributeInstance import de.bixilon.minosoft.data.mappings.effects.attributes.StatusEffectAttributeInstance
import de.bixilon.minosoft.data.mappings.effects.attributes.StatusEffectOperations import de.bixilon.minosoft.data.mappings.effects.attributes.StatusEffectOperations
import de.bixilon.minosoft.data.mappings.enchantment.Enchantment
import de.bixilon.minosoft.data.mappings.entities.EntityType import de.bixilon.minosoft.data.mappings.entities.EntityType
import de.bixilon.minosoft.data.physics.PhysicsEntity import de.bixilon.minosoft.data.physics.PhysicsEntity
import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.data.text.ChatComponent
@ -36,6 +37,7 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
import glm_.vec2.Vec2 import glm_.vec2.Vec2
import glm_.vec3.Vec3 import glm_.vec3.Vec3
import glm_.vec3.Vec3d import glm_.vec3.Vec3d
@ -65,7 +67,7 @@ abstract class Entity(
var passengers: MutableSet<Entity> = synchronizedSetOf() var passengers: MutableSet<Entity> = synchronizedSetOf()
override var velocity: Vec3d = Vec3d.EMPTY override var velocity: Vec3d = Vec3d.EMPTY
var velocityMultiplier = Vec3d.EMPTY var movementMultiplier = Vec3d.EMPTY // ToDo: Used in cobwebs, etc
protected open val hasCollisions = true protected open val hasCollisions = true
@ -305,6 +307,19 @@ abstract class Entity(
override val aabb: AABB override val aabb: AABB
get() = defaultAABB + position get() = defaultAABB + position
fun getEquipmentEnchant(enchantment: Enchantment?): Int {
enchantment ?: return 0
var maxLevel = 0
for ((slot, equipment) in this.equipment.toSynchronizedMap()) {
equipment.enchantments[enchantment]?.let {
if (it > maxLevel) {
maxLevel = it
}
}
}
return maxLevel
}
companion object { companion object {
private const val HITBOX_MARGIN = 1e-5f private const val HITBOX_MARGIN = 1e-5f

View File

@ -16,7 +16,21 @@ package de.bixilon.minosoft.data.mappings.blocks
import de.bixilon.minosoft.util.KUtil.asResourceLocation import de.bixilon.minosoft.util.KUtil.asResourceLocation
object DefaultBlocks { object DefaultBlocks {
val SCAFFOLDING = "minecraft:scaffolding".asResourceLocation()
val LADDER = "minecraft:ladder".asResourceLocation()
val VINE = "minecraft:vine".asResourceLocation()
val WEEPING_VINES = "minecraft:weeping_vines".asResourceLocation()
val WEEPING_VINES_PLANT = "minecraft:weeping_vines_plant".asResourceLocation()
val TWISTING_VINES = "minecraft:twisting_vines".asResourceLocation()
val TWISTING_VINES_PLANT = "minecraft:twisting_vines_plant".asResourceLocation()
val CAVE_VINES = "minecraft:cave_vines".asResourceLocation()
val CAVE_VINES_PLANT = "minecraft:cave_vines_plant".asResourceLocation()
val POWDER_SNOW = "minecraft:powder_snow".asResourceLocation()
val GRASS_BLOCK = "minecraft:grass_block".asResourceLocation() val GRASS_BLOCK = "minecraft:grass_block".asResourceLocation()
val MOVING_PISTON = "minecraft:moving_piston".asResourceLocation() val MOVING_PISTON = "minecraft:moving_piston".asResourceLocation()
val COBWEB = "minecraft:cobweb".asResourceLocation() val COBWEB = "minecraft:cobweb".asResourceLocation()
val WATER = "minecraft:water".asResourceLocation()
val BUBBLE_COLUMN = "minecraft:bubble_column".asResourceLocation()
} }

View File

@ -59,6 +59,9 @@ open class Block(
open lateinit var item: Item open lateinit var item: Item
protected set protected set
open lateinit var properties: Map<BlockProperties, List<Any>> open lateinit var properties: Map<BlockProperties, List<Any>>
open val friction = data["friction"]?.asDouble ?: 0.6
open val velocityMultiplier = data["velocity_multiplier"]?.asDouble ?: 1.0 // ToDo: They exist since ~1.15
open val jumpVelocityMultiplier = data["jump_velocity_multiplier"]?.asDouble ?: 1.0
override fun postInit(registries: Registries) { override fun postInit(registries: Registries) {
item = registries.itemRegistry[itemId] item = registries.itemRegistry[itemId]

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.data.mappings.enchantment
import de.bixilon.minosoft.util.KUtil.asResourceLocation import de.bixilon.minosoft.util.KUtil.asResourceLocation
object DefaultEnchantments { object DefaultEnchantments {
val SOUL_SPEED = "minecraft:soul_speed".asResourceLocation()
val UNBREAKING = "minecraft:unbreaking".asResourceLocation() val UNBREAKING = "minecraft:unbreaking".asResourceLocation()
val EFFICIENCY = "minecraft:efficiency".asResourceLocation() val EFFICIENCY = "minecraft:efficiency".asResourceLocation()
} }

View File

@ -0,0 +1,20 @@
/*
* 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.mappings.items
import de.bixilon.minosoft.util.KUtil.asResourceLocation
object DefaultItems {
val LEATHER_BOOTS = "minecraft:leather_boots".asResourceLocation()
}

View File

@ -19,14 +19,21 @@ import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
import de.bixilon.minosoft.data.entities.entities.player.RemotePlayerEntity import de.bixilon.minosoft.data.entities.entities.player.RemotePlayerEntity
import de.bixilon.minosoft.data.inventory.InventorySlots
import de.bixilon.minosoft.data.mappings.blocks.DefaultBlocks
import de.bixilon.minosoft.data.mappings.blocks.types.Block
import de.bixilon.minosoft.data.mappings.effects.DefaultStatusEffects import de.bixilon.minosoft.data.mappings.effects.DefaultStatusEffects
import de.bixilon.minosoft.data.mappings.effects.attributes.DefaultStatusEffectAttributeNames import de.bixilon.minosoft.data.mappings.effects.attributes.DefaultStatusEffectAttributeNames
import de.bixilon.minosoft.data.mappings.effects.attributes.DefaultStatusEffectAttributes import de.bixilon.minosoft.data.mappings.effects.attributes.DefaultStatusEffectAttributes
import de.bixilon.minosoft.data.mappings.effects.attributes.StatusEffectAttributeInstance import de.bixilon.minosoft.data.mappings.effects.attributes.StatusEffectAttributeInstance
import de.bixilon.minosoft.data.mappings.enchantment.DefaultEnchantments
import de.bixilon.minosoft.data.mappings.items.DefaultItems
import de.bixilon.minosoft.data.mappings.items.Item 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.Container
import de.bixilon.minosoft.data.mappings.other.containers.PlayerInventory import de.bixilon.minosoft.data.mappings.other.containers.PlayerInventory
import de.bixilon.minosoft.data.physics.PhysicsConstants import de.bixilon.minosoft.data.physics.PhysicsConstants
import de.bixilon.minosoft.data.tags.DefaultBlockTags
import de.bixilon.minosoft.data.tags.Tag
import de.bixilon.minosoft.gui.rendering.input.camera.MovementInput import de.bixilon.minosoft.gui.rendering.input.camera.MovementInput
import de.bixilon.minosoft.gui.rendering.util.VecUtil import de.bixilon.minosoft.gui.rendering.util.VecUtil
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
@ -35,8 +42,11 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.clearZero
import de.bixilon.minosoft.gui.rendering.util.VecUtil.empty import de.bixilon.minosoft.gui.rendering.util.VecUtil.empty
import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.packets.c2s.play.* import de.bixilon.minosoft.protocol.packets.c2s.play.*
import de.bixilon.minosoft.protocol.packets.s2c.play.TagsS2CP
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.asResourceLocation
import de.bixilon.minosoft.util.KUtil.decide import de.bixilon.minosoft.util.KUtil.decide
import de.bixilon.minosoft.util.KUtil.nullCast
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.MMath import de.bixilon.minosoft.util.MMath
import glm_.func.cos import glm_.func.cos
@ -45,9 +55,8 @@ import glm_.func.sin
import glm_.vec3.Vec3 import glm_.vec3.Vec3
import glm_.vec3.Vec3d import glm_.vec3.Vec3d
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
import kotlin.math.cos import kotlin.math.max
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sin
class LocalPlayerEntity( class LocalPlayerEntity(
account: Account, account: Account,
@ -127,12 +136,57 @@ class LocalPlayerEntity(
field = value field = value
} }
val canSwimInFluids: Boolean private val canSwimInFluids: Boolean
get() = !baseAbilities.isFlying get() = !baseAbilities.isFlying
override val isSneaking: Boolean override val isSneaking: Boolean
get() = input.sneaking get() = input.sneaking
private val isClimbing: Boolean
get() {
if (gamemode == Gamemodes.SPECTATOR) {
return false
}
val blockState = connection.world[positionInfo.blockPosition] ?: return false
connection.tags[TagsS2CP.BLOCK_TAG_RESOURCE_LOCATION]?.get(CLIMBABLE_TAG)?.nullCast<Tag<Block>>()?.let {
return it.entries.contains(blockState.block)
}
return DefaultBlockTags.CLIMBABLE.contains(blockState.block.resourceLocation)
}
private val velocityMultiplier: Double
get() {
if (isFlyingWithElytra || baseAbilities.isFlying) {
return 1.0
}
val onSoulSpeedBlock = connection.tags[TagsS2CP.BLOCK_TAG_RESOURCE_LOCATION]?.get(SOUL_SPEED_BLOCKS)?.nullCast<Tag<Block>>()?.entries?.contains(connection.world[positionInfo.velocityPosition]?.block) ?: false
if (onSoulSpeedBlock && getEquipmentEnchant(connection.registries.enchantmentRegistry[DefaultEnchantments.SOUL_SPEED]) > 0) {
// ToDo
return 1.0
}
val blockStateBelow = connection.world[positionInfo.blockPosition] ?: return 1.0
if (blockStateBelow.block.resourceLocation == DefaultBlocks.WATER || blockStateBelow.block.resourceLocation == DefaultBlocks.BUBBLE_COLUMN) {
if (blockStateBelow.block.velocityMultiplier == 1.0) {
return connection.world[positionInfo.blockPosition]?.block?.velocityMultiplier ?: 1.0
}
}
return blockStateBelow.block.velocityMultiplier
}
private val jumpVelocityMultiplier: Double
get() {
val blockModifier = connection.world[positionInfo.blockPosition]?.block?.jumpVelocityMultiplier ?: 1.0
if (blockModifier == 1.0) {
return connection.world[positionInfo.velocityPosition]?.block?.jumpVelocityMultiplier ?: 1.0
}
return blockModifier
}
private fun sendMovementPackets() { private fun sendMovementPackets() {
if (Minosoft.config.config.game.camera.disableMovementSending) { if (Minosoft.config.config.game.camera.disableMovementSending) {
return return
@ -192,9 +246,9 @@ class LocalPlayerEntity(
lastOnGround = onGround lastOnGround = onGround
} }
private fun slipperinessToMovementSpeed(slipperiness: Double): Double { private fun frictionToMovement(friction: Double): Double {
if (onGround) { if (onGround) {
return walkingSpeed * (0.21600002 / (slipperiness.pow(3))) return walkingSpeed * (0.21600002 / (friction.pow(3)))
} }
return flyingSpeed return flyingSpeed
} }
@ -236,9 +290,9 @@ class LocalPlayerEntity(
// ToDo: Check for piston movement+ // ToDo: Check for piston movement+
if (!velocityMultiplier.empty) { if (!movementMultiplier.empty) {
movement = movement * velocityMultiplier movement = movement * movementMultiplier
velocityMultiplier = Vec3d.EMPTY movementMultiplier = Vec3d.EMPTY
velocity = Vec3d.EMPTY velocity = Vec3d.EMPTY
} }
@ -271,20 +325,43 @@ class LocalPlayerEntity(
} }
// ToDo: Check for move effect // ToDo: Check for move effect
val velocityMultiplier = velocityMultiplier
velocity.x *= velocityMultiplier
velocity.z *= velocityMultiplier
}
private fun applyClimbingSpeed(velocity: Vec3d): Vec3d {
if (!isClimbing) {
return velocity
}
this.fallDistance = 0.0
val returnVelocity = Vec3d(
x = MMath.clamp(velocity.x, -CLIMBING_CLAMP_VALUE, CLIMBING_CLAMP_VALUE),
y = max(velocity.y, -CLIMBING_CLAMP_VALUE),
z = MMath.clamp(velocity.z, -CLIMBING_CLAMP_VALUE, CLIMBING_CLAMP_VALUE)
)
if (returnVelocity.y < 0.0 && connection.world[positionInfo.blockPosition]?.block?.resourceLocation != DefaultBlocks.SCAFFOLDING && isSneaking) {
returnVelocity.y = 0.0
}
return returnVelocity
} }
private fun move(sidewaysSpeed: Float, forwardSpeed: Float, slipperiness: Double): Vec3d { private fun move(sidewaysSpeed: Float, forwardSpeed: Float, friction: Double): Vec3d {
velocity = velocity + calculateVelocity(sidewaysSpeed, forwardSpeed, slipperinessToMovementSpeed(slipperiness), rotation.headYaw) velocity = velocity + calculateVelocity(sidewaysSpeed, forwardSpeed, frictionToMovement(friction), rotation.headYaw)
velocity = applyClimbingSpeed(velocity)
move(velocity) move(velocity)
return adjustVelocityForClimbing(velocity) return adjustVelocityForClimbing(velocity)
} }
private fun adjustVelocityForClimbing(velocity: Vec3d): Vec3d { private fun adjustVelocityForClimbing(velocity: Vec3d): Vec3d {
// ToDo: Check climbing or powder snow if ((this.horizontalCollision || isJumping) && (isClimbing || connection.world[positionInfo.blockPosition]?.block == DefaultBlocks.POWDER_SNOW && equipment[InventorySlots.EquipmentSlots.FEET]?.item?.resourceLocation == DefaultItems.LEATHER_BOOTS)) {
return Vec3d(velocity.x, 0.2, velocity.z)
}
return velocity return velocity
} }
private fun travel(sidewaysSpeed: Float, forwardSpeed: Float) { private fun travel(sidewaysSpeed: Float, forwardSpeed: Float) {
@ -319,14 +396,12 @@ class LocalPlayerEntity(
isFlyingWithElytra -> { isFlyingWithElytra -> {
} }
else -> { else -> {
val velocityPosition = Vec3i(position.x, position.y + defaultAABB.min.y - 0.5000001f, position.z) val friction = connection.world.connection.world[positionInfo.velocityPosition]?.block?.friction ?: 0.6
val slipperiness = /* ToDo: connection.world.connection.world[velocityPosition]?.block?.slipperiness ?: */0.6
speedMultiplier = 0.91 speedMultiplier = 0.91
if (onGround) { if (onGround) {
speedMultiplier *= slipperiness speedMultiplier *= friction
} }
val velocity = move(sidewaysSpeed, forwardSpeed, slipperiness) val velocity = move(sidewaysSpeed, forwardSpeed, friction)
activeStatusEffects[connection.registries.statusEffectRegistry[DefaultStatusEffects.LEVITATION]]?.let { activeStatusEffects[connection.registries.statusEffectRegistry[DefaultStatusEffects.LEVITATION]]?.let {
@ -434,7 +509,7 @@ class LocalPlayerEntity(
private fun jump() { private fun jump() {
var velocity = 0.42 // ToDo: Check for special blocks (e.g. soul sand, slime blocks, honey blocks, etc) var velocity = 0.42 * jumpVelocityMultiplier
activeStatusEffects[connection.registries.statusEffectRegistry[DefaultStatusEffects.JUMP_BOOST]]?.let { activeStatusEffects[connection.registries.statusEffectRegistry[DefaultStatusEffects.JUMP_BOOST]]?.let {
velocity += 0.1 * (it.amplifier + 1.0) velocity += 0.1 * (it.amplifier + 1.0)
@ -443,7 +518,7 @@ class LocalPlayerEntity(
if (isSprinting) { if (isSprinting) {
val yawRad = rotation.headYaw.rad val yawRad = rotation.headYaw.rad
this.velocity = this.velocity + Vec3(-(sin(yawRad) * 0.2f), 0.0f, cos(yawRad) * 0.2f) this.velocity = this.velocity + Vec3(-(yawRad.sin * 0.2f), 0.0f, yawRad.cos * 0.2f)
} }
dirtyVelocity = true dirtyVelocity = true
} }
@ -465,4 +540,10 @@ class LocalPlayerEntity(
lastFovMultiplier = currentFovMultiplier lastFovMultiplier = currentFovMultiplier
currentFovMultiplier = MMath.clamp(1.0 + walkingSpeed, 1.0, 1.5) currentFovMultiplier = MMath.clamp(1.0 + walkingSpeed, 1.0, 1.5)
} }
companion object {
private val CLIMBABLE_TAG = "minecraft:climbable".asResourceLocation()
private val SOUL_SPEED_BLOCKS = "minecraft:soul_speed_blocks".asResourceLocation()
private const val CLIMBING_CLAMP_VALUE = 0.15f.toDouble()
}
} }

View File

@ -0,0 +1,20 @@
/*
* 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.tags
import de.bixilon.minosoft.data.mappings.blocks.DefaultBlocks
object DefaultBlockTags {
val CLIMBABLE = setOf(DefaultBlocks.LADDER, DefaultBlocks.VINE, DefaultBlocks.SCAFFOLDING, DefaultBlocks.WEEPING_VINES, DefaultBlocks.WEEPING_VINES_PLANT, DefaultBlocks.TWISTING_VINES, DefaultBlocks.WEEPING_VINES_PLANT, DefaultBlocks.CAVE_VINES, DefaultBlocks.CAVE_VINES_PLANT)
}

View File

@ -29,6 +29,8 @@ class EntityPositionInfo(
) { ) {
lateinit var blockPosition: Vec3i lateinit var blockPosition: Vec3i
private set private set
lateinit var velocityPosition: Vec3i
private set
lateinit var chunkPosition: Vec2i lateinit var chunkPosition: Vec2i
private set private set
lateinit var inChunkSectionPosition: Vec3i lateinit var inChunkSectionPosition: Vec3i
@ -44,6 +46,7 @@ class EntityPositionInfo(
fun update() { fun update() {
blockPosition = entity.position.blockPosition blockPosition = entity.position.blockPosition
velocityPosition = Vec3i(entity.position.x, entity.position.y + -0.5000001f, entity.position.z)
chunkPosition = blockPosition.chunkPosition chunkPosition = blockPosition.chunkPosition
inChunkSectionPosition = blockPosition.inChunkSectionPosition inChunkSectionPosition = blockPosition.inChunkSectionPosition
sectionHeight = blockPosition.sectionHeight sectionHeight = blockPosition.sectionHeight

View File

@ -30,7 +30,7 @@ class TagsS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
init { init {
val tags: MutableMap<ResourceLocation, Map<ResourceLocation, Tag<Any>>> = mutableMapOf() val tags: MutableMap<ResourceLocation, Map<ResourceLocation, Tag<Any>>> = mutableMapOf()
if (buffer.versionId < ProtocolVersions.V_20W51A) { if (buffer.versionId < ProtocolVersions.V_20W51A) {
tags[BLOCK_TAG_RESOURCE_LOCATION] = buffer.readTagArray { buffer.connection.registries.getBlockState(it)!! } tags[BLOCK_TAG_RESOURCE_LOCATION] = buffer.readTagArray { buffer.connection.registries.blockRegistry[it] }
tags[ITEM_TAG_RESOURCE_LOCATION] = buffer.readTagArray { buffer.connection.registries.itemRegistry[it] } tags[ITEM_TAG_RESOURCE_LOCATION] = buffer.readTagArray { buffer.connection.registries.itemRegistry[it] }
tags[FLUID_TAG_RESOURCE_LOCATION] = buffer.readTagArray { buffer.connection.registries.fluidRegistry[it] } // ToDo: when was this added? Was not available in 18w01 tags[FLUID_TAG_RESOURCE_LOCATION] = buffer.readTagArray { buffer.connection.registries.fluidRegistry[it] } // ToDo: when was this added? Was not available in 18w01
if (buffer.versionId >= ProtocolVersions.V_18W43A) { if (buffer.versionId >= ProtocolVersions.V_18W43A) {

File diff suppressed because one or more lines are too long