This commit is contained in:
Naruse
2025-04-15 19:36:05 +08:00
parent dd51fb491d
commit ec8972d5d6
121 changed files with 30598 additions and 0 deletions

133
game_server/net/session.py Normal file
View File

@@ -0,0 +1,133 @@
import asyncio
import importlib
import betterproto
from game_server.net.kcp import Kcp
from game_server.net.packet import NetPacket
from utils.logger import Info,Error,Warn
from rail_proto import cmd
from rail_proto import lib as protos
from game_server.game.player.player_manager import PlayerManager
from game_server.dummy import dummyprotolist
import traceback
class PlayerSession:
def __init__(self, transport, session_id, client_addr, db):
self.transport = transport
self.session_id = session_id
self.client_addr = client_addr
self.kcp = Kcp(session_id, self.send_output)
self.kcp.set_nodelay(1, 5, 2, 0)
self.is_destroyed = False
self.db = db
self.pending_notifies = list()
self.player = PlayerManager()
self.active = False
self.last_received = asyncio.get_event_loop().time()
def update_last_received(self):
self.last_received = asyncio.get_event_loop().time()
def is_timeout(self, timeout=15):
return asyncio.get_event_loop().time() - self.last_received > timeout
def pending_notify(self, data: betterproto.Message, delay=0):
"""
This can be used to queue packet to be sent after response inside a handler
"""
self.pending_notifies.append((data, delay))
async def notify(self, data: betterproto.Message):
msg_name = data.__class__.__name__
cmd_id = getattr(cmd.CmdID, msg_name, None)
if not cmd_id:
Warn(f"Server tried to send notify with unsupported message: {msg_name}")
return
response_packet = NetPacket.from_message(cmd_id, data)
await self.send(response_packet)
def send_output(self, data):
self.transport.sendto(data, self.client_addr)
async def consume(self, data):
self.kcp.input(data)
self.kcp.update(asyncio.get_running_loop().time())
while True:
packet = self.kcp.recv()
if packet is None:
break
await self.handle_packet(packet)
self.kcp.update(asyncio.get_running_loop().time())
async def handle_packet(self, packet):
net_packet = NetPacket.from_bytes(packet)
cmd_id = net_packet.cmd_type
request_name = cmd.get_key_by_value(cmd_id)
if not request_name:
Warn(
f"Request doesn't have registered message_id: {cmd_id}"
)
return
if request_name[:-5] in dummyprotolist:
dummy_cmd_id = getattr(cmd.CmdID, f"{request_name[:-5]}ScRsp", None)
dummy_response = NetPacket.from_message(dummy_cmd_id, b'')
await self.send(dummy_response)
return
try:
try:
req: betterproto.Message = getattr(protos, request_name)()
req.parse(net_packet.body)
except Exception:
req = betterproto.Message()
try:
handle_result: betterproto.Message = await importlib.import_module(
f"game_server.handlers.{request_name}"
).handle(self, req)
if not handle_result:
return
except ModuleNotFoundError:
Error(f"Unhandled request {request_name}")
return
except Exception:
Error(f"Handler {request_name} returns error.")
traceback.print_exc()
return
Info(f"Received cmd: {request_name}({cmd_id})")
response_name = handle_result.__class__.__name__
cmd_type = getattr(cmd.CmdID, response_name, None)
if not cmd_type:
Warn(
f"Server tried to send response with unsupported message: {response_name}"
)
return
response_packet = NetPacket.from_message(cmd_type, handle_result)
await self.send(response_packet)
asyncio.create_task(self.send_pending_notifies(
self.pending_notifies.copy()
))
self.pending_notifies.clear()
except:
pass
async def send_pending_notifies(
self,
pending_notifies: list[tuple[betterproto.Message, int]]
):
for notify, delay in pending_notifies:
if delay > 0:
await asyncio.sleep(delay)
await self.notify(notify)
async def send(self, packet):
self.kcp.send(packet.to_bytes())
self.kcp.flush()
self.kcp.update(asyncio.get_running_loop().time())