diff --git a/src/main/java/de/bixilon/minosoft/data/entities/entities/Entity.kt b/src/main/java/de/bixilon/minosoft/data/entities/entities/Entity.kt index 5c3d04949..13e16e77a 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/entities/Entity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/entities/Entity.kt @@ -32,6 +32,7 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import glm_.vec3.Vec3 import java.lang.reflect.InvocationTargetException import java.util.* +import kotlin.math.pow abstract class Entity( protected val connection: PlayConnection, @@ -52,6 +53,8 @@ abstract class Entity( protected open val hasCollisions = true + var onGround = false + private val defaultAABB = AABB( Vec3(-(entityType.width / 2 + HITBOX_MARGIN), 0, -(entityType.width / 2 + HITBOX_MARGIN)), Vec3(+(entityType.width / 2 + HITBOX_MARGIN), entityType.height, +(entityType.width / 2 + HITBOX_MARGIN)) @@ -214,30 +217,47 @@ abstract class Entity( } private fun collide(deltaPosition: Vec3, collisionsToCheck: VoxelShape, aabb: AABB): Vec3 { + onGround = false val delta = Vec3(deltaPosition) if (delta.y != 0.0f) { delta.y = collisionsToCheck.computeOffset(aabb, deltaPosition.y, Axes.Y) aabb.offsetAssign(0f, delta.y, 0f) + if (delta.y != deltaPosition.y) { + velocity?.y = 0.0f + if (deltaPosition.y < 0) { + onGround = true; + } + } } val xPriority = delta.x > delta.z if (delta.x != 0.0f && xPriority) { delta.x = collisionsToCheck.computeOffset(aabb, deltaPosition.x, Axes.X) aabb.offsetAssign(delta.x, 0f, 0f) + if (delta.x != deltaPosition.x) { + velocity?.x = 0.0f + } } if (delta.z != 0.0f) { delta.z = collisionsToCheck.computeOffset(aabb, deltaPosition.z, Axes.Z) aabb.offsetAssign(0f, 0f, delta.z) + if (delta.z != deltaPosition.z) { + velocity?.z = 0.0f + } } if (delta.x != 0.0f && !xPriority) { delta.x = collisionsToCheck.computeOffset(aabb, deltaPosition.x, Axes.X) + if (delta.x != deltaPosition.x) { + velocity?.x = 0.0f + } } return delta } - fun computeTimeStep(deltaTime: Float) { + fun computeTimeStep(deltaMillis: Long) { + val deltaTime = deltaMillis.toFloat() / 1000.0f if (! hasNoGravity) { if (velocity == null) { - velocity = Vec3(0, deltaTime * ProtocolDefinition.GRAVITY) + velocity = Vec3(0, deltaTime * ProtocolDefinition.GRAVITY, 0) } else { velocity!!.y += deltaTime * ProtocolDefinition.GRAVITY; } @@ -245,6 +265,14 @@ abstract class Entity( if (velocity == VecUtil.EMPTY_VEC3) { velocity = null } + if (velocity == null) { + return + } + velocity?.timesAssign(0.25f.pow(deltaTime)) + if (velocity?.length()!! < 0.05f) { + velocity = null + return + } velocity?.let { move(velocity!! * deltaTime) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt index d340af9b8..c1b696623 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt @@ -206,7 +206,6 @@ class Camera( for (shader in shaders) { shader.use().setMat4("viewProjectionMatrix", matrix) } - positionChangeCallback() } @@ -236,10 +235,20 @@ class Camera( } private fun calculateViewMatrix(): Mat4 { - cameraPosition = playerEntity.position + Vec3(0, PLAYER_HEIGHT, 0) + cameraPosition = getAbsoluteCameraPosition() return glm.lookAt(cameraPosition, cameraPosition + cameraFront, CAMERA_UP_VEC3) } + private fun getAbsoluteCameraPosition(): Vec3 { + return playerEntity.position + Vec3(0, PLAYER_HEIGHT, 0) + } + + fun checkPosition() { + if (cameraPosition != getAbsoluteCameraPosition()) { + currentPositionSent = false + } + } + fun setRotation(yaw: Float, pitch: Float) { playerEntity.rotation = EntityRotation(yaw.toDouble(), pitch.toDouble()) @@ -258,34 +267,21 @@ class Camera( fun draw() { if (!currentPositionSent || !currentRotationSent) { + recalculateViewProjectionMatrix() sendPositionToServer() } } private fun sendPositionToServer() { - if (System.currentTimeMillis() - lastMovementPacketSent > ProtocolDefinition.TICK_TIME) { - if (!currentPositionSent && !currentPositionSent) { - connection.sendPacket(PlayerPositionAndRotationC2SPacket(playerEntity.position, playerEntity.rotation, false)) - } else if (!currentPositionSent) { - connection.sendPacket(PlayerPositionC2SPacket(playerEntity.position, false)) - } else { - connection.sendPacket(PlayerRotationC2SPacket(playerEntity.rotation, false)) - } - lastMovementPacketSent = System.currentTimeMillis() - currentPositionSent = true - currentRotationSent = true - return - } if (System.currentTimeMillis() - lastMovementPacketSent < ProtocolDefinition.TICK_TIME) { return } - if (!currentPositionSent && !currentPositionSent) { - connection.sendPacket(PlayerPositionAndRotationC2SPacket(cameraPosition - Vec3(0, PLAYER_HEIGHT, 0), EntityRotation(yaw, pitch), false)) + connection.sendPacket(PlayerPositionAndRotationC2SPacket(playerEntity.position, playerEntity.rotation, playerEntity.onGround)) } else if (!currentPositionSent) { - connection.sendPacket(PlayerPositionC2SPacket(cameraPosition - Vec3(0, PLAYER_HEIGHT, 0), false)) + connection.sendPacket(PlayerPositionC2SPacket(playerEntity.position, playerEntity.onGround)) } else { - connection.sendPacket(PlayerRotationC2SPacket(EntityRotation(yaw, pitch), false)) + connection.sendPacket(PlayerRotationC2SPacket(playerEntity.rotation, playerEntity.onGround)) } lastMovementPacketSent = System.currentTimeMillis() currentPositionSent = true diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/PlayConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/PlayConnection.kt index ad538f64c..175b6654b 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/PlayConnection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/PlayConnection.kt @@ -35,16 +35,15 @@ import de.bixilon.minosoft.protocol.packets.c2s.handshaking.HandshakeC2SPacket import de.bixilon.minosoft.protocol.packets.c2s.login.LoginStartC2SPacket import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket import de.bixilon.minosoft.protocol.packets.s2c.S2CPacket -import de.bixilon.minosoft.protocol.protocol.ConnectionStates -import de.bixilon.minosoft.protocol.protocol.PacketSender -import de.bixilon.minosoft.protocol.protocol.PacketTypes -import de.bixilon.minosoft.protocol.protocol.Protocol +import de.bixilon.minosoft.protocol.protocol.* import de.bixilon.minosoft.terminal.CLI import de.bixilon.minosoft.terminal.commands.commands.Command import de.bixilon.minosoft.util.CountUpAndDownLatch import de.bixilon.minosoft.util.ServerAddress import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels +import de.bixilon.minosoft.util.time.TimeWorker +import de.bixilon.minosoft.util.time.TimeWorkerTask class PlayConnection( @@ -70,6 +69,9 @@ class PlayConnection( private set private var _connectionState: ConnectionStates = ConnectionStates.DISCONNECTED + lateinit var velocityHandlerTask: TimeWorkerTask + private var velocityHandlerLastExecutionTime: Long = 0L + override var connectionState: ConnectionStates get() = _connectionState set(value) { @@ -112,6 +114,17 @@ class PlayConnection( if (CLI.getCurrentConnection() == null) { CLI.setCurrentConnection(this) } + velocityHandlerLastExecutionTime = System.currentTimeMillis() + velocityHandlerTask = TimeWorkerTask(ProtocolDefinition.TICK_TIME / 4) { + val currentTime = System.currentTimeMillis(); + val deltaTime = currentTime - velocityHandlerLastExecutionTime + for (entity in world.entityIdMap.values) { + entity.computeTimeStep(deltaTime) + } + renderer?.renderWindow?.camera?.checkPosition() + velocityHandlerLastExecutionTime = currentTime + } + TimeWorker.addTask(velocityHandlerTask) } ConnectionStates.DISCONNECTED -> { // unregister all custom recipes @@ -121,6 +134,9 @@ class PlayConnection( CLI.setCurrentConnection(null) Command.print("Disconnected from current connection!") } + if (this::velocityHandlerTask.isInitialized) { + TimeWorker.removeTask(velocityHandlerTask) + } } else -> { } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java index 6abbc8c57..0e9e1c3c3 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java @@ -93,7 +93,7 @@ public final class ProtocolDefinition { public static final int TICKS_PER_SECOND = 20; public static final int TICK_TIME = 1000 / TICKS_PER_SECOND; - public static final float VELOCITY_CONSTANT = 1 / 8000f * TICKS_PER_SECOND; + public static final float VELOCITY_CONSTANT = (float) TICKS_PER_SECOND / 80f; public static final float GRAVITY = -10; // TODO: find the correct value diff --git a/src/main/java/de/bixilon/minosoft/util/Util.java b/src/main/java/de/bixilon/minosoft/util/Util.java index 383840f58..ad8007ff4 100644 --- a/src/main/java/de/bixilon/minosoft/util/Util.java +++ b/src/main/java/de/bixilon/minosoft/util/Util.java @@ -23,6 +23,7 @@ import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer; import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition; import de.bixilon.minosoft.util.logging.Log; import de.bixilon.minosoft.util.microsoft.MicrosoftOAuthUtils; +import de.bixilon.minosoft.util.time.TimeWorker; import org.jetbrains.annotations.NotNull; import java.io.*; @@ -286,6 +287,7 @@ public final class Util { public static void initUtilClasses() { forceClassInit(Log.class); forceClassInit(MicrosoftOAuthUtils.class); + forceClassInit(TimeWorker.class); } public static Map urlQueryToMap(String query) { diff --git a/src/main/java/de/bixilon/minosoft/util/time/TimeWorker.kt b/src/main/java/de/bixilon/minosoft/util/time/TimeWorker.kt new file mode 100644 index 000000000..9c8beb3db --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/time/TimeWorker.kt @@ -0,0 +1,30 @@ +package de.bixilon.minosoft.util.time + +import de.bixilon.minosoft.Minosoft + +object TimeWorker { + private val TASKS: MutableList = mutableListOf() + + init { + Thread({ + while (true) { + val currentTime = System.currentTimeMillis(); + for (task in TASKS) { + if (currentTime - task.lastExecution >= task.interval) { + Minosoft.THREAD_POOL.execute(task.runnable) + task.lastExecution = currentTime + } + } + Thread.sleep(1) + } + }, "TimeWorkerThread").start() + } + + fun addTask(task: TimeWorkerTask) { + TASKS.add(task) + } + + fun removeTask(task: TimeWorkerTask) { + TASKS.remove(task) + } +} diff --git a/src/main/java/de/bixilon/minosoft/util/time/TimeWorkerTask.kt b/src/main/java/de/bixilon/minosoft/util/time/TimeWorkerTask.kt new file mode 100644 index 000000000..22fb5077a --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/time/TimeWorkerTask.kt @@ -0,0 +1,8 @@ +package de.bixilon.minosoft.util.time + +data class TimeWorkerTask( + val interval: Int, + val runnable: Runnable, +) { + var lastExecution: Long = 0L +}