Files
Commonwealth-Online-Server/server/client_session.py
T

79 lines
2.8 KiB
Python

from __future__ import annotations
import socket
import threading
from dataclasses import dataclass, field
from typing import Any
@dataclass
class ClientSession:
connection: socket.socket
address: tuple[str, int]
player_id: int
connected_at: float
last_packet_at: float | None = None
last_transform: dict[str, Any] | None = None
last_transform_monotonic: float | None = None
packets_received: int = 0
packets_sent: int = 0
packets_broadcast: int = 0
gameplay_active: bool = False
protocol_version: int = 0
_lock: Any = field(repr=False, compare=False, default_factory=threading.RLock)
_send_lock: Any = field(repr=False, compare=False, default_factory=threading.Lock)
@property
def label(self) -> str:
return f"{self.address[0]}:{self.address[1]}"
def record_received(self, received_at: float) -> int:
with self._lock:
self.last_packet_at = received_at
self.packets_received += 1
return self.packets_received
def record_transform(self, packet: dict[str, Any], accepted_monotonic: float | None = None) -> None:
with self._lock:
self.last_transform = dict(packet)
self.last_transform_monotonic = accepted_monotonic
def get_last_transform_anchor(self) -> tuple[dict[str, Any] | None, float | None]:
with self._lock:
transform = dict(self.last_transform) if self.last_transform is not None else None
return transform, self.last_transform_monotonic
def record_sent(self, *, broadcast: bool = False) -> None:
with self._lock:
self.packets_sent += 1
if broadcast:
self.packets_broadcast += 1
def mark_gameplay_active(self, protocol_version: int) -> bool:
with self._lock:
if self.gameplay_active:
return False
self.gameplay_active = True
self.protocol_version = int(protocol_version)
return True
def send_bytes(self, payload: bytes) -> None:
with self._send_lock:
self.connection.sendall(payload)
def to_snapshot(self) -> dict[str, Any]:
with self._lock:
return {
"playerId": self.player_id,
"address": self.address[0],
"port": self.address[1],
"connectedAt": self.connected_at,
"lastPacketAt": self.last_packet_at,
"lastTransform": dict(self.last_transform) if self.last_transform is not None else None,
"packetsReceived": self.packets_received,
"packetsSent": self.packets_sent,
"packetsBroadcast": self.packets_broadcast,
"gameplayActive": self.gameplay_active,
"protocolVersion": self.protocol_version,
}