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.StatusEffectAttributeInstance
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.physics.PhysicsEntity
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.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
import glm_.vec2.Vec2
import glm_.vec3.Vec3
import glm_.vec3.Vec3d
@ -65,7 +67,7 @@ abstract class Entity(
var passengers: MutableSet<Entity> = synchronizedSetOf()
override var velocity: Vec3d = Vec3d.EMPTY
var velocityMultiplier = Vec3d.EMPTY
var movementMultiplier = Vec3d.EMPTY // ToDo: Used in cobwebs, etc
protected open val hasCollisions = true
@ -305,6 +307,19 @@ abstract class Entity(
override val aabb: AABB
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 {
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
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 MOVING_PISTON = "minecraft:moving_piston".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
protected set
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) {
item = registries.itemRegistry[itemId]

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.data.mappings.enchantment
import de.bixilon.minosoft.util.KUtil.asResourceLocation
object DefaultEnchantments {
val SOUL_SPEED = "minecraft:soul_speed".asResourceLocation()
val UNBREAKING = "minecraft:unbreaking".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.entities.player.PlayerEntity
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.attributes.DefaultStatusEffectAttributeNames
import de.bixilon.minosoft.data.mappings.effects.attributes.DefaultStatusEffectAttributes
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.other.containers.Container
import de.bixilon.minosoft.data.mappings.other.containers.PlayerInventory
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.util.VecUtil
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.protocol.network.connection.PlayConnection
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.util.KUtil.asResourceLocation
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.MMath
import glm_.func.cos
@ -45,9 +55,8 @@ import glm_.func.sin
import glm_.vec3.Vec3
import glm_.vec3.Vec3d
import glm_.vec3.Vec3i
import kotlin.math.cos
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.sin
class LocalPlayerEntity(
account: Account,
@ -127,12 +136,57 @@ class LocalPlayerEntity(
field = value
}
val canSwimInFluids: Boolean
private val canSwimInFluids: Boolean
get() = !baseAbilities.isFlying
override val isSneaking: Boolean
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() {
if (Minosoft.config.config.game.camera.disableMovementSending) {
return
@ -192,9 +246,9 @@ class LocalPlayerEntity(
lastOnGround = onGround
}
private fun slipperinessToMovementSpeed(slipperiness: Double): Double {
private fun frictionToMovement(friction: Double): Double {
if (onGround) {
return walkingSpeed * (0.21600002 / (slipperiness.pow(3)))
return walkingSpeed * (0.21600002 / (friction.pow(3)))
}
return flyingSpeed
}
@ -236,9 +290,9 @@ class LocalPlayerEntity(
// ToDo: Check for piston movement+
if (!velocityMultiplier.empty) {
movement = movement * velocityMultiplier
velocityMultiplier = Vec3d.EMPTY
if (!movementMultiplier.empty) {
movement = movement * movementMultiplier
movementMultiplier = Vec3d.EMPTY
velocity = Vec3d.EMPTY
}
@ -271,20 +325,43 @@ class LocalPlayerEntity(
}
// 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 {
velocity = velocity + calculateVelocity(sidewaysSpeed, forwardSpeed, slipperinessToMovementSpeed(slipperiness), rotation.headYaw)
private fun move(sidewaysSpeed: Float, forwardSpeed: Float, friction: Double): Vec3d {
velocity = velocity + calculateVelocity(sidewaysSpeed, forwardSpeed, frictionToMovement(friction), rotation.headYaw)
velocity = applyClimbingSpeed(velocity)
move(velocity)
return adjustVelocityForClimbing(velocity)
}
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
}
private fun travel(sidewaysSpeed: Float, forwardSpeed: Float) {
@ -319,14 +396,12 @@ class LocalPlayerEntity(
isFlyingWithElytra -> {
}
else -> {
val velocityPosition = Vec3i(position.x, position.y + defaultAABB.min.y - 0.5000001f, position.z)
val slipperiness = /* ToDo: connection.world.connection.world[velocityPosition]?.block?.slipperiness ?: */0.6
val friction = connection.world.connection.world[positionInfo.velocityPosition]?.block?.friction ?: 0.6
speedMultiplier = 0.91
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 {
@ -434,7 +509,7 @@ class LocalPlayerEntity(
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 {
velocity += 0.1 * (it.amplifier + 1.0)
@ -443,7 +518,7 @@ class LocalPlayerEntity(
if (isSprinting) {
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
}
@ -465,4 +540,10 @@ class LocalPlayerEntity(
lastFovMultiplier = currentFovMultiplier
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
private set
lateinit var velocityPosition: Vec3i
private set
lateinit var chunkPosition: Vec2i
private set
lateinit var inChunkSectionPosition: Vec3i
@ -44,6 +46,7 @@ class EntityPositionInfo(
fun update() {
blockPosition = entity.position.blockPosition
velocityPosition = Vec3i(entity.position.x, entity.position.y + -0.5000001f, entity.position.z)
chunkPosition = blockPosition.chunkPosition
inChunkSectionPosition = blockPosition.inChunkSectionPosition
sectionHeight = blockPosition.sectionHeight

View File

@ -30,7 +30,7 @@ class TagsS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
init {
val tags: MutableMap<ResourceLocation, Map<ResourceLocation, Tag<Any>>> = mutableMapOf()
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[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) {

File diff suppressed because one or more lines are too long