From 99e6ce96994f8dd909d12c516bbaca00f588c25e Mon Sep 17 00:00:00 2001 From: "Sebastian Benjamin (aider)" Date: Tue, 3 Jun 2025 18:08:04 -0700 Subject: [PATCH] feat: implement grace window for player input handling in game loop --- server/game-modes/battle-royale/game-loop.go | 25 +++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/server/game-modes/battle-royale/game-loop.go b/server/game-modes/battle-royale/game-loop.go index 4c97e70..2c24119 100644 --- a/server/game-modes/battle-royale/game-loop.go +++ b/server/game-modes/battle-royale/game-loop.go @@ -24,7 +24,9 @@ func CheckMatchTerminate(lobbyState *MatchState, logger *runtime.Logger) bool { return false } -func RespondToInput(lobbyState *MatchState, messages []runtime.MatchData, logger *runtime.Logger) { +const GRACE_WINDOW_TICKS = 15 + +func RespondToInput(lobbyState *MatchState, messages []runtime.MatchData, logger *runtime.Logger, tick int64, dispatcher *runtime.MatchDispatcher) { for _, msg := range messages { _, exists := lobbyState.presences[msg.GetSessionId()] if !exists { @@ -32,7 +34,24 @@ func RespondToInput(lobbyState *MatchState, messages []runtime.MatchData, logger continue } - // Parse player message + // Check if the input is within the grace window + if msg.GetTick() < tick && tick-msg.GetTick() <= GRACE_WINDOW_TICKS { + // Replay the game state for the intervening ticks + for t := msg.GetTick(); t < tick; t++ { + // Apply the input to the player's state + lobbyState.presences[msg.GetSessionId()].stageState.BoundsCheckedMove(update.X, update.Y) + // Check if the player survives after applying the input + if lobbyState.presences[msg.GetSessionId()].stageState.CheckDeathState(t) == PLAYER_ALIVE { + // Send a cancel death message to the client + cancelDeathMessage := map[string]any{ + "cancelDeath": true, + } + data, _ := json.Marshal(cancelDeathMessage) + (*dispatcher).BroadcastMessage(CANCEL_DEATH, data, []runtime.Presence{msg.GetPresence()}, nil, true) + break + } + } + } var update ClientUpdate if err := json.Unmarshal(msg.GetData(), &update); err != nil { (*logger).Warn("Failed to parse input: %v", err) @@ -115,7 +134,7 @@ func (m *Match) MatchLoop(ctx context.Context, logger runtime.Logger, db *sql.DB return nil } - RespondToInput(lobbyState, messages, &logger) + RespondToInput(lobbyState, messages, &logger, tick, &dispatcher) BroadcastToPresences(tick, lobbyState, &logger, &dispatcher) return lobbyState