package network import ( "log" "net" "time" "gitea.boner.be/bdnugget/goonscape/types" pb "gitea.boner.be/bdnugget/goonserver/actions" "google.golang.org/protobuf/proto" ) func ConnectToServer() (net.Conn, int32, error) { conn, err := net.Dial("tcp", types.ServerAddr) if err != nil { log.Printf("Failed to dial server: %v", err) return nil, 0, err } log.Println("Connected to server. Waiting for player ID...") buf := make([]byte, 1024) n, err := conn.Read(buf) if err != nil { log.Printf("Error reading player ID from server: %v", err) return nil, 0, err } var response pb.ServerMessage if err := proto.Unmarshal(buf[:n], &response); err != nil { log.Printf("Failed to unmarshal server response: %v", err) return nil, 0, err } playerID := response.GetPlayerId() log.Printf("Successfully connected with player ID: %d", playerID) return conn, playerID, nil } func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Player, otherPlayers map[int32]*types.Player) { buf := make([]byte, 4096) 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) batch := &pb.ActionBatch{ PlayerId: playerID, Actions: actions, Tick: player.CurrentTick, } player.ActionQueue = player.ActionQueue[:0] player.Unlock() data, err := proto.Marshal(batch) if err != nil { log.Printf("Failed to marshal action batch: %v", err) continue } if _, err = conn.Write(data); err != nil { log.Printf("Failed to send actions to server: %v", err) return } } else { player.Unlock() } } }() for { n, err := conn.Read(buf) if err != nil { log.Printf("Failed to read from server: %v", err) return } var serverMessage pb.ServerMessage if err := proto.Unmarshal(buf[:n], &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 } } } 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) } } } }