From d86cbe15a3dbe60da8026d52b8646adf9964df2d Mon Sep 17 00:00:00 2001 From: bdnugget Date: Sat, 18 Jan 2025 22:27:22 +0100 Subject: [PATCH] add quit channel to clean up after self --- game/game.go | 5 +- main.go | 5 +- network/network.go | 135 ++++++++++++++++++++++++--------------------- 3 files changed, 80 insertions(+), 65 deletions(-) diff --git a/game/game.go b/game/game.go index 70d6e3a..270ea19 100644 --- a/game/game.go +++ b/game/game.go @@ -17,6 +17,7 @@ type Game struct { Music rl.Music Chat *Chat MenuOpen bool + QuitChan chan struct{} // Channel to signal shutdown } func New() *Game { @@ -37,7 +38,8 @@ func New() *Game { Fovy: 45.0, Projection: rl.CameraPerspective, }, - Chat: NewChat(), + Chat: NewChat(), + QuitChan: make(chan struct{}), } game.Player.UserData = game game.Chat.userData = game @@ -259,6 +261,7 @@ func (g *Game) DrawMenu() { case "Settings": // TODO: Implement settings case "Exit Game": + close(g.QuitChan) // Signal all goroutines to shut down rl.CloseWindow() } } diff --git a/main.go b/main.go index fbc399a..9c8fb43 100644 --- a/main.go +++ b/main.go @@ -52,7 +52,7 @@ func main() { game.Player.Model = game.Models[modelIndex].Model game.Player.Texture = game.Models[modelIndex].Texture - go network.HandleServerCommunication(conn, playerID, game.Player, game.OtherPlayers) + go network.HandleServerCommunication(conn, playerID, game.Player, game.OtherPlayers, game.QuitChan) rl.PlayMusicStream(game.Music) rl.SetMusicVolume(game.Music, 0.5) @@ -65,4 +65,7 @@ func main() { game.Update(deltaTime) game.Render() } + + // Wait for clean shutdown + <-game.QuitChan } diff --git a/network/network.go b/network/network.go index 02da330..65779ba 100644 --- a/network/network.go +++ b/network/network.go @@ -56,89 +56,98 @@ func ConnectToServer() (net.Conn, int32, error) { return conn, playerID, nil } -func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Player, otherPlayers map[int32]*types.Player) { - // Create a buffered reader for the connection +func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Player, otherPlayers map[int32]*types.Player, quitChan <-chan struct{}) { reader := bufio.NewReader(conn) actionTicker := time.NewTicker(types.ClientTickRate) defer actionTicker.Stop() go func() { - for range actionTicker.C { - player.Lock() - if len(player.ActionQueue) > 0 { - actions := make([]*pb.Action, len(player.ActionQueue)) - copy(actions, player.ActionQueue) + for { + select { + case <-quitChan: + return + case <-actionTicker.C: + player.Lock() + if len(player.ActionQueue) > 0 { + actions := make([]*pb.Action, len(player.ActionQueue)) + copy(actions, player.ActionQueue) - batch := &pb.ActionBatch{ - PlayerId: playerID, - Actions: actions, - Tick: player.CurrentTick, + batch := &pb.ActionBatch{ + PlayerId: playerID, + Actions: actions, + Tick: player.CurrentTick, + } + + player.ActionQueue = player.ActionQueue[:0] + player.Unlock() + + if err := writeMessage(conn, batch); err != nil { + log.Printf("Failed to send actions to server: %v", err) + return + } + } else { + player.Unlock() } - - player.ActionQueue = player.ActionQueue[:0] - player.Unlock() - - if err := writeMessage(conn, batch); err != nil { - log.Printf("Failed to send actions to server: %v", err) - return - } - } else { - player.Unlock() } } }() for { - // Read message length (4 bytes) - lengthBuf := make([]byte, 4) - if _, err := io.ReadFull(reader, lengthBuf); err != nil { - log.Printf("Failed to read message length: %v", err) + select { + case <-quitChan: return - } - messageLength := binary.BigEndian.Uint32(lengthBuf) - - // Read the full message - messageBuf := make([]byte, messageLength) - if _, err := io.ReadFull(reader, messageBuf); err != nil { - log.Printf("Failed to read message body: %v", err) - return - } - - var serverMessage pb.ServerMessage - if err := proto.Unmarshal(messageBuf, &serverMessage); err != nil { - log.Printf("Failed to unmarshal server message: %v", err) - continue - } - - player.Lock() - player.CurrentTick = serverMessage.CurrentTick - - tickDiff := serverMessage.CurrentTick - player.CurrentTick - if tickDiff > types.MaxTickDesync { - for _, state := range serverMessage.Players { - if state.PlayerId == playerID { - player.ForceResync(state) - break - } + default: + // Read message length (4 bytes) + lengthBuf := make([]byte, 4) + if _, err := io.ReadFull(reader, lengthBuf); err != nil { + log.Printf("Failed to read message length: %v", err) + return } - } - player.Unlock() + messageLength := binary.BigEndian.Uint32(lengthBuf) - for _, state := range serverMessage.Players { - if state.PlayerId == playerID { + // Read the full message + messageBuf := make([]byte, messageLength) + if _, err := io.ReadFull(reader, messageBuf); err != nil { + log.Printf("Failed to read message body: %v", err) + return + } + + var serverMessage pb.ServerMessage + if err := proto.Unmarshal(messageBuf, &serverMessage); err != nil { + log.Printf("Failed to unmarshal server message: %v", err) continue } - if otherPlayer, exists := otherPlayers[state.PlayerId]; exists { - otherPlayer.UpdatePosition(state, types.ServerTickRate) - } else { - otherPlayers[state.PlayerId] = types.NewPlayer(state) - } - } + player.Lock() + player.CurrentTick = serverMessage.CurrentTick - if g, ok := player.UserData.(*game.Game); ok && len(serverMessage.ChatMessages) > 0 { - g.Chat.HandleServerMessages(serverMessage.ChatMessages) + tickDiff := serverMessage.CurrentTick - player.CurrentTick + if tickDiff > types.MaxTickDesync { + for _, state := range serverMessage.Players { + if state.PlayerId == playerID { + player.ForceResync(state) + break + } + } + } + player.Unlock() + + for _, state := range serverMessage.Players { + if state.PlayerId == playerID { + continue + } + + if otherPlayer, exists := otherPlayers[state.PlayerId]; exists { + otherPlayer.UpdatePosition(state, types.ServerTickRate) + } else { + otherPlayers[state.PlayerId] = types.NewPlayer(state) + } + } + + if g, ok := player.UserData.(*game.Game); ok && len(serverMessage.ChatMessages) > 0 { + g.Chat.HandleServerMessages(serverMessage.ChatMessages) + } } } }