mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 10:25:06 -04:00
physics: handle physics and add gravity
This commit is contained in:
parent
caebbdef67
commit
a8a565cf44
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 -> {
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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<String, String> urlQueryToMap(String query) {
|
||||
|
30
src/main/java/de/bixilon/minosoft/util/time/TimeWorker.kt
Normal file
30
src/main/java/de/bixilon/minosoft/util/time/TimeWorker.kt
Normal file
@ -0,0 +1,30 @@
|
||||
package de.bixilon.minosoft.util.time
|
||||
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
|
||||
object TimeWorker {
|
||||
private val TASKS: MutableList<TimeWorkerTask> = 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)
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package de.bixilon.minosoft.util.time
|
||||
|
||||
data class TimeWorkerTask(
|
||||
val interval: Int,
|
||||
val runnable: Runnable,
|
||||
) {
|
||||
var lastExecution: Long = 0L
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user