From dbc52a5e0337cfe8a040ac77117b788b49ef46db Mon Sep 17 00:00:00 2001 From: Ritabrata Das Date: Thu, 20 Feb 2025 14:48:31 +0530 Subject: Add being same IFF to refueling --- lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py | 4 +- lib/Player.py | 1 + plugins/refuel.py | 45 ++++++++++++++--------- proxy.py | 3 ++ 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py b/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py index 7796599..f24c94a 100644 --- a/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py +++ b/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py @@ -7,7 +7,7 @@ class FSNETCMD_JOINREQUEST: #8 """ def __init__(self, buffer:bytes, should_decode:bool=True): self.buffer = buffer - self.iff = None + self.iff = 0 # The IFF sent is 1 subtracted from the selected value by the player self.aircraft = None self.start_pos = None #It's the STP name self.fuel = None @@ -26,4 +26,4 @@ class FSNETCMD_JOINREQUEST: #8 start_pos.encode(), 1, fuel, smoke) if with_size: return pack("I",len(buffer))+buffer - return buffer \ No newline at end of file + return buffer diff --git a/lib/Player.py b/lib/Player.py index 7f54914..1d39a56 100644 --- a/lib/Player.py +++ b/lib/Player.py @@ -12,6 +12,7 @@ class Player: self.ip = "" self.streamWriterObject = streamWriterObject self.is_a_bot = True # We check if they are still present after LOGIN packet, then they're not a bot + self.iff = 0 def set_aircraft(self, aircraft:Aircraft): self.aircraft = aircraft diff --git a/plugins/refuel.py b/plugins/refuel.py index 1b33031..12af66a 100644 --- a/plugins/refuel.py +++ b/plugins/refuel.py @@ -23,6 +23,7 @@ class Plugin: self.plugin_manager.register_command('refuel', self.refuel) self.plugin_manager.register_command('refueler', self.refueler) self.plugin_manager.register_hook('on_flight_data', self.on_flight_data) + self.plugin_manager.register_hook('on_unjoin', self.on_unjoin) def refueler(self, full_message, player, message_to_client, message_to_server): if player in refueling: @@ -32,7 +33,7 @@ class Plugin: a = YSchat.message("You are no more refueling!") refuelers.pop(player) else: - a = YSchat.message(f"You are now refueling other players! To refuel the plane must be within {REFUEL_RADIUS}m") + a = YSchat.message(f"You are now refueling other players! To refuel the plane must be within {REFUEL_RADIUS}m and have same IFF") refuelers[player] = [0, [], False] message_to_client.append(a) @@ -46,7 +47,7 @@ class Plugin: a = YSchat.message("You are no more refueling!") refueling.pop(player) else: - a = YSchat.message(f"You can now be refueled by other players! To refuel the plane must be within {REFUEL_RADIUS}m") + a = YSchat.message(f"You can now be refueled by other players! To refuel the plane must be within {REFUEL_RADIUS}m and have same IFF") refueling[player] = [0, []] message_to_client.append(a) @@ -54,23 +55,24 @@ class Plugin: decode = FSNETCMD_AIRPLANESTATE(data) if player in refueling: for refueler in refuelers: - refueling[player] = [decode.fuel, decode.position] - if self.in_range(refuelers[refueler][1], decode.position): - refuelers[refueler][2] = True - max_lim = int((player.aircraft.initial_config['WEIGFUEL'])[:-2]) - if decode.fuel < max_lim: - a = FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITFUEL", f"{decode.fuel+FUEL_RATE}kg", True) - message_to_client.append(a) - elif decode.fuel >= max_lim: - a = YSchat.message("The plane is full!") - refuelers[refueler][2] = False # No longer refueling - message_to_client.append(a) + if refueler.iff == player.iff: + refueling[player] = [decode.fuel, decode.position] + if self.in_range(refuelers[refueler][1], decode.position): + refuelers[refueler][2] = True + max_lim = int((player.aircraft.initial_config['WEIGFUEL'])[:-2]) + if decode.fuel < max_lim: + a = FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITFUEL", f"{decode.fuel+FUEL_RATE}kg", True) + message_to_client.append(a) + elif decode.fuel >= max_lim: + a = YSchat.message("The plane is full!") + refuelers[refueler][2] = False # No longer refueling + message_to_client.append(a) - if refuelers[refueler][0] < FUEL_RATE: - a = YSchat.message("The refueler ran out of fuel!") - message_to_client.append(a) - else: - refuelers[refueler][2] = False # No longer refueling + if refuelers[refueler][0] < FUEL_RATE: + a = YSchat.message("The refueler ran out of fuel!") + message_to_client.append(a) + else: + refuelers[refueler][2] = False # No longer refueling elif player in refuelers: @@ -80,6 +82,13 @@ class Plugin: message_to_client.append(a) return True + def on_unjoin(self, data, player, message_to_client, message_to_server): + if player in refuelers: + refuelers.pop(player) + elif player in refueling: + refueling.pop(player) + return True + @staticmethod def in_range(refueler_cord:list, refueled_cord:list): # the plane to be refueled must be below and behind the diff --git a/proxy.py b/proxy.py index 9a60c0c..9cb6a5e 100644 --- a/proxy.py +++ b/proxy.py @@ -130,6 +130,9 @@ async def handle_client(client_reader, client_writer): writer.write(data) continue + elif packet_type == "FSNETCMD_JOINREQUEST": + player.iff = FSNETCMD_JOINREQUEST(packet).iff + 1 + elif packet_type == "FSNETCMD_AIRPLANESTATE": player.aircraft.add_state(FSNETCMD_AIRPLANESTATE(packet)) #TODO: Do we want to convert all this to plugins? Probably not, but there is duplicated functionality # keep_message = plugin_manager.triggar_hook('on_flight_data', packet, player, message_to_client, message_to_server) -- cgit v1.2.3 From bac0338396377a96805026bd0b8059a715647839 Mon Sep 17 00:00:00 2001 From: Ritabrata Das Date: Thu, 20 Feb 2025 21:26:39 +0530 Subject: Start work on radar --- lib/Player.py | 2 +- plugins/radar.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 plugins/radar.py diff --git a/lib/Player.py b/lib/Player.py index 1d39a56..8e2250a 100644 --- a/lib/Player.py +++ b/lib/Player.py @@ -12,7 +12,7 @@ class Player: self.ip = "" self.streamWriterObject = streamWriterObject self.is_a_bot = True # We check if they are still present after LOGIN packet, then they're not a bot - self.iff = 0 + self.iff = 1 def set_aircraft(self, aircraft:Aircraft): self.aircraft = aircraft diff --git a/plugins/radar.py b/plugins/radar.py new file mode 100644 index 0000000..ca9fd40 --- /dev/null +++ b/plugins/radar.py @@ -0,0 +1,46 @@ +""" +This plugin allows you have to Radar features similar to that of +original WW3 server. +""" +import math +from lib.PacketManager.packets import FSNETCMD_AIRPLANESTATE +import traceback + +ENABLED = True +RADIUS = 500 # in meters, within this range planes with different IFF can see each other on radar + +flying_players = {} + +class Plugin: + def __init__(self): + self.plugin_manager = None + + def register(self, plugin_manager): + self.plugin_manager = plugin_manager + self.plugin_manager.register_hook('on_flight_data_server', self.on_flight_data_server) + self.plugin_manager.register_hook('on_unjoin', self.on_unjoin) + + def on_flight_data_server(self, data, player, message_to_client, message_to_server): + decode = FSNETCMD_AIRPLANESTATE(data) + if decode.player_id == player.aircraft.id: + return True + else: + try: + print(decode.packet_version) + print(*decode.position, *decode.atti, *decode.velocity, *decode.atti_velocity) + message_to_client.append(FSNETCMD_AIRPLANESTATE.encode(decode.remote_time, decode.player_id, decode.packet_version, [0.0,0.0,0.0], decode.atti, decode.velocity, decode.atti_velocity, + decode.smoke_oil, decode.fuel, decode.payload, decode.flight_state, decode.vgw, decode.spoiler, decode.landing_gear, decode.flap, decode.brake, + decode.flags, decode.gun_ammo, decode.rocket_ammo, decode.aam, decode.agm, decode.bomb, decode.life, decode.g_value, decode.throttle, decode.elev, decode.ail, decode.rud, + decode.trim, decode.thrust_vector, decode.bomb_bay_info, True)) + except: + traceback.print_exc() + return False + + def on_unjoin(self, data, player, message_to_client, message_to_server): + return True + + @staticmethod + def in_range(pos1, pos2): + # pos1 and pos2 are lists of [x,y,z] + dist = math.sqrt((pos1[0] - pos2[0])**2 + (pos1[1] - pos2[1])**2 + (pos1[2] - pos2[2])**2) + return dist <= RADIUS -- cgit v1.2.3 From d420f7d5a1606c657576aa8aa02a4ad1ea1beec7 Mon Sep 17 00:00:00 2001 From: Ritabrata Das Date: Fri, 21 Feb 2025 19:26:06 +0530 Subject: Very premetive implementation of radar --- .../packets/FSNETCMD_AIRPLANESTATE.py | 2 +- plugins/radar.py | 60 +++++++++++++++++----- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py index 3ebf8d6..8c5aec7 100644 --- a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py +++ b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py @@ -235,7 +235,7 @@ class FSNETCMD_AIRPLANESTATE: #11 buffer = pack("IfI", 11, remote_time, player_id) buffer += pack("H", packet_version) if packet_version == 4 or packet_version == 5: - buffer += pack("fffhhhhhhhhh", *position, *atti, *velocity, *atti_velocity) + buffer += pack("3f9H", *position, *atti, *velocity, *atti_velocity) buffer += pack("hhhh", smoke_oil, fuel, payload, 0) buffer += pack("BB", flight_state, int(vgw*255)) buffer += pack("BB", int(spoiler*15)<<4 | int(landing_gear*15), int(flap*15)<<4 | int(brake*15)) diff --git a/plugins/radar.py b/plugins/radar.py index ca9fd40..cacc6c4 100644 --- a/plugins/radar.py +++ b/plugins/radar.py @@ -4,6 +4,8 @@ original WW3 server. """ import math from lib.PacketManager.packets import FSNETCMD_AIRPLANESTATE +from lib.YSchat import send +import struct import traceback ENABLED = True @@ -18,23 +20,46 @@ class Plugin: def register(self, plugin_manager): self.plugin_manager = plugin_manager self.plugin_manager.register_hook('on_flight_data_server', self.on_flight_data_server) + self.plugin_manager.register_hook('on_flight_data', self.on_flight_data) self.plugin_manager.register_hook('on_unjoin', self.on_unjoin) + def on_flight_data(self, data, player, message_to_client, message_to_server): + flying_players[player.aircraft.id][1] = FSNETCMD_AIRPLANESTATE(data).position + return True + def on_flight_data_server(self, data, player, message_to_client, message_to_server): - decode = FSNETCMD_AIRPLANESTATE(data) - if decode.player_id == player.aircraft.id: - return True - else: - try: - print(decode.packet_version) - print(*decode.position, *decode.atti, *decode.velocity, *decode.atti_velocity) - message_to_client.append(FSNETCMD_AIRPLANESTATE.encode(decode.remote_time, decode.player_id, decode.packet_version, [0.0,0.0,0.0], decode.atti, decode.velocity, decode.atti_velocity, - decode.smoke_oil, decode.fuel, decode.payload, decode.flight_state, decode.vgw, decode.spoiler, decode.landing_gear, decode.flap, decode.brake, - decode.flags, decode.gun_ammo, decode.rocket_ammo, decode.aam, decode.agm, decode.bomb, decode.life, decode.g_value, decode.throttle, decode.elev, decode.ail, decode.rud, - decode.trim, decode.thrust_vector, decode.bomb_bay_info, True)) - except: - traceback.print_exc() - return False + # TODO : This is very primitive, we need to implement a better way to keep track of players + try: + if player.aircraft.id not in flying_players and player.aircraft.id != -1: + flying_players[player.aircraft.id] = [player, []] + elif player.aircraft.id == -1: + return True + + decode = FSNETCMD_AIRPLANESTATE(data) + + if decode.player_id == player.aircraft.id: + return True + elif self.get_player_by_pilotid(int(decode.player_id)).iff == player.iff: + return True + elif self.in_range(flying_players[player.aircraft.id][1], decode.position): + print(flying_players[player.aircraft.id][1], decode.position) + print("HERE") + return True + else: + try: + position_data = struct.pack("3f", -1, 1000.0, 1000.0) + if decode.packet_version == 4 or 5: + updated_data = data[:14] + position_data + data[26:] + else: + updated_data = data[:16] + position_data + data[28:] + except: + traceback.print_exc() + + player.streamWriterObject.write(send(updated_data)) + player.streamWriterObject.drain() + return False + except: + traceback.print_exc() def on_unjoin(self, data, player, message_to_client, message_to_server): return True @@ -44,3 +69,10 @@ class Plugin: # pos1 and pos2 are lists of [x,y,z] dist = math.sqrt((pos1[0] - pos2[0])**2 + (pos1[1] - pos2[1])**2 + (pos1[2] - pos2[2])**2) return dist <= RADIUS + + @staticmethod + def get_player_by_pilotid(pilotid:int): + for playerid in flying_players: + if playerid == pilotid: + return flying_players[playerid][0] + return None -- cgit v1.2.3 From a9c36b6d90ffa4723fa60a24205c1c279ac682db Mon Sep 17 00:00:00 2001 From: Skipper Date: Sat, 22 Feb 2025 07:01:39 +0000 Subject: Updated packet defs, and test plugin of aircraft replacement on join --- lib/PacketManager/packets/FSNETCMD_ADDOBJECT.py | 27 ++++ .../packets/FSNETCMD_AIRPLANESTATE.py | 149 +++++++++++---------- lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py | 8 +- lib/plugin_manager.py | 6 +- plugins/aircraft_replacer.py | 70 ++++++++++ 5 files changed, 188 insertions(+), 72 deletions(-) create mode 100644 plugins/aircraft_replacer.py diff --git a/lib/PacketManager/packets/FSNETCMD_ADDOBJECT.py b/lib/PacketManager/packets/FSNETCMD_ADDOBJECT.py index ef7f785..61e2b3f 100644 --- a/lib/PacketManager/packets/FSNETCMD_ADDOBJECT.py +++ b/lib/PacketManager/packets/FSNETCMD_ADDOBJECT.py @@ -46,7 +46,34 @@ class FSNETCMD_ADDOBJECT: #5 #There is an extra short, but it's just set to 0 if len(self.buffer) >= 176: self.pilot = unpack("32s", self.buffer[124:156])[0].decode().strip('\x00') + + def to_dict(self): + return { + "object_type": self.object_type, + "net_type": self.net_type, + "object_id": self.object_id, + "iff": self.iff, + "pos": self.pos, + "atti": self.atti, + "identifier": self.identifier, + "substrname": self.substrname, + "ysfid": self.ysfid, + "flags": self.flags, + "flags0": self.flags0, + "outside_radius": self.outsideRadius, + "aircraft_class": self.aircraft_class, + "aircraft_category": self.aircraft_category, + "pilot": self.pilot + } + def to_packet(self, with_size:bool=True): + return FSNETCMD_ADDOBJECT.encode(self.object_type, self.net_type, + self.object_id, self.iff, self.pos, + self.atti, self.identifier, self.substrname, + self.ysfid, self.flags, self.flags0, + self.outsideRadius, self.aircraft_class, + self.aircraft_category, self.pilot, with_size) + @staticmethod def encode(object_type, net_type, object_id, iff, pos, atti, identifier, substrname, ysfid, flags, flags0, outside_radius, aircraft_class=None, aircraft_category=None, diff --git a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py index 3ebf8d6..ebb2a6d 100644 --- a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py +++ b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py @@ -74,7 +74,6 @@ 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]))) - debug(self.atti) self.velocity = list(map(lambda x: x/10, unpack("HHH", self.buffer[32:38]))) @@ -218,6 +217,12 @@ class FSNETCMD_AIRPLANESTATE: #11 packet = self.buffer[:74] + pack('h',flag) + self.buffer[76:] return pack('I',len(packet)) + packet + def to_packet(self, with_size:bool=True): + return FSNETCMD_AIRPLANESTATE.encode(self.remote_time, self.player_id, self.packet_version, self.position, self.atti, self.velocity, self.atti_velocity, + self.smoke_oil, self.fuel, self.payload, self.flight_state, self.vgw, self.spoiler, self.landing_gear, self.flap, self.brake, + self.flags, self.gun_ammo, self.rocket_ammo, self.aam, self.agm, self.bomb, self.life, self.g_value, self.throttle, self.elev, self.ail, self.rud, + self.trim, self.thrust_vector, self.bomb_bay_info, with_size) + @staticmethod def get_life(buffer:bytes): version = unpack("h", buffer[12:14])[0] @@ -232,73 +237,81 @@ class FSNETCMD_AIRPLANESTATE: #11 smoke_oil, fuel, payload, flight_state, vgw, spoiler, landing_gear, flap, brake, flags, gun_ammo, rocket_ammo, aam, agm, bomb, life, g_value, throttle, elev, ail, rud, trim, thrust_vector, bomb_bay_info, with_size:bool=False): - buffer = pack("IfI", 11, remote_time, player_id) - buffer += pack("H", packet_version) - if packet_version == 4 or packet_version == 5: - buffer += pack("fffhhhhhhhhh", *position, *atti, *velocity, *atti_velocity) - buffer += pack("hhhh", smoke_oil, fuel, payload, 0) - buffer += pack("BB", flight_state, int(vgw*255)) - buffer += pack("BB", int(spoiler*15)<<4 | int(landing_gear*15), int(flap*15)<<4 | int(brake*15)) - flagschar = 0 - if flags["ab"]: - flagschar |= 1 - if flags["firing"]: - flagschar |= 8 - if flags["smoke"]: - flagschar |= flags["smoke"] << 8 - if flags["beacon"]: - flagschar |= 16 - if flags["nav_lights"]: - flagschar |= 32 - if flags["strobe"]: - flagschar |= 64 - if flags["landing_lights"]: - flagschar |= 128 - buffer += pack("h", flagschar) - buffer += pack("HHBBB", gun_ammo, rocket_ammo, aam, agm, bomb) - buffer += pack("B", life) - buffer += pack("b", int(g_value*10)) - buffer += pack("B", int(throttle*99)) - buffer += pack("b", int(elev*99)) - buffer += pack("b", int(ail*99)) - buffer += pack("b", int(rud*99)) - buffer += pack("b", int(trim*99)) - - if packet_version == 4: - buffer += pack("BB", int(thrust_vector["vector"]*15)<<4 | int(thrust_vector["reverser"]*15), - int(bomb_bay_info*15)) - - else: - buffer += pack("fffhhhfff", *position, *atti, *velocity, *atti_velocity) - buffer += pack("HHHHH", gun_ammo, aam, agm, bomb, smoke_oil) - buffer += pack("f", payload) - buffer += pack("H", life) - buffer += pack("BB", flight_state, int(vgw*255)) - buffer += pack("BBBB", int(spoiler*15), int(landing_gear*15), - int(flap*15), int(brake*15)) - flagschar = 0 - if flags["ab"]: - flagschar |= 1 - if flags["firing"]: - flagschar |= 8 - if flags["smoke"]: - flagschar |= flags["smoke"] << 8 - buffer += pack("H", flagschar) - buffer += pack("B", int(throttle*99)) - buffer += pack("b", int(elev*99)) - buffer += pack("b", int(ail*99)) - buffer += pack("b", int(rud*99)) - buffer += pack("b", int(trim*99)) - buffer += pack("H", rocket_ammo) - if packet_version >= 1: - buffer += pack("fff", *atti_velocity) - if packet_version >= 2: - buffer += pack("BBB", int(thrust_vector["vector"]*255), int(thrust_vector["reverser"]*255), - int(bomb_bay_info*255)) - - if with_size: - return pack("I",len(buffer))+buffer - return buffer + try: + buffer = pack("IfI", 11, remote_time, player_id) + buffer += pack("H", packet_version) + if packet_version == 4 or packet_version == 5: + buffer += pack("fffhhhhhhhhh", *position, *atti, *velocity, *atti_velocity) + buffer += pack("hhhh", smoke_oil, fuel, payload, 0) + buffer += pack("BB", flight_state, int(vgw*255)) + buffer += pack("BB", int(spoiler*15)<<4 | int(landing_gear*15), int(flap*15)<<4 | int(brake*15)) + flagschar = 0 + if flags["ab"]: + flagschar |= 1 + if flags["firing"]: + flagschar |= 8 + if flags["smoke"]: + flagschar |= flags["smoke"] << 8 + if flags["beacon"]: + flagschar |= 16 + if flags["nav_lights"]: + flagschar |= 32 + if flags["strobe"]: + flagschar |= 64 + if flags["landing_lights"]: + flagschar |= 128 + buffer += pack("h", flagschar) + buffer += pack("HHBBB", gun_ammo, rocket_ammo, aam, agm, bomb) + buffer += pack("B", life) + buffer += pack("b", int(g_value*10)) + buffer += pack("B", int(throttle*99)) + buffer += pack("b", int(elev*99)) + buffer += pack("b", int(ail*99)) + buffer += pack("b", int(rud*99)) + buffer += pack("b", int(trim*99)) + + if packet_version == 4: + buffer += pack("BB", int(thrust_vector["vector"]*15)<<4 | int(thrust_vector["reverser"]*15), + int(bomb_bay_info*15)) + + else: + buffer += pack("fff", *position) + buffer += pack("HHH", *map(lambda x: int(x*32768.0/pi), atti)) + buffer += pack("HHH", *map(lambda x: int(x*10), velocity)) + buffer += pack("HHH", *map(lambda x: int(x*32768.0/pi), atti_velocity)) + buffer += pack("H", int(g_value)) + buffer += pack("HHHHH", gun_ammo, aam, agm, bomb, smoke_oil) + buffer += pack("f", payload) + buffer += pack("H", life) + buffer += pack("BB", flight_state, int(vgw*255)) + buffer += pack("BBBB", int(spoiler*15), int(landing_gear*15), + int(flap*15), int(brake*15)) + flagschar = 0 + if flags["ab"]: + flagschar |= 1 + if flags["firing"]: + flagschar |= 8 + if flags["smoke"]: + flagschar |= flags["smoke"] << 8 + buffer += pack("H", flagschar) + buffer += pack("B", int(throttle*99)) + buffer += pack("b", int(elev*99)) + buffer += pack("b", int(ail*99)) + buffer += pack("b", int(rud*99)) + buffer += pack("b", int(trim*99)) + buffer += pack("H", rocket_ammo) + if packet_version >= 1: + buffer += pack("fff", *atti_velocity) + if packet_version >= 2: + buffer += pack("BBB", int(thrust_vector["vector"]*255), int(thrust_vector["reverser"]*255), + int(bomb_bay_info*255)) + + if with_size: + return pack("I",len(buffer))+buffer + return buffer + except Exception as e: + import traceback + traceback.print_exc() def __str__(self): return f"Player ID : {self.player_id}; Remote Time : {self.remote_time}; \ diff --git a/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py b/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py index 7796599..15848fa 100644 --- a/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py +++ b/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py @@ -20,10 +20,16 @@ class FSNETCMD_JOINREQUEST: #8 self.start_pos = self.start_pos.decode().strip('\x00') self.aircraft = self.aircraft.decode().strip('\x00') + def to_packet(self, with_size:bool=True): + return FSNETCMD_JOINREQUEST.encode(self.iff, self.aircraft, self.start_pos, self.fuel, self.smoke, with_size) + @staticmethod def encode(iff, aircraft, start_pos, fuel, smoke, with_size:bool=False): buffer = pack("IHH32s32sHHH", 8, iff, 0, aircraft.encode(), start_pos.encode(), 1, fuel, smoke) if with_size: return pack("I",len(buffer))+buffer - return buffer \ No newline at end of file + return buffer + + def __str__(self): + return f"JoinRequest: {self.iff} {self.aircraft} {self.start_pos} {self.fuel} {self.smoke}" \ No newline at end of file diff --git a/lib/plugin_manager.py b/lib/plugin_manager.py index ae4cf0b..279d601 100644 --- a/lib/plugin_manager.py +++ b/lib/plugin_manager.py @@ -58,13 +58,13 @@ class PluginManager: If a callback returns False, then the original data is set to None and not forwarded to the destination. This is useful for modifying packets.""" - keep_orignal = True + keep_original = True if hook_name in self.hooks: for callback in self.hooks[hook_name]: keep = callback(data, *args, **kwargs) if keep == False: - keep_orignal = False - return keep_orignal + keep_original = False + return keep_original def trigger_command(self, command:str, player, full_message:str, message_to_client:list, message_to_server:list): """Triggers the command""" diff --git a/plugins/aircraft_replacer.py b/plugins/aircraft_replacer.py new file mode 100644 index 0000000..1515a6a --- /dev/null +++ b/plugins/aircraft_replacer.py @@ -0,0 +1,70 @@ +"""This plugin will replace the aircraft of the player +with the aircraft specified in the plugin. It is a template +for creating plugins that modify the aircraft of the player.""" +from lib.PacketManager.packets import FSNETCMD_ADDOBJECT, FSNETCMD_JOINREQUEST, FSNETCMD_READBACK, FSNETCMD_AIRPLANESTATE +from config import G_LIM +import time + +# CONFIG +ENABLED = False # Enable or disable the plugin + +class Plugin: + def __init__(self): + self.plugin_manager = None + self.first_add_object = False + + def register(self, plugin_manager): + self.plugin_manager = plugin_manager + # self.plugin_manager.register_hook('on_flight_data', self.on_flight_data) + self.plugin_manager.register_hook('on_add_object_server', self.on_add_object_server) + # self.plugin_manager.register_hook('on_flight_data_server', self.on_flight_data_server) + self.plugin_manager.register_hook('on_join_request', self.on_join_request) + + + def on_add_object_server(self, data, player, messages_to_client, *args): + packet = FSNETCMD_ADDOBJECT(data) + #Swap the aircraft and position + if packet.pilot == player.username: + packet.identifier = "EUROFIGHTER_TYPHOON" + messages_to_client.append(packet.to_packet()) + self.first_add_object = True + return False + return True + + # def on_flight_data(self, data, player, messages_to_client, *args): + # packet = FSNETCMD_AIRPLANESTATE(data) + # if packet.player_id == player.aircraft.id: + + # return True + + # def on_flight_data_server(self, data, player, messages_to_client, *args): + # packet = FSNETCMD_AIRPLANESTATE(data) + # if packet.player_id == player.aircraft.id and self.first_add_object: + # packet.position = [0,2000.0,0] + # packet.velocity = [25,0,25] + # messages_to_client.append(packet.to_packet()) + + # self.first_add_object = False + # return False + # return True + + def on_join_request(self, data, player, messages_to_client, message_to_server, *args): + packet = FSNETCMD_JOINREQUEST(data) + #Replace the aircraft: + packet.aircraft = "EUROFIGHTER_TYPHOON" + message_to_server.append(packet.to_packet()) + return False + + # def on_receive(self, data, player, messages_to_client, *args): + # if ENABLED: + # if abs(player.aircraft.last_packet.g_value)> G_LIM: + # if time.time() - player.aircraft.last_over_g_message > INTERVAL: + # player.aircraft.last_over_g_message = time.time() + # damage_packet = FSNETCMD_GETDAMAGE.encode(player.aircraft.id, + # 1, 1, + # player.aircraft.id, + # 1, 11,0, True) + # warning_message = FSNETCMD_TEXTMESSAGE.encode(f"You are exceeding the G Limit for the aircraft!, gValue = {player.aircraft.last_packet.g_value}!",True) + # messages_to_client.append(damage_packet) + # messages_to_client.append(warning_message) + # return True -- cgit v1.2.3 From 9708d6ecec391307b87507e034665e02d6643c08 Mon Sep 17 00:00:00 2001 From: Skipper Date: Sat, 22 Feb 2025 07:12:19 +0000 Subject: Typo in plugin manager --- lib/plugin_manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plugin_manager.py b/lib/plugin_manager.py index 07e28e6..52fb1f7 100644 --- a/lib/plugin_manager.py +++ b/lib/plugin_manager.py @@ -58,16 +58,16 @@ class PluginManager: If a callback returns False, then the original data is set to None and not forwarded to the destination. This is useful for modifying packets.""" - keep_orignal = True + keep_original = True if hook_name in self.hooks: for callback in self.hooks[hook_name]: keep = callback(data, *args, **kwargs) if type(keep) == bool: if keep == False: - keep_orignal = False + keep_original = False else: warning(f"Return value of {callback} is not a boolean") - return keep_orignal + return keep_original def trigger_command(self, command:str, player, full_message:str, message_to_client:list, message_to_server:list): """Triggers the command""" -- cgit v1.2.3 From d661428a89e0b2ce0661af1471b6eb7c12a50ec0 Mon Sep 17 00:00:00 2001 From: Ritabrata Das Date: Sat, 22 Feb 2025 16:18:15 +0530 Subject: Make refuel plugin optimised --- plugins/refuel.py | 59 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/plugins/refuel.py b/plugins/refuel.py index 12af66a..ff96699 100644 --- a/plugins/refuel.py +++ b/plugins/refuel.py @@ -4,6 +4,7 @@ This plugin enables you to perform air to air refueling. import math from lib.PacketManager.packets import FSNETCMD_AIRCMD, FSNETCMD_AIRPLANESTATE from lib import YSchat +import asyncio ENABLED = True REFUEL_RADIUS = 500 @@ -52,7 +53,31 @@ class Plugin: message_to_client.append(a) def on_flight_data(self, data, player, message_to_client, message_to_server): + asyncio.create_task(self.refuel_logic(data, player)) + return True + + def on_unjoin(self, data, player, message_to_client, message_to_server): + if player in refuelers: + refuelers.pop(player) + elif player in refueling: + refueling.pop(player) + return True + + @staticmethod + def in_range(refueler_cord:list, refueled_cord:list): + # the plane to be refueled must be below and behind the + # refueler plane, ysf sends cords in list[x, y, z] + # implement this later + # for now we just use distance formula in a 3d space + dist = math.sqrt((refueler_cord[0]-refueled_cord[0])**2 + (refueler_cord[1]-refueled_cord[1])**2 + (refueler_cord[2]-refueled_cord[2])**2) + if dist < REFUEL_RADIUS: + return True + else: + return False + + async def refuel_logic(self, data, player): decode = FSNETCMD_AIRPLANESTATE(data) + k = player.streamWriterObject if player in refueling: for refueler in refuelers: if refueler.iff == player.iff: @@ -61,16 +86,19 @@ class Plugin: refuelers[refueler][2] = True max_lim = int((player.aircraft.initial_config['WEIGFUEL'])[:-2]) if decode.fuel < max_lim: - a = FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITFUEL", f"{decode.fuel+FUEL_RATE}kg", True) - message_to_client.append(a) + #a = FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITFUEL", f"{decode.fuel+FUEL_RATE}kg", True) + #message_to_client.append(a) + k.write(FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITFUEL", f"{decode.fuel+FUEL_RATE}kg", True)) elif decode.fuel >= max_lim: a = YSchat.message("The plane is full!") refuelers[refueler][2] = False # No longer refueling - message_to_client.append(a) + k.write(a) + #message_to_client.append(a) if refuelers[refueler][0] < FUEL_RATE: a = YSchat.message("The refueler ran out of fuel!") - message_to_client.append(a) + k.write(a) + #message_to_client.append(a) else: refuelers[refueler][2] = False # No longer refueling @@ -79,24 +107,5 @@ class Plugin: refuelers[player] = [decode.fuel, decode.position, refuelers[player][2]] if decode.fuel-FUEL_RATE > 0 and refuelers[player][2]: a = FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITFUEL", f"{decode.fuel-FUEL_RATE}kg", True) - message_to_client.append(a) - return True - - def on_unjoin(self, data, player, message_to_client, message_to_server): - if player in refuelers: - refuelers.pop(player) - elif player in refueling: - refueling.pop(player) - return True - - @staticmethod - def in_range(refueler_cord:list, refueled_cord:list): - # the plane to be refueled must be below and behind the - # refueler plane, ysf sends cords in list[x, y, z] - # implement this later - # for now we just use distance formula in a 3d space - dist = math.sqrt((refueler_cord[0]-refueled_cord[0])**2 + (refueler_cord[1]-refueled_cord[1])**2 + (refueler_cord[2]-refueled_cord[2])**2) - if dist < REFUEL_RADIUS: - return True - else: - return False + #message_to_client.append(a) + k.write(a) -- cgit v1.2.3 From e15a34bf9195101398772e05ca655f9a73c3ef6d Mon Sep 17 00:00:00 2001 From: Ritabrata Das Date: Sat, 22 Feb 2025 19:34:33 +0530 Subject: Optimise Radar --- plugins/radar.py | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/plugins/radar.py b/plugins/radar.py index cacc6c4..4695f06 100644 --- a/plugins/radar.py +++ b/plugins/radar.py @@ -9,7 +9,7 @@ import struct import traceback ENABLED = True -RADIUS = 500 # in meters, within this range planes with different IFF can see each other on radar +RADIUS = 5000 # in meters, within this range planes with different IFF can see each other. flying_players = {} @@ -22,9 +22,19 @@ class Plugin: self.plugin_manager.register_hook('on_flight_data_server', self.on_flight_data_server) self.plugin_manager.register_hook('on_flight_data', self.on_flight_data) self.plugin_manager.register_hook('on_unjoin', self.on_unjoin) + #self.plugin_manager.register_hook('on_join_request', self.on_join) + + """ + def on_join(self, data, player, message_to_client, message_to_server): + flying_players[player.aircraft.id] = [player, []] + return True + """ def on_flight_data(self, data, player, message_to_client, message_to_server): - flying_players[player.aircraft.id][1] = FSNETCMD_AIRPLANESTATE(data).position + try: + flying_players[player.aircraft.id][1] = FSNETCMD_AIRPLANESTATE(data).position + except KeyError: + return True return True def on_flight_data_server(self, data, player, message_to_client, message_to_server): @@ -32,22 +42,23 @@ class Plugin: try: if player.aircraft.id not in flying_players and player.aircraft.id != -1: flying_players[player.aircraft.id] = [player, []] + return True elif player.aircraft.id == -1: return True decode = FSNETCMD_AIRPLANESTATE(data) - if decode.player_id == player.aircraft.id: + if len(flying_players[player.aircraft.id][1]) == 0: return True - elif self.get_player_by_pilotid(int(decode.player_id)).iff == player.iff: + elif decode.player_id == player.aircraft.id: + return True + elif flying_players[decode.player_id][0].iff == player.iff: return True elif self.in_range(flying_players[player.aircraft.id][1], decode.position): - print(flying_players[player.aircraft.id][1], decode.position) - print("HERE") return True else: try: - position_data = struct.pack("3f", -1, 1000.0, 1000.0) + position_data = struct.pack("3f", 10000, 1000.0, 1000.0) if decode.packet_version == 4 or 5: updated_data = data[:14] + position_data + data[26:] else: @@ -56,12 +67,16 @@ class Plugin: traceback.print_exc() player.streamWriterObject.write(send(updated_data)) - player.streamWriterObject.drain() + # await player.streamWriterObject.drain() return False - except: + except Exception as e: + if isinstance(e, KeyError): + return True traceback.print_exc() def on_unjoin(self, data, player, message_to_client, message_to_server): + if player.aircraft.id in flying_players: + flying_players.pop(player.aircraft.id) return True @staticmethod @@ -69,10 +84,3 @@ class Plugin: # pos1 and pos2 are lists of [x,y,z] dist = math.sqrt((pos1[0] - pos2[0])**2 + (pos1[1] - pos2[1])**2 + (pos1[2] - pos2[2])**2) return dist <= RADIUS - - @staticmethod - def get_player_by_pilotid(pilotid:int): - for playerid in flying_players: - if playerid == pilotid: - return flying_players[playerid][0] - return None -- cgit v1.2.3 From 20b1b5b1ce90514f4a51e5edd073dc6e6ed60d0e Mon Sep 17 00:00:00 2001 From: Ritabrata Das Date: Sun, 23 Feb 2025 10:39:10 +0530 Subject: Make radar position aribitary --- plugins/aircraft_replacer.py | 8 ++++---- plugins/radar.py | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/aircraft_replacer.py b/plugins/aircraft_replacer.py index 1515a6a..f2db5a9 100644 --- a/plugins/aircraft_replacer.py +++ b/plugins/aircraft_replacer.py @@ -19,7 +19,7 @@ class Plugin: self.plugin_manager.register_hook('on_add_object_server', self.on_add_object_server) # self.plugin_manager.register_hook('on_flight_data_server', self.on_flight_data_server) self.plugin_manager.register_hook('on_join_request', self.on_join_request) - + def on_add_object_server(self, data, player, messages_to_client, *args): packet = FSNETCMD_ADDOBJECT(data) @@ -43,18 +43,18 @@ class Plugin: # packet.position = [0,2000.0,0] # packet.velocity = [25,0,25] # messages_to_client.append(packet.to_packet()) - + # self.first_add_object = False # return False # return True - + def on_join_request(self, data, player, messages_to_client, message_to_server, *args): packet = FSNETCMD_JOINREQUEST(data) #Replace the aircraft: packet.aircraft = "EUROFIGHTER_TYPHOON" message_to_server.append(packet.to_packet()) return False - + # def on_receive(self, data, player, messages_to_client, *args): # if ENABLED: # if abs(player.aircraft.last_packet.g_value)> G_LIM: diff --git a/plugins/radar.py b/plugins/radar.py index 4695f06..7636dc4 100644 --- a/plugins/radar.py +++ b/plugins/radar.py @@ -58,7 +58,9 @@ class Plugin: return True else: try: - position_data = struct.pack("3f", 10000, 1000.0, 1000.0) + # This is a really arbitary position thats hard to reach, better would + # be to randomise it for every time the server starts. + position_data = struct.pack("3f", 10e7, 10e7, 10e7) if decode.packet_version == 4 or 5: updated_data = data[:14] + position_data + data[26:] else: -- cgit v1.2.3 From 30c7e24aa8de762a1b8c21476e9e8436db1b9826 Mon Sep 17 00:00:00 2001 From: Ritabrata Das Date: Sun, 23 Feb 2025 19:04:58 +0530 Subject: Work on discord chat sync, and fix smoke --- lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py | 4 ++-- proxy.py | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py index 8c5aec7..9ebfc00 100644 --- a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py +++ b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py @@ -198,7 +198,7 @@ class FSNETCMD_AIRPLANESTATE: #11 packet = self.buffer[:56] + pack('h',flag) + self.buffer[58:] return pack('I',len(packet)) + packet else: - flag = unpack('h',self.buffer[74:75])[0] + flag = unpack('h',self.buffer[74:76])[0] flag &= ~((255<<8)|2) flag |= (255<<8) | 2 @@ -213,7 +213,7 @@ class FSNETCMD_AIRPLANESTATE: #11 packet = self.buffer[:56] + pack('h',flag) + self.buffer[58:] return pack('I',len(packet)) + packet else: - flag = unpack('h',self.buffer[74:75])[0] + flag = unpack('h',self.buffer[74:76])[0] flag &= ~(8) packet = self.buffer[:74] + pack('h',flag) + self.buffer[76:] return pack('I',len(packet)) + packet diff --git a/proxy.py b/proxy.py index 9cb6a5e..d043b32 100644 --- a/proxy.py +++ b/proxy.py @@ -132,6 +132,8 @@ async def handle_client(client_reader, client_writer): elif packet_type == "FSNETCMD_JOINREQUEST": player.iff = FSNETCMD_JOINREQUEST(packet).iff + 1 + if DISCORD_ENABLED: + asyncio.create_task(discord_send_message(CHANNEL_ID, f"{player.username} has taken off! 🛫")) elif packet_type == "FSNETCMD_AIRPLANESTATE": player.aircraft.add_state(FSNETCMD_AIRPLANESTATE(packet)) #TODO: Do we want to convert all this to plugins? Probably not, but there is duplicated functionality @@ -147,6 +149,8 @@ async def handle_client(client_reader, client_writer): player.aircraft.just_repaired = False elif packet_type == "FSNETCMD_UNJOIN": + if DISCORD_ENABLED: + asyncio.create_task(discord_send_message(CHANNEL_ID, f"{player.username} has left the airplane! 🛬")) player.aircraft.reset() elif packet_type == "FSNETCMD_WEAPONCONFIG": @@ -248,12 +252,16 @@ async def start_proxy(): info(f"Proxy server listening on port {PROXY_PORT}") if DISCORD_ENABLED: await asyncio.create_task(monitor_channel(CHANNEL_ID, CONNECTED_PLAYERS)) + # await asyncio.create_task(set_bot_status_online()) async with server: await server.serve_forever() if __name__ == "__main__": try: + if DISCORD_ENABLED: + asyncio.run(discord_send_message(CHANNEL_ID, "✅ Server has started.")) asyncio.run(start_proxy()) except KeyboardInterrupt: + asyncio.run(discord_send_message(CHANNEL_ID, "❌ Server has stopped.")) info("Goodbye!") -- cgit v1.2.3