func (player *Player) mainLoop() { defer func() { // Close the transmitLoop and receiveLoop cleanly. player.txQueue <- nil player.conn.Close() player.onDisconnect <- player.EntityId if player.ping.timer != nil { player.ping.timer.Stop() } buf := new(bytes.Buffer) proto.WriteUserListItem(buf, player.name, false, 0) player.game.BroadcastPacket(buf.Bytes()) }() expVarPlayerConnectionCount.Add(1) defer expVarPlayerDisconnectionCount.Add(1) player.chunkSubs.Init(player) defer player.chunkSubs.Close() // Start the keep-alive/latency pings. player.pingNew() player.sendChatMessage(fmt.Sprintf("%s has joined", player.name), false) MAINLOOP: for { select { case _ = <-player.stopPlayer: break MAINLOOP case f, ok := <-player.mainQueue: if !ok { return } player.runQueuedCall(f) case _ = <-player.ping.timer.C: player.pingTimeout() case err := <-player.rxErrChan: log.Printf("%v: receive loop failed: %v", player, err) player.Stop() case err := <-player.txErrChan: log.Printf("%v: send loop failed: %v", player, err) player.Stop() } } }
// pingReceived is called when a keep alive packet is received. func (player *Player) pingReceived(id int32) { if id == 0 { // Client-initiated keep-alive. return } if *playerPingNoCheck { if !player.ping.running { return } } else { if !player.ping.running { log.Printf("%v: Received keep-alive id=%d when none was running", player, id) player.Stop() return } else if id != player.ping.id { log.Printf("%v: Bad keep alive ID received", player) player.Stop() return } } // Received valid keep-alive. now := time.Now() if player.ping.timer != nil { player.ping.timer.Stop() } latencyNs := now.Sub(time.Unix(0, player.ping.timestampNs)) // Check that there wasn't an apparent time-shift on this before broadcasting // this latency value. if latencyNs >= 0 && latencyNs < PingTimeoutNs { buf := new(bytes.Buffer) proto.WriteUserListItem(buf, player.name, true, int16(latencyNs/1e6)) player.game.BroadcastPacket(buf.Bytes()) } player.ping.running = false player.ping.id = 0 player.ping.timer = time.NewTimer(PingIntervalNs) }