init
This commit is contained in:
133
game_server/net/session.py
Normal file
133
game_server/net/session.py
Normal 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())
|
||||
Reference in New Issue
Block a user