diff --git a/main.go b/main.go index 18a62a7..91ccfce 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "net" + "sync" "time" pb "gitea.boner.be/bdnugget/goonserver/actions" @@ -17,6 +18,7 @@ const ( ) type Player struct { + sync.Mutex ID int X, Y int // Position on the game grid } @@ -60,13 +62,15 @@ func handleConnection(conn net.Conn) { // Assign a new player ID and add the player to the game state playerID := len(players) + 1 - players[playerID] = &Player{ID: playerID, X: 5, Y: 5} // Start at default position - playerConns[playerID] = conn // Store the connection + newPlayer := &Player{ID: playerID, X: 5, Y: 5} + players[playerID] = newPlayer + playerConns[playerID] = conn fmt.Printf("Player %d connected\n", playerID) // Send player ID to the client serverMsg := &pb.ServerMessage{ - PlayerId: int32(playerID), + PlayerId: int32(playerID), + CurrentTick: 0, } data, err := proto.Marshal(serverMsg) if err != nil { @@ -85,18 +89,20 @@ func handleConnection(conn net.Conn) { if err != nil { log.Printf("Error reading from player %d: %v", playerID, err) delete(players, playerID) - delete(playerConns, playerID) // Remove connection on error + delete(playerConns, playerID) return } - action := &pb.Action{} - if err := proto.Unmarshal(buf[:n], action); err != nil { - log.Printf("Failed to unmarshal action for player %d: %v", playerID, err) + batch := &pb.ActionBatch{} + if err := proto.Unmarshal(buf[:n], batch); err != nil { + log.Printf("Failed to unmarshal action batch for player %d: %v", playerID, err) continue } - // Queue the action for processing in the game loop - actionQueue[playerID] = append(actionQueue[playerID], action) + // Queue the actions for processing + if batch.PlayerId == int32(playerID) { + actionQueue[playerID] = append(actionQueue[playerID], batch.Actions...) + } } } @@ -104,6 +110,7 @@ func processActions() { // Update players based on queued actions for playerID, actions := range actionQueue { player := players[playerID] + player.Lock() for _, action := range actions { if action.Type == pb.Action_MOVE { player.X = int(action.X) @@ -111,31 +118,36 @@ func processActions() { fmt.Printf("Player %d moved to (%d, %d)\n", playerID, player.X, player.Y) } } + player.Unlock() actionQueue[playerID] = nil // Clear the action queue after processing } - // Prepare and broadcast the positions of all players - for playerID := range players { - state := &pb.ServerMessage{} - for id, p := range players { - state.Players = append(state.Players, &pb.PlayerState{ - PlayerId: int32(id), - X: int32(p.X), - Y: int32(p.Y), - }) - } + // Prepare and broadcast the current game state + currentTick := time.Now().UnixNano() / int64(tickRate) + state := &pb.ServerMessage{ + CurrentTick: currentTick, + } - data, err := proto.Marshal(state) - if err != nil { - log.Printf("Failed to marshal player state: %v", err) - continue - } + for id, p := range players { + p.Lock() + state.Players = append(state.Players, &pb.PlayerState{ + PlayerId: int32(id), + X: int32(p.X), + Y: int32(p.Y), + }) + p.Unlock() + } - // Send to each connected player - for _, conn := range playerConns { - if _, err := conn.Write(data); err != nil { - log.Printf("Failed to send update to player %d: %v", playerID, err) - } + data, err := proto.Marshal(state) + if err != nil { + log.Printf("Failed to marshal game state: %v", err) + return + } + + // Send to each connected player + for _, conn := range playerConns { + if _, err := conn.Write(data); err != nil { + log.Printf("Failed to send update: %v", err) } } }