Files
sampy/sampy/client/player.py
2021-03-25 00:00:39 +01:00

113 lines
3.5 KiB
Python

import socket
import struct
from .base import BaseClient
from ..raknet.bitstream import Bitstream
import logging
logger = logging.getLogger(__name__)
STATE_CONNECTING = 0
STATE_CONNECTED = 1
class PlayerClient(BaseClient):
def __init__(self, server: "__ServerInstance__", ip: str, port: int):
super().__init__(server, ip, port)
logger.debug("Client resolved to PlayerClient")
# TODO: check if banned and handle here
self.state = STATE_CONNECTING
# TODO: Make this static
self.handlers = {
"default": {
"default": self.on_unimplemented_state
},
STATE_CONNECTING: {
"default": self.on_unexpected,
0x18: self.on_connection_request
},
STATE_CONNECTED: {
"default": self.on_player_packet
}
}
async def on_packet(self, packet: bytes):
logger.debug("on_packet(%s)" % packet)
#try:
packet = self.server.compressor.decompress(packet)
current_handlers = self.handlers.get(self.state, self.handlers["default"])
await current_handlers.get(packet[0], current_handlers["default"])(packet)
#except Exception as err:
#logger.error(err)
async def on_unexpected(self, packet: bytes):
logger.warning("Received unexpected packet: %s" % packet)
async def on_unimplemented_state(self, packet: bytes):
logger.warning("Unimplemented state: %d" % self.state)
async def on_unimplemented(self, packet: bytes):
logger.warning("Unimplemented handler for packet: %s" % packet)
async def on_connection_request(self, packet: bytes):
logger.debug("on_connection_request(%s)" % packet)
challenge = (self.ip_uint ^ self.server.config.challenge_short) & 0xFFFF
challenge_solution = challenge ^ 0x6969 # 0x6969 being client_version?
challenge_answer, = struct.unpack_from(b"<H", packet, 1)
if challenge_answer != challenge_solution: # Did not pass challenge
logger.debug("challenge: failed")
await self.send(struct.pack(b"<BH", 0x1A, challenge))
return
logger.debug("challenge: passed")
self.state = STATE_CONNECTED
await self.send(b"\x19\x00") # Challenge passed
async def on_player_packet(self, packet: bytes):
bitstream = Bitstream(packet)
has_acks = bitstream.read(0x01)
if has_acks:
logger.debug("Unfinished code hit; has_acks: True")
return
handled = await self.handle_internal_packet(bitstream)
if not handled:
logger.debug("Internal packet were not handled")
async def handle_internal_packet(self, bitstream: Bitstream) -> bool:
if (len(bitstream.buffer) * 8) - bitstream.offset < 0x10:
return False
message_number = bitstream.read(0x10)
reliability = bitstream.read(0x04)
isSplitPacket = bitstream.read(0x01)
if isSplitPacket:
logger.warning("Skipping split packet")
return
# Something I dont understand yet
# TODO: ReadCompressed
bitstream.offset += 1
unknown = bitstream.read(0x01)
bit_length = bitstream.read(0x08)
##
logger.debug("bit_length: %d" % bit_length)
logger.debug("bitstream: %s" % bitstream)
# TODO: ReadAlignedBytes
data = bitstream.read(bit_length)
logger.debug("data: %s" % data)