diff options
| -rw-r--r-- | lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py | 149 | ||||
| -rw-r--r-- | lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py | 8 | ||||
| -rw-r--r-- | lib/Player.py | 1 | ||||
| -rw-r--r-- | lib/plugin_manager.py | 11 | ||||
| -rw-r--r-- | plugins/radar.py | 78 | ||||
| -rw-r--r-- | plugins/refuel.py | 70 | ||||
| -rw-r--r-- | plugins/smoke_on_damage/Plugin.py | 4 | ||||
| -rw-r--r-- | proxy.py | 6 |
8 files changed, 211 insertions, 116 deletions
diff --git a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py index ebb2a6d..8c5aec7 100644 --- a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py +++ b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py @@ -74,6 +74,7 @@ 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]))) @@ -217,12 +218,6 @@ 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] @@ -237,81 +232,73 @@ 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): - 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() + buffer = pack("IfI", 11, remote_time, player_id) + buffer += pack("H", packet_version) + if packet_version == 4 or packet_version == 5: + 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)) + 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 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 15848fa..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 @@ -20,9 +20,6 @@ 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(), @@ -30,6 +27,3 @@ class FSNETCMD_JOINREQUEST: #8 if with_size: return pack("I",len(buffer))+buffer 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/Player.py b/lib/Player.py index 7f54914..8e2250a 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 = 1 def set_aircraft(self, aircraft:Aircraft): self.aircraft = aircraft diff --git a/lib/plugin_manager.py b/lib/plugin_manager.py index 279d601..07e28e6 100644 --- a/lib/plugin_manager.py +++ b/lib/plugin_manager.py @@ -58,13 +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_original = True + keep_orignal = True if hook_name in self.hooks: for callback in self.hooks[hook_name]: keep = callback(data, *args, **kwargs) - if keep == False: - keep_original = False - return keep_original + if type(keep) == bool: + if keep == False: + keep_orignal = False + else: + warning(f"Return value of {callback} is not a boolean") + return keep_orignal 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/radar.py b/plugins/radar.py new file mode 100644 index 0000000..cacc6c4 --- /dev/null +++ b/plugins/radar.py @@ -0,0 +1,78 @@ +""" +This plugin allows you have to Radar features similar to that of +original WW3 server. +""" +import math +from lib.PacketManager.packets import FSNETCMD_AIRPLANESTATE +from lib.YSchat import send +import struct +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_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): + # 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 + + @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 + + @staticmethod + def get_player_by_pilotid(pilotid:int): + for playerid in flying_players: + if playerid == pilotid: + return flying_players[playerid][0] + return None diff --git a/plugins/refuel.py b/plugins/refuel.py index e171953..12af66a 100644 --- a/plugins/refuel.py +++ b/plugins/refuel.py @@ -3,60 +3,91 @@ 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 ENABLED = True -REFUEL_RADIUS = 100 # in meters +REFUEL_RADIUS = 500 +# in meters, recomended to set +100-200m more than +# required range to compensate for distance lag caused by network. +FUEL_RATE = 50 # in kg/s (aprroximately a second, timing is not accurate) refuelers = {} refueling = {} class Plugin: def __init__(self): - def __init__(self): - self.plugin_manager = None + self.plugin_manager = None def register(self, plugin_manager): self.plugin_manager = plugin_manager self.plugin_manager.register_command('refuel', self.refuel) - self.plugin_manager.register_command('k', self.refueler) + 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 refuelers: + if player in refueling: + a = YSchat.message("You cannot be refueled while being a refueler") + + elif player in refuelers: + 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 and have same IFF") refuelers[player] = [0, [], False] + message_to_client.append(a) def refuel(self, full_message, player, message_to_client, message_to_server): #a = FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITFUEL", "3750kg", True) #message_to_client.append(a) #print(player in refueling) - if player in refueling: + if player in refuelers: + a = YSchat.message("You cannot be a refueler while being refueled") + elif player in refueling: + 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 and have same IFF") refueling[player] = [0, []] + message_to_client.append(a) def on_flight_data(self, data, player, message_to_client, message_to_server): decode = FSNETCMD_AIRPLANESTATE(data) if player in refueling: - for player in refuelers: - refueling[player] = [decode.fuel, decode.position] - if self.in_range(refuelers[player][1], decode.position): - print("here!") - refuelers[player][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+100}kg", True) - message_to_client.append(a) - else: - refuelers[player][2] = False + for refueler in refuelers: + 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 elif player in refuelers: refuelers[player] = [decode.fuel, decode.position, refuelers[player][2]] - if decode.fuel-100 > 0 and refuelers[player][2]: - a = FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITFUEL", f"{decode.fuel-5}kg", True) + 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): @@ -65,7 +96,6 @@ class Plugin: # 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) - print(dist) if dist < REFUEL_RADIUS: return True else: diff --git a/plugins/smoke_on_damage/Plugin.py b/plugins/smoke_on_damage/Plugin.py index 12effc8..ed7fcf7 100644 --- a/plugins/smoke_on_damage/Plugin.py +++ b/plugins/smoke_on_damage/Plugin.py @@ -38,7 +38,9 @@ class Plugin: message_to_client.append(FSNETCMD_AIRCMD.set_afterburner(player.aircraft.id, False, True)) - return False + return False + else: + return True def on_weapon_config(self, data, player, message_to_client, message_to_server): if ENABLED: @@ -117,9 +117,6 @@ async def handle_client(client_reader, client_writer): try: - if packet_type == "FSNETCMD_AIRCMD": - print(FSNETCMD_AIRCMD.decode(packet)) - if packet_type == "FSNETCMD_LOGON": # keep_message = plugin_manager.triggar_hook('on_login', packet, player, message_to_client, message_to_server) # if not keep_message: @@ -133,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) |
