diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | config.py | 6 | ||||
| -rw-r--r-- | lib/Aircraft.py | 28 | ||||
| -rw-r--r-- | lib/PacketManager/packets/FSNETCMD_AIRCMD.py | 5 | ||||
| -rw-r--r-- | lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py | 20 | ||||
| -rw-r--r-- | lib/PacketManager/packets/FSNETCMD_GETDAMAGE.py | 13 | ||||
| -rw-r--r-- | lib/Player.py | 5 | ||||
| -rw-r--r-- | proxy.py | 76 |
9 files changed, 106 insertions, 55 deletions
@@ -3,4 +3,3 @@ __pycache__/ lib/__pycache__/ venv/ flightPacketParser.ipynb -config.py @@ -16,6 +16,13 @@ Sakuya AC and G Limiter at 20. It also has all the experimental options turned o --- +## Contributors + +- Skipper +- Biry (Emotional Support) + +--- + ## **Features** - Intercepts and parses network packets to monitor gameplay. - Adds features like G Limiter and Smoke Emission on Death. @@ -12,6 +12,12 @@ SERVER_PORT = 7914 # Please put where the normal YSFlight server is running # Port for the proxy server PROXY_PORT = 7915 +# Welcome Message to the playe +# For formatting use {username} +# eg. "Welcome {username} to the server!" +# > Welcome Sakuya to the server! +WELCOME_MESSAGE = "Welcome {username} to the server!" + # Native YSFlight Server # Please select the YSFlight server version for the # local ysflight server diff --git a/lib/Aircraft.py b/lib/Aircraft.py index 3b79947..215a1cb 100644 --- a/lib/Aircraft.py +++ b/lib/Aircraft.py @@ -1,4 +1,6 @@ from lib.PacketManager.packets import FSNETCMD_AIRPLANESTATE, FSNETCMD_AIRCMD +from logging import debug + class Aircraft: """ An aircraft class - this will hold the info from the Airplane state, weapons etc packets.""" @@ -13,7 +15,8 @@ class Aircraft: self.prev_life = -1 self.id = -1 self.last_packet = None - + self.damage_engine_warn_sent = False + def reset(self): """Resets the aircraft""" self.name = "" @@ -25,7 +28,8 @@ class Aircraft: self.prev_life = -1 self.id = -1 self.last_packet = None - + self.damage_engine_warn_sent = False + def set_position(self, position:list): """Sets the position of the aircraft from the Airplane state packet""" self.position = position @@ -33,36 +37,36 @@ class Aircraft: def set_attitude(self, attitude:list): """Sets the attitude of the aircraft from the Airplane state packet""" self.attitude = attitude - + def get_position(self): """Returns the position of the aircraft""" return self.position - + def get_altitude(self): """Returns the altitude in m""" return self.position[2] - + def get_attitude(self): """Returns the attitude of the aircraft""" return self.attitude - + def set_initial_config(self, config:dict): """Sets the initial config of the aircraft""" for key in config: self.initial_config[key] = config[key] - + def get_initial_config_value(self, key:str): """Returns the value of the initial config""" if key in self.initial_config: return self.initial_config[key] - + return None - + def set_custom_config_value(self, key:str, value): """Sets a custom config value""" self.custom_config[key] = value #Send this to the client. - + def add_state(self, packet:FSNETCMD_AIRPLANESTATE): """Adds the state of the aircraft""" if packet.player_id != self.id: @@ -73,11 +77,11 @@ class Aircraft: self.set_attitude(packet.atti) self.last_packet = packet return packet - + def check_command(self,command:FSNETCMD_AIRCMD): """Checks the command""" if command.aircraft_id != self.id: return if command.command: self.initial_config[command.command[0]] = command.command[1] - print(f"Command: {command.command}") + debug(f"Command: {command.command}") diff --git a/lib/PacketManager/packets/FSNETCMD_AIRCMD.py b/lib/PacketManager/packets/FSNETCMD_AIRCMD.py index 98d782c..094da7d 100644 --- a/lib/PacketManager/packets/FSNETCMD_AIRCMD.py +++ b/lib/PacketManager/packets/FSNETCMD_AIRCMD.py @@ -40,7 +40,7 @@ class FSNETCMD_AIRCMD: #30 if with_size: return pack("I",len(buffer))+buffer return buffer - + @staticmethod def setPayload(aircraft_id:int, payload:int, units:str='kg', with_size:bool=False): """ @@ -51,3 +51,6 @@ class FSNETCMD_AIRCMD: #30 payload = str(payload) message = f"INITLOAD {payload} {units}" return FSNETCMD_AIRCMD.encode(aircraft_id, message, with_size) + + def __str__(self): + return "Aircraft ID : {self.aircraft_id}; Message : {self.message}; Command : {self.command}" diff --git a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py index 071db5e..2282367 100644 --- a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py +++ b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py @@ -1,6 +1,7 @@ from struct import pack, unpack from math import pi import math +from logging import debug class FSNETCMD_AIRPLANESTATE: #11 """ @@ -73,8 +74,8 @@ class FSNETCMD_AIRPLANESTATE: #11 # self.atti = list(unpack("HHH", self.buffer[26:32])) self.atti = list(map(lambda x: x * (pi / 32768.0), unpack("HHH", self.buffer[26:32]))) - print(self.atti) - + debug(self.atti) + self.velocity = list(map(lambda x: x/10, unpack("HHH", self.buffer[32:38]))) self.atti_velocity = list(map(lambda x: x * (pi / 32768.0), @@ -101,12 +102,11 @@ class FSNETCMD_AIRPLANESTATE: #11 self.flags["firing"] = bool(flags &8) self.flags["smoke"] = 0 if flags & 2: - - self.flags["smoke"] = (flags >> 8) & 255 # bitshift 8 to the right, + self.flags["smoke"] = (flags >> 8) & 255 # bitshift 8 to the right, #then mask with 255 if self.flags["smoke"] == 0: self.flags["smoke"] = 255 # Need to review what this actuall does! - + if flags & 16: self.flags["beacon"] = True if flags & 32: @@ -140,10 +140,10 @@ class FSNETCMD_AIRPLANESTATE: #11 self.atti = list(map(lambda x: x * (pi / 32768.0), unpack("HHH", self.buffer[28:34]))) - + self.velocity = list(map(lambda x: x/10, unpack("HHH", self.buffer[34:40]))) - + self.atti_velocity = list(map(lambda x: x / (pi / 32768.0), unpack("HHH", self.buffer[40:46]))) self.g_value = unpack("h", self.buffer[46:48])[0]/100.0 @@ -199,13 +199,13 @@ class FSNETCMD_AIRPLANESTATE: #11 return pack('I',len(packet)) + packet else: flag = unpack('h',self.buffer[74:75])[0] - + flag &= ~((255<<8)|2) flag |= (255<<8) | 2 - print(flag) + debug(flag) packet = self.buffer[:74] + pack('h',flag) + self.buffer[76:] return pack('I',len(packet)) + packet - + def stop_firing(self): if self.packet_version == 4 or self.packet_version == 5: flag = unpack('h',self.buffer[56:58])[0] diff --git a/lib/PacketManager/packets/FSNETCMD_GETDAMAGE.py b/lib/PacketManager/packets/FSNETCMD_GETDAMAGE.py index 1becb40..165da4d 100644 --- a/lib/PacketManager/packets/FSNETCMD_GETDAMAGE.py +++ b/lib/PacketManager/packets/FSNETCMD_GETDAMAGE.py @@ -19,8 +19,8 @@ class FSNETCMD_GETDAMAGE: #22 def decode(self): variables = unpack("IIIIIHHH", self.buffer[0:26]) - self.victim_id = variables[2] self.victim_type = variables[1] + self.victim_id = variables[2] self.attacker_type = variables[3] self.attacker_id = variables[4] self.damage = variables[5] @@ -28,7 +28,7 @@ class FSNETCMD_GETDAMAGE: #22 self.weapon_type = variables[7] if self.weapon_type in FSWEAPON_DICT: self.weapon_type = FSWEAPON_DICT[self.weapon_type] - + @staticmethod def encode(victim_id, victim_type, attacker_type, attacker_id, damage, died_of, @@ -36,8 +36,13 @@ class FSNETCMD_GETDAMAGE: #22 if weapon_type in FSWEAPON_DICT and not isinstance(weapon_type,int): weapon_type = list(FSWEAPON_DICT.keys())[list(FSWEAPON_DICT.values()).index(weapon_type)] - buffer = pack("I",22)+pack("IIIIIHHH", victim_id, victim_type, attacker_type, - attacker_id, damage, died_of, weapon_type) + buffer = pack("I",22)+pack("4I3H", victim_type, victim_id, attacker_type,attacker_id, + damage, died_of, weapon_type) if with_size: return pack("I", len(buffer))+buffer return buffer + + def __str__(self): + return f"Victim ID : {self.victim_id}; Victim Type : {self.victim_type}; \ + Attacker Type : {self.attacker_type}; Attacker ID : {self.attacker_id} \ + Damage : {self.damage}; Died Of : {self.died_of}; weapon : {self.weapon_type}" diff --git a/lib/Player.py b/lib/Player.py index be49746..bc94bf2 100644 --- a/lib/Player.py +++ b/lib/Player.py @@ -3,13 +3,14 @@ from lib.PacketManager.packets import FSNETCMD_LOGON, FSNETCMD_ADDOBJECT class Player: """ A player class, this will hold info about the client, including which aircraft they're flying""" - def __init__(self, server_messages, client_messages): + def __init__(self, server_messages, client_messages, streamWriterObject): self.username = "" self.alias = "" self.aircraft = Aircraft() self.version = 0 self.ip = "" + self.streamWriterObject = streamWriterObject def set_aircraft(self, aircraft:Aircraft): self.aircraft = aircraft @@ -32,4 +33,4 @@ class Player: "IFF": packet.iff }) return True - return False
\ No newline at end of file + return False @@ -29,8 +29,8 @@ info("Lisenced under GPLv3") async def handle_client(client_reader, client_writer): message_to_client = [] message_to_server = [] - player = Player.Player(message_to_server, message_to_client) #Initialise the player. - + player = Player.Player(message_to_server, message_to_client, client_writer) #Initialise the player. + try: # Connect to the actual server @@ -69,40 +69,68 @@ async def handle_client(client_reader, client_writer): data = header + packet packet_type = PacketManager().get_packet_type(packet) if direction == "client_to_server": + debug("C2S" + str(packet_type)) + debug(data) + try: - + if packet_type == "FSNETCMD_LOGON": player.login(FSNETCMD_LOGON(packet)) - - - + elif packet_type == "FSNETCMD_AIRPLANESTATE": + # print("Damaging!") + # damageData = FSNETCMD_GETDAMAGE.encode(player.aircraft.id, 1, 1, player.aircraft.id, 1, 11, 0, True) + # print("custom", damageData) + # message_to_server.append(damageData) + # message_to_client.append(damageData) - if packet_type == "FSNETCMD_AIRPLANESTATE": packet = player.aircraft.add_state(FSNETCMD_AIRPLANESTATE(packet)) + + """ + Just for fun! if packet.flags['firing']: bomb_drop = FSNETCMD_MISSILELAUNCH.drop_bombs(player.aircraft) message_to_server.append(bomb_drop) message_to_client.append(bomb_drop) + """ + if player.aircraft.last_packet.g_value > G_LIM: + debug("G Value exceeded : ", player.aircraft.last_packet.g_value) + # We make a packet which damages the aircraft using the same pilot ID, using a gun + damageData = FSNETCMD_GETDAMAGE.encode(player.aircraft.id, 1, 1, player.aircraft.id, 1, 11, 0, True) + warnMsg = YSchat.message(f"You are exceeding the G Limit for the aircraft!, gValue = {player.aircraft.last_packet.g_value}!") + message_to_client.append(damageData) + message_to_client.append(warnMsg) prev_life = player.aircraft.prev_life if player.aircraft.life == -1: #Uninitialised player.aircraft.life = prev_life + elif prev_life > player.aircraft.life: cheatingMsg = YSchat.message(f"{HEALTH_HACK_MESSAGE} by {player.username}") writer.write(cheatingMsg) await writer.drain() + + elif player.aircraft.life < SMOKE_LIFE and SMOKE_PLANE: + + if not player.aircraft.damage_engine_warn_sent: + warningMsg = YSchat.message(f"Your engine has been damaged! You can't turn on afterburner") + debug(f"Sending warning to {player.username}") + message_to_client.append(warningMsg) + player.aircraft.damage_engine_warn_sent = True + player.aircraft.life = prev_life - + elif packet_type == "FSNETCMD_UNJOIN": player.aircraft.reset() - - elif packet_type == "FSNETCMD_MISSILELAUNCH": - print(packet) - length, packet_type = unpack("<I I", data[:8]) - debug("C2S" + str(packet_type)) - debug(data) + elif packet_type == "FSNETCMD_AIRCMD": + h = FSNETCMD_AIRCMD(packet) + print(h.decode) + + # elif packet_type == "FSNETCMD_GETDAMAGE": + # h = FSNETCMD_GETDAMAGE(packet, True) + # print(h) + # if packet_type == 11: # Flight data packet # playerData = parseFlightData(data) # player.playerId = playerData[1] @@ -194,28 +222,26 @@ async def handle_client(client_reader, client_writer): except Exception as e: warning(f"Error parsing flight data: {e}", exc_info=True) - + else : + debug("S2C" + str(packet_type)) + debug(data) + #Coming from the server to the client if packet_type == "FSNETCMD_ADDOBJECT": if player.check_add_object(FSNETCMD_ADDOBJECT(packet)): info(f"{player.username} has spawned an aircraft") addSmoke = FSNETCMD_WEAPONCONFIG.addSmoke(player.aircraft.id) message_to_server.append(addSmoke) - + elif packet_type == "FSNETCMD_AIRCMD": #Check the configs against the current aircraft command = FSNETCMD_AIRCMD(packet) player.aircraft.check_command(command) - - length, packet_type = unpack("<I I", data[:8]) - debug("S2C" + str(packet_type)) - debug(data) - if packet_type == 36: - # print("S2C ", str(data)) - pass - + elif packet_type == "FSNETCMD_PREPARESIMULATION": + welcomeMsg = YSchat.message(WELCOME_MESSAGE.format(username=player.username)) + message_to_server.append(welcomeMsg) # Forward the packet to the other endpoint writer.write(data) @@ -251,4 +277,4 @@ async def start_proxy(): if __name__ == "__main__": - asyncio.run(start_proxy())
\ No newline at end of file + asyncio.run(start_proxy()) |
