All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 7m51s
158 lines
4.3 KiB
Go
158 lines
4.3 KiB
Go
package main
|
|
|
|
import (
|
|
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/game"
|
|
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/physics"
|
|
)
|
|
|
|
// ApplyInput wendet einen Input auf den vorhergesagten Zustand an
|
|
// Nutzt die gemeinsame Physik-Engine aus pkg/physics
|
|
func (g *Game) ApplyInput(input InputState) {
|
|
// Horizontale Bewegung mit analogem Joystick
|
|
moveX := 0.0
|
|
if input.Left {
|
|
moveX = -1.0
|
|
} else if input.Right {
|
|
moveX = 1.0
|
|
}
|
|
|
|
// Wenn Joystick benutzt wird, überschreibe moveX mit analogem Wert
|
|
if input.JoyX != 0 {
|
|
moveX = input.JoyX
|
|
}
|
|
|
|
// Physik-State vorbereiten
|
|
state := physics.PlayerPhysicsState{
|
|
X: g.predictedX,
|
|
Y: g.predictedY,
|
|
VX: g.predictedVX,
|
|
VY: g.predictedVY,
|
|
OnGround: g.predictedGround,
|
|
OnWall: g.predictedOnWall,
|
|
}
|
|
|
|
// Physik-Input vorbereiten
|
|
physicsInput := physics.PhysicsInput{
|
|
InputX: moveX,
|
|
Jump: input.Jump,
|
|
Down: input.Down,
|
|
}
|
|
|
|
// Kollisions-Checker vorbereiten
|
|
g.stateMutex.Lock()
|
|
collisionChecker := &physics.ClientCollisionChecker{
|
|
World: g.world,
|
|
ActiveChunks: g.gameState.WorldChunks,
|
|
MovingPlatforms: g.gameState.MovingPlatforms,
|
|
}
|
|
g.stateMutex.Unlock()
|
|
|
|
// Gemeinsame Physik anwenden (1:1 wie Server)
|
|
physics.ApplyPhysics(&state, physicsInput, g.currentSpeed, collisionChecker, physics.DefaultPlayerConstants())
|
|
|
|
// Ergebnis zurückschreiben
|
|
g.predictedX = state.X
|
|
g.predictedY = state.Y
|
|
g.predictedVX = state.VX
|
|
g.predictedVY = state.VY
|
|
g.predictedGround = state.OnGround
|
|
g.predictedOnWall = state.OnWall
|
|
}
|
|
|
|
// ReconcileWithServer gleicht lokale Prediction mit Server-State ab
|
|
func (g *Game) ReconcileWithServer(serverState game.PlayerState) {
|
|
g.predictionMutex.Lock()
|
|
defer g.predictionMutex.Unlock()
|
|
|
|
// Server-bestätigte Sequenz
|
|
g.lastServerSeq = serverState.LastInputSeq
|
|
|
|
// Entferne alle bestätigten Inputs
|
|
for seq := range g.pendingInputs {
|
|
if seq <= g.lastServerSeq {
|
|
delete(g.pendingInputs, seq)
|
|
}
|
|
}
|
|
|
|
// Temporäre Position für Replay (jetzt MIT Y-Achse)
|
|
replayX := serverState.X
|
|
replayY := serverState.Y
|
|
replayVX := serverState.VX
|
|
replayVY := serverState.VY
|
|
replayGround := serverState.OnGround
|
|
replayOnWall := serverState.OnWall
|
|
|
|
// Replay alle noch nicht bestätigten Inputs mit VOLLER Physik
|
|
if len(g.pendingInputs) > 0 {
|
|
for seq := g.lastServerSeq + 1; seq <= g.inputSequence; seq++ {
|
|
if input, ok := g.pendingInputs[seq]; ok {
|
|
// Temporär auf Replay-Position setzen
|
|
oldX, oldY := g.predictedX, g.predictedY
|
|
oldVX, oldVY := g.predictedVX, g.predictedVY
|
|
oldGround := g.predictedGround
|
|
oldOnWall := g.predictedOnWall
|
|
|
|
g.predictedX = replayX
|
|
g.predictedY = replayY
|
|
g.predictedVX = replayVX
|
|
g.predictedVY = replayVY
|
|
g.predictedGround = replayGround
|
|
g.predictedOnWall = replayOnWall
|
|
|
|
g.ApplyInput(input)
|
|
|
|
replayX = g.predictedX
|
|
replayY = g.predictedY
|
|
replayVX = g.predictedVX
|
|
replayVY = g.predictedVY
|
|
replayGround = g.predictedGround
|
|
replayOnWall = g.predictedOnWall
|
|
|
|
// Zurücksetzen
|
|
g.predictedX = oldX
|
|
g.predictedY = oldY
|
|
g.predictedVX = oldVX
|
|
g.predictedVY = oldVY
|
|
g.predictedGround = oldGround
|
|
g.predictedOnWall = oldOnWall
|
|
}
|
|
}
|
|
}
|
|
|
|
// Berechne Differenz zwischen Client-Prediction und Server-Replay (X und Y)
|
|
diffX := replayX - g.predictedX
|
|
diffY := replayY - g.predictedY
|
|
dist := diffX*diffX + diffY*diffY
|
|
|
|
// Speichere Korrektur-Magnitude für Debug
|
|
g.correctionX = diffX
|
|
g.correctionY = diffY
|
|
|
|
// Bei sehr kleinen Abweichungen (<2px): Sofort korrigieren um Drift zu vermeiden
|
|
if dist < 4.0 { // 2px threshold
|
|
g.predictedX = replayX
|
|
g.predictedY = replayY
|
|
} else if dist > 100*100 {
|
|
// Bei sehr großen Abweichungen (>100px): Sofort korrigieren (Teleport/Respawn)
|
|
g.predictedX = replayX
|
|
g.predictedY = replayY
|
|
g.correctionCount++
|
|
} else if dist > 1.0 {
|
|
// Bei normalen Abweichungen: Sanfte Interpolation
|
|
// Bei 20 TPS: Aggressivere Interpolation
|
|
interpFactor := 0.5 // 50% pro Tick
|
|
if dist > 50*50 {
|
|
interpFactor = 0.8 // 80% bei großen Abweichungen
|
|
}
|
|
g.predictedX += diffX * interpFactor
|
|
g.predictedY += diffY * interpFactor
|
|
g.correctionCount++
|
|
}
|
|
|
|
// Velocity und Ground Status vom Server übernehmen
|
|
g.predictedVX = replayVX
|
|
g.predictedVY = replayVY
|
|
g.predictedGround = replayGround
|
|
g.predictedOnWall = replayOnWall
|
|
}
|