diff options
Diffstat (limited to 'lib/PacketManager/packets')
31 files changed, 1732 insertions, 0 deletions
diff --git a/lib/PacketManager/packets/FSNETCMD_ADDOBJECT.py b/lib/PacketManager/packets/FSNETCMD_ADDOBJECT.py new file mode 100644 index 0000000..ef7f785 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_ADDOBJECT.py @@ -0,0 +1,67 @@ +from struct import pack, unpack + +class FSNETCMD_ADDOBJECT: #5 + """ + This packet is sent by the server to add an object to the client. + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.object_type = None + self.net_type = None + self.object_id = None + self.iff = None + self.pos = [0,0,0] + self.atti = [0,0,0] + self.identifier = None + self.substrname = None + self.ysfid = None + self.flags = None + self.flags0 = None + self.outsideRadius = None + self.aircraft_class = None + self.aircraft_category = None + self.pilot = None + + if len(buffer)>=120 and should_decode: + self.decode() + + def decode(self): + self.object_type, self.net_type = unpack("HH", self.buffer[4:8]) + #If object_type = 0, then it's an aircraft, and client will send + # FSNETREADBACK_ADDAIRPLANE + #If object_types = 1, then it's a ground object, and client will send + # FSNETREADBACK_ADDGROUND + self.object_id = unpack("I", self.buffer[8:12])[0] + self.iff, _ = unpack("hh", self.buffer[12:16]) + self.pos = list(unpack("fff", self.buffer[16:28])) + self.atti = list(unpack("fff", self.buffer[28:40])) + self.identifier = unpack("32s", self.buffer[40:72])[0].decode().strip('\x00') + self.substrname = unpack("32s", self.buffer[72:104])[0].decode().strip('\x00') + self.ysfid = unpack("I", self.buffer[104:108])[0] + self.flags, self.flags0 = unpack("II", self.buffer[108:116]) + self.outsideRadius = unpack("f", self.buffer[116:120])[0] + + if len(self.buffer)>=128: + self.aircraft_class, self.aircraft_category = unpack("hh", self.buffer[120:124]) + #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') + + @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, + pilot=None, with_size:bool=False): + + buffer = pack('IHH', 5, object_type, net_type) + buffer += pack('IHHffffff', object_id, iff, 0, pos[0], pos[1], pos[2], atti[0], atti[1], atti[2]) + buffer += pack('32s32sI', identifier.encode(), substrname.encode(), ysfid) + buffer += pack('II', flags, flags0) + buffer += pack('f', outside_radius) + + if aircraft_class and aircraft_category: + buffer += pack("hhh", aircraft_class, aircraft_category, 0) + if pilot: + buffer += pack("32s", pilot.encode()) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_AIRCMD.py b/lib/PacketManager/packets/FSNETCMD_AIRCMD.py new file mode 100644 index 0000000..98d782c --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_AIRCMD.py @@ -0,0 +1,53 @@ +from struct import pack, unpack +from .constants import AIRCMD_KEYWORDS + +class FSNETCMD_AIRCMD: #30 + + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.aircraft_id = None + self.message = None + self.command = None + if should_decode: + self.decode() + + def decode(self): + self.aircraft_id = unpack("I", self.buffer[4:8])[0] + self.message = self.buffer[8:].decode("utf-8").strip("\x00") + if self.message.startswith('*'): + self.command = self.get_command_from_message(self.message) + + def get_command_from_message(self, message:str): + """ + If the messages are prefixed with a *, then it is usually an engine/.dat + command, such as WEIGFUEL being the weight of the fuel. + Command would be something like *43 1000 + """ + message = message[1:] + engine_code = message.split(" ")[0] + try: + command = int(engine_code) + command = AIRCMD_KEYWORDS[command] + except ValueError: + return None + value = message.split(" ")[1] + return command, value + + @staticmethod + def encode(aircraft_id:int, message:str, with_size:bool=False): + buffer = pack("I",30)+pack("I",aircraft_id)+message.encode("utf-8") + buffer = buffer + b"\x00" #Last padding + 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): + """ + This will set the payload of the aircraft, useful if you want to + load or unload passengers/cargo - for YSRP I use this to load and unload + on mission start and end. + """ + payload = str(payload) + message = f"INITLOAD {payload} {units}" + return FSNETCMD_AIRCMD.encode(aircraft_id, message, with_size) diff --git a/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py new file mode 100644 index 0000000..071db5e --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_AIRPLANESTATE.py @@ -0,0 +1,301 @@ +from struct import pack, unpack +from math import pi +import math + +class FSNETCMD_AIRPLANESTATE: #11 + """ + This packet is sent by the client to the server to update the state of the aircraft. + The server sends this to the client to update the state of the aircraft. + + Versions: + Version 0: vh, vp and vr are 16bit shorts + >= 1: vh, vp and vr are 32bit integer appended at the end. Because ...why? + >=2: includes thrust vector, reverser and bombbay + >=3: idOnServer is 32bit int + 4 and 5: Short version of vh, vp and vr + 4: thrust vector and bombbay + 5: no thrust vector or bombbay + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.remote_time = None + self.player_id = None + self.packet_version = None + self.position = [0,0,0] + self.atti = [0,0,0] + self.velocity = [0,0,0] + self.atti_velocity = [0,0,0] + self.smoke_oil = None + self.fuel = None + self.payload = None + self.flight_state = None + self.vgw = None + self.spoiler = None + self.landing_gear = None + self.flap = None + self.brake = None + self.flags = { + "ab": None, + "firing": None, + "smoke": None, + "nav_lights": False, + "beacon": False, + "strobe": False, + "landing_lights": False, + } + self.gun_ammo = None + self.rocket_ammo = None + self.aam = None + self.agm = None + self.bomb = None + self.life = None + self.g_value = None + self.throttle = None + self.elev = None + self.ail = None + self.rud = None + self.trim = None + self.thrust_vector = { + "vector": None, + "reverser": None + } + self.bomb_bay_info = None + if should_decode: + self.decode() + + def decode(self): + self.remote_time, self.player_id = unpack("fI", self.buffer[4:12]) + self.packet_version = unpack("h", self.buffer[12:14])[0] + + if self.packet_version == 4 or self.packet_version == 5: + + self.position = list(unpack("fff", self.buffer[14:26])) + # 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) + + 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), + unpack("HHH", self.buffer[38:44]))) + self.smoke_oil = unpack("h", self.buffer[44:46])[0] + + self.fuel = unpack("I", self.buffer[46:50])[0] + + self.payload = unpack("h", self.buffer[50:52])[0] + + self.flight_state, self.vgw = unpack("BB", self.buffer[52:54]) + self.vgw = self.vgw / 255.0 + + c = unpack("B", self.buffer[54:55])[0] + self.spoiler = (c >> 4 & 15) / 15.0 #Bitshift 4 to the right, then mask with 15 + self.landing_gear = (c & 15) / 15.0 #Mask with 15 + + c = unpack("B", self.buffer[55:56])[0] + self.flap = (c >> 4 & 15) / 15.0 + self.brake = (c & 15) / 15.0 + + flags = unpack("h", self.buffer[56:58])[0] + self.flags["ab"] = bool(flags & 1) # Last bit + self.flags["firing"] = bool(flags &8) + self.flags["smoke"] = 0 + if flags & 2: + + 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: + self.flags["nav_lights"] = True + if flags & 64: + self.flags["strobe"] = True + if flags & 128: + self.flags["landing_lights"] = True + + self.gun_ammo, self.rocket_ammo, self.aam, self.agm, self.bomb = unpack("HHBBB", self.buffer[58:65]) + self.life = unpack("B", self.buffer[65:66])[0] + + self.g_value = unpack("b", self.buffer[66:67])[0]/10.0 + + self.throttle = unpack("B", self.buffer[67:68])[0]/99.0 + self.elev = unpack("b", self.buffer[68:69])[0]/99.0 + self.ail = unpack("b", self.buffer[69:70])[0]/99.0 + self.rud = unpack("b", self.buffer[70:71])[0]/99.0 + self.trim = unpack("b", self.buffer[71:72])[0]/99.0 + + if self.packet_version == 4: + c = unpack("B", self.buffer[71:72])[0] + self.thrust_vector["vector"] = (c >> 4 & 15) / 15.0 + self.thrust_vector["reverser"] = (c & 15) / 15.0 + c = unpack("B", self.buffer[72:73])[0] + self.bomb_bay_info = (c >> 4 & 15) / 15.0 + + else: + + self.position = list(unpack("fff", self.buffer[16:28])) + 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 + + self.gun_ammo, self.aam, self.agm, self.bomb, self.smoke_oil = unpack("hhhhh", self.buffer[48:58]) + self.fuel = unpack("f", self.buffer[58:62])[0] + self.payload = unpack("f", self.buffer[62:66])[0] + + self.life = unpack("h", self.buffer[66:68])[0] + + self.flight_state, self.vgw = unpack("BB", self.buffer[68:70]) + self.vgw = self.vgw / 255.0 + self.spoiler = unpack("B", self.buffer[70:71])[0]/255.0 + self.landing_gear = unpack("B", self.buffer[71:72])[0]/255.0 + self.flap = unpack("B", self.buffer[72:73])[0]/255.0 + self.brake = unpack("B", self.buffer[73:74])[0]/255.0 + + flags = unpack("H", self.buffer[74:76])[0] + self.flags["ab"] = bool(flags & 1) + self.flags["firing"] = bool(flags & 8) + self.flags["smoke"] = 0 + if flags & 2: + self.flags["smoke"] = (flags >> 8) & 255 + if self.flags["smoke"] == 0: + self.flags["smoke"] = 255 + + self.throttle = unpack("B", self.buffer[76:77])[0]/99.0 + self.elev = unpack("b", self.buffer[77:78])[0]/99.0 + self.ail = unpack("b", self.buffer[78:79])[0]/99.0 + self.rud = unpack("b", self.buffer[79:80])[0]/99.0 + self.trim = unpack("b", self.buffer[80:81])[0]/99.0 + + self.rocket_ammo = unpack("H", self.buffer[81:83])[0] + + if self.packet_version >= 1: + + self.atti_velocity = list(map(lambda x: x / (pi / 32768.0), + unpack("fff", self.buffer[83:95]))) + + if self.packet_version >= 2: + self.thrust_vector["vector"] = unpack("B", self.buffer[95:96])[0]/255.0 + self.thrust_vector["reverser"] = unpack("B", self.buffer[96:97])[0]/255.0 + self.bomb_bay_info = unpack("B", self.buffer[97:98])[0]/255.0 + + def smoke(self): + if self.packet_version == 4 or self.packet_version == 5: + flag = unpack('h',self.buffer[56:58])[0] + flag &= ~((1<<8)|2) + flag |= (1<<8) |2 + flag |= (1<<9) + flag |= (1<<10) + 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 &= ~((255<<8)|2) + flag |= (255<<8) | 2 + print(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] + flag &= ~(8) + 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 &= ~(8) + packet = self.buffer[:74] + pack('h',flag) + self.buffer[76:] + return pack('I',len(packet)) + packet + + @staticmethod + def get_life(buffer:bytes): + version = unpack("h", buffer[12:14])[0] + if version == 5 or version == 4: + return unpack("B", buffer[65:66])[0] + else: + return unpack("H", buffer[66:68])[0] + + + @staticmethod + def encode(remote_time, player_id, packet_version, position, atti, velocity, atti_velocity, + 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 diff --git a/lib/PacketManager/packets/FSNETCMD_EMPTYPACKET.py b/lib/PacketManager/packets/FSNETCMD_EMPTYPACKET.py new file mode 100644 index 0000000..cfb35d6 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_EMPTYPACKET.py @@ -0,0 +1,19 @@ +from struct import pack + +class FSNETCMD_EMPTYPACKET: + """ + A template function for empty packets""" + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + if should_decode: + self.decode() + + def decode(self): + pass # There are no messages in this packet! + + @staticmethod + def encode(with_size:bool=False): #This will be extended by each func. + buffer = pack("I",14) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_ENVIRONMENT.py b/lib/PacketManager/packets/FSNETCMD_ENVIRONMENT.py new file mode 100644 index 0000000..4937fba --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_ENVIRONMENT.py @@ -0,0 +1,51 @@ +from struct import pack, unpack + +class FSNETCMD_ENVIRONMENT: #33 + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.day_night = None # 0 is day, 1 is night + self.flags = { + "fog":False, + "blackout":False, + "midair":False, + "can_land_anywhere":False + } + self.wind = [0,0,0] + self.visibility = None + if should_decode: + self.decode() + + def decode(self): + variables = unpack("IHHIffff", self.buffer[0:28]) + #0 is the packet type, 1 is just padding. + self.day_night = variables[2] + flags = variables[3] + self.wind = list(variables[4:7]) + self.visibility = variables[7] + self.flags["fog"] = bool(flags & 1) + if flags&8 == 1: #Server controls blackout: + self.flags["blackout"] = bool(flags & 4) + if flags&32 == 1: #Server controls midair: + self.flags["midair"] = bool(flags & 16) + if flags&128 == 1: #Server controls can_land_anywhere: + self.flags["can_land_anywhere"] = bool(flags & 64) + + @staticmethod + def encode(day_night, fog, blackout, midair, can_land_anywhere, wind, visibility, with_size:bool=False): + flags = 0 + if fog: + flags |= 1 + if blackout: + flags |= 4 + flags |=8 + if midair: + flags += 16 + flags += 32 + if can_land_anywhere: + flags += 64 + flags += 128 + buffer = pack("IHHIffff", 33, 0, day_night, flags, *wind, visibility) + if with_size: + return pack("I", len(buffer))+buffer + return buffer + diff --git a/lib/PacketManager/packets/FSNETCMD_ERROR.py b/lib/PacketManager/packets/FSNETCMD_ERROR.py new file mode 100644 index 0000000..327d38c --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_ERROR.py @@ -0,0 +1,22 @@ +from struct import pack, unpack +from .constants import ERROR_CODES + +class FSNETCMD_ERROR: #3 + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.error_code = None + self.error_message = None + if should_decode: + self.decode() + + def decode(self): + errorCode = unpack("I",self.buffer[4:8])[0] + if errorCode < len(ERROR_CODES): + self.error_message = ERROR_CODES[errorCode] + + @staticmethod + def encode(error_code, with_size:bool=False): + buffer = pack("I",3)+pack("I",error_code) + if with_size: + return pack("I",len(buffer))+buffer + return buffer diff --git a/lib/PacketManager/packets/FSNETCMD_GETDAMAGE.py b/lib/PacketManager/packets/FSNETCMD_GETDAMAGE.py new file mode 100644 index 0000000..1becb40 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_GETDAMAGE.py @@ -0,0 +1,43 @@ +from struct import pack, unpack +from .constants import FSWEAPON_DICT + +class FSNETCMD_GETDAMAGE: #22 + """ + Sent when an aircraft or ground target has taken damage + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.victim_id = None + self.victim_type = None + self.attacker_type = None + self.attacker_id = None + self.damage = None + self.died_of = None + self.weapon_type = None + if should_decode: + self.decode() + + def decode(self): + variables = unpack("IIIIIHHH", self.buffer[0:26]) + self.victim_id = variables[2] + self.victim_type = variables[1] + self.attacker_type = variables[3] + self.attacker_id = variables[4] + self.damage = variables[5] + self.died_of = variables[6] + 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, + weapon_type, with_size:bool=False): + 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) + if with_size: + return pack("I", len(buffer))+buffer + return buffer diff --git a/lib/PacketManager/packets/FSNETCMD_JOINAPPROVAL.py b/lib/PacketManager/packets/FSNETCMD_JOINAPPROVAL.py new file mode 100644 index 0000000..beb6ab9 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_JOINAPPROVAL.py @@ -0,0 +1,22 @@ +from struct import pack + +class FSNETCMD_JOINAPPROVAL: #9 + """ + When the server sends the "add aircraft" command, and + receves the readback from the client, they'll send this + It's an empty packet, but can be useful to know the client is about to join. + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + if should_decode: + self.decode() + + def decode(self): + pass + + @staticmethod + def encode(with_size:bool=False): + buffer = pack("I",9) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py b/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py new file mode 100644 index 0000000..7796599 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py @@ -0,0 +1,29 @@ +from struct import pack, unpack + +class FSNETCMD_JOINREQUEST: #8 + """ + The client sends a join request to the server with their iff, aircraft, start position, fuel and smoke + The server replies with the join request readback,The server replies with the join request readback + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.iff = None + self.aircraft = None + self.start_pos = None #It's the STP name + self.fuel = None + self.smoke = None + if should_decode: + self.decode() + + def decode(self): + self.iff, _, self.aircraft, self.start_pos, _, self.fuel, self.smoke = unpack("HH32s32sHHH", self.buffer[4:78]) + self.start_pos = self.start_pos.decode().strip('\x00') + self.aircraft = self.aircraft.decode().strip('\x00') + + @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 diff --git a/lib/PacketManager/packets/FSNETCMD_KILLSERVER.py b/lib/PacketManager/packets/FSNETCMD_KILLSERVER.py new file mode 100644 index 0000000..3e1b4ec --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_KILLSERVER.py @@ -0,0 +1,14 @@ +from struct import pack +from .FSNETCMD_EMPTYPACKET import FSNETCMD_EMPTYPACKET + +class FSNETCMD_KILLSERVER(FSNETCMD_EMPTYPACKET): #15 + """ + This is unimplemented in YS, but it would shutdown the server + The actual server functionality is disabled. + """ + @staticmethod + def encode(with_size:bool=False): + buffer = pack("I",15) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_LOADFIELD.py b/lib/PacketManager/packets/FSNETCMD_LOADFIELD.py new file mode 100644 index 0000000..2184f7d --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_LOADFIELD.py @@ -0,0 +1,30 @@ +from struct import pack, unpack + +class FSNETCMD_LOADFIELD: #4 + """ + This packet is sent by the server along with the field info. When received, + the client replies with the same packet. + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.field = None + self.fieldShortName = None + self.flags = None + self.pos = [0,0,0] + self.atti = [0,0,0] + if len(buffer) == 64 and should_decode: + self.decode() + + def decode(self): + self.field, self.flags, self.pos[0], self.pos[1], self.pos[2], self.atti[0], self.atti[1], self.atti[2] = unpack("32sIffffff", self.buffer[4:]) + self.fieldShortName = self.field.split(b'\x00')[0].decode() + + @staticmethod + def encode(field, flags, pos, atti, with_size:bool=False): + if isinstance(field, str): + field = field.encode() + buffer = pack("I32sIffffff", 4, field, flags, pos[0], pos[1], + pos[2], atti[0], atti[1], atti[2]) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_LOCKON.py b/lib/PacketManager/packets/FSNETCMD_LOCKON.py new file mode 100644 index 0000000..2b3d01a --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_LOCKON.py @@ -0,0 +1,31 @@ +from struct import pack, unpack + +class FSNETCMD_LOCKON: #18 + """ + Sent from server to client, and client to server + when someone locks onto someone else + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.locker_id = None + self.locker_is_air = False + self.lockee_id = None + self.lockee_is_air = False + if should_decode: + self.decode() + + def decode(self): + self.locker_id, self.locker_is_air, self.lockee_id, self.lockee_is_air = unpack("IIII", self.buffer[4:20]) + self.locker_is_air = bool(self.locker_is_air) + self.lockee_is_air = bool(self.lockee_is_air) + + @staticmethod + def encode(locker_id, locker_is_air, lockee_id, lockee_is_air, with_size:bool=False): + if isinstance(locker_is_air, bool): + locker_is_air = int(locker_is_air) + if isinstance(lockee_is_air, bool): + lockee_is_air = int(lockee_is_air) + buffer = pack("I",18)+pack("IIII", locker_id, locker_is_air, lockee_id, lockee_is_air) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_LOGOFF.py b/lib/PacketManager/packets/FSNETCMD_LOGOFF.py new file mode 100644 index 0000000..bc03a0b --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_LOGOFF.py @@ -0,0 +1,19 @@ +from struct import pack + +class FSNETCMD_LOGOFF: #2 + """ + This is a logoff packet, used to logoff from the server. + It appeasr to be un-used by YS. Including it for completeness. + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + + def decode(self): + pass + + @staticmethod + def encode( with_size:bool=False): + buffer = pack("I",2) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_LOGON.py b/lib/PacketManager/packets/FSNETCMD_LOGON.py new file mode 100644 index 0000000..9848590 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_LOGON.py @@ -0,0 +1,58 @@ +from struct import pack, unpack + +class FSNETCMD_LOGON: #1 + """ + This is a logon packet, used to logon to the server. + The client sends this to the server on login, and the server replies to acknowledge. + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.version = None + self.username = None + self.alias = None #Alias is the longer form of the username, if they're longer than 16 chars + + #If the YS version is 2018 (or YSCE) then the server will reply with an + # empty packet on login-complete. + if len(self.buffer)>5 and should_decode: + #We can decode the packet. + self.decode() + + def decode(self): + self.username, self.version = unpack("16sI",self.buffer[4:24]) + if len(self.buffer)>24: + self.alias = self.buffer[24:].decode().strip('\x00') + else: + self.alias = self.username + if isinstance(self.username,bytes): + self.username = self.username.decode().strip('\x00') + if isinstance(self.alias,bytes): + self.alias = self.alias.decode().strip('\x00') + + + @staticmethod #Method to create a logon packet, if required. + def encode(username, version, with_size:bool=False): + if len(username)>15: + shortform = username[:15] + alias = username + else: + shortform = username + alias = None + if isinstance(shortform,str): + shortform = shortform.encode() + buffer = pack("I16sI", 1, shortform, version) + if alias: + if isinstance(alias,str): + alias = alias.encode() + if len(alias)<200: + alias = alias.ljust(200,b'\x00') + alias += b'\x00\x00\x00\x00' + buffer += alias + + if with_size: + return pack("I",len(buffer))+buffer + + return buffer + + @staticmethod + def alter_version(buffer:bytes, new_version:int): + return buffer[:20]+pack("I",new_version)+buffer[24:]
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_MISSILELAUNCH.py b/lib/PacketManager/packets/FSNETCMD_MISSILELAUNCH.py new file mode 100644 index 0000000..ad03128 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_MISSILELAUNCH.py @@ -0,0 +1,97 @@ +from struct import pack, unpack +from .constants import FSWEAPON_DICT, GUIDEDWEAPONS +from lib.Aircraft import Aircraft +from math import pi +import random + +class FSNETCMD_MISSILELAUNCH: #20 + """ + Sent when a missile has been launched + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.weapon_type = None + self.position = [0,0,0] + self.atti = [0,0,0] + self.velocity = None + self.life_remaining = None + self.power = None + self.fired_by_aircraft = None + self.fired_by = None + self.v_max = None + self.mobility = None + self.radar = None + self.fired_at_aircraft = None + self.fired_at = None + if should_decode: + self.decode() + + def decode(self): + print(self.buffer) + # _ = unpack("I", self.buffer[:4])[0] #Packet type + # IH # 6 + # fff # 12 + # fff # 12 + # ffH #10 + # II # 8 + self.weapon_type = unpack("H", self.buffer[4:6])[0] + self.position = list(unpack("fff", self.buffer[6:18])) + self.atti = list(unpack("fff", self.buffer[18:30])) + self.velocity, self.life_remaining, self.power = unpack("ffH", self.buffer[30:40]) + self.fired_by_aircraft = unpack("I", self.buffer[40:44])[0] + self.fired_by = unpack("I", self.buffer[44:48])[0] + if self.weapon_type in FSWEAPON_DICT: + self.weapon_type = FSWEAPON_DICT[self.weapon_type] + + if self.weapon_type in GUIDEDWEAPONS: + self.v_max, self.mobility, self.radar = unpack("fff", self.buffer[48:60]) + self.fired_at_aircraft = bool(unpack("I", self.buffer[60:64])[0]) + self.fired_at = unpack("I", self.buffer[64:68])[0] + elif self.weapon_type == "FSWEAPON_FLARE": + self.v_max = unpack("f", self.buffer[48:52])[0] + + + + @staticmethod + def encode(weapon_type, position, atti, velocity, life_remaining, power, + fired_by_aircraft, fired_by, v_max=1000, mobility=0, + radar=0, fired_at_aircraft=False, fired_at=0, with_size:bool=False): + if weapon_type in FSWEAPON_DICT and isinstance(weapon_type,int): + weapon_type_name = FSWEAPON_DICT[weapon_type] + else: + weapon_type_name = weapon_type + weapon_type = list(FSWEAPON_DICT.keys())[list(FSWEAPON_DICT.values()).index(weapon_type)] + buffer = pack("I",20) #Packet type 0:4 + + buffer += pack("H", weapon_type) #Weapon type 4:6 + buffer += pack("f", position[0]) #6:10 + buffer += pack("f", position[1]) #10:14 + buffer += pack("f", position[2]) #Position #14:18 + buffer += pack("f", atti[0]) #18:22 + buffer += pack("f", atti[1]) #22:26 + buffer += pack("f", atti[2]) #Attitude #26:30 + buffer += pack("ffH", velocity, life_remaining, power) #Velocity, life remaining, power #30:40 + buffer += pack("II",fired_by_aircraft,fired_by) #Fired by aircraft, fired by #40:48 + print(buffer) + if weapon_type_name in GUIDEDWEAPONS: + buffer += pack("fff", v_max, mobility, radar) + if isinstance(fired_at_aircraft, bool): + fired_at_aircraft = int(fired_at_aircraft) + buffer += pack("II", fired_at_aircraft, fired_at) + if weapon_type_name == "FSWEAPON_FLARE": + buffer += pack("f", v_max) + + if with_size: + return pack("I",len(buffer))+buffer + return buffer + + @staticmethod + def drop_bombs(aircraft:Aircraft): + position = aircraft.position + atti = aircraft.attitude + # atti = [(value*(32768/ pi)) for value in atti] + atti[2] =0 + weapon_type = random.randint(0,13) + packet = FSNETCMD_MISSILELAUNCH.encode(weapon_type, position=position, atti=atti, velocity=20, life_remaining=30000, power=999, fired_by_aircraft=0, fired_by=aircraft.id, v_max=1000, with_size=True) + print(packet) + return packet
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_NULL.py b/lib/PacketManager/packets/FSNETCMD_NULL.py new file mode 100644 index 0000000..5e35777 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_NULL.py @@ -0,0 +1,16 @@ +from struct import pack + +class FSNETCMD_NULL: #0 + """ + This is a 'null' packet, there is nothing to process. + """ + def __init__(self,buffer:bytes, should_decode:bool=True): + pass + + def decode(self): + return None + + def encode(self, with_size:bool=False): + if with_size: + return pack("II",4,0) + return pack("I", 0) diff --git a/lib/PacketManager/packets/FSNETCMD_PREPARESIMULATION.py b/lib/PacketManager/packets/FSNETCMD_PREPARESIMULATION.py new file mode 100644 index 0000000..4cfef8f --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_PREPARESIMULATION.py @@ -0,0 +1,14 @@ +from struct import pack +from .FSNETCMD_EMPTYPACKET import FSNETCMD_EMPTYPACKET + +class FSNETCMD_PREPARESIMULATION(FSNETCMD_EMPTYPACKET): #16 + """ + This is sent from server to client when they've almost finished + logging in. + """ + @staticmethod + def encode(with_size:bool=False): + buffer = pack("I",16) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_READBACK.py b/lib/PacketManager/packets/FSNETCMD_READBACK.py new file mode 100644 index 0000000..0fd4ead --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_READBACK.py @@ -0,0 +1,39 @@ +from struct import pack, unpack + +class FSNETCMD_READBACK: #6 + """ + Sent from client to server and back to acknowledge various packets. + + * Client sends FSNETREADBACK_ADDAIRPLAN or FSNETREADBACK_ADDGROUND to + acknowledge FSNETCMD_ADDOBJECT + * Client sends FSNETREADBACK_REMOVEAIRPLANE or FSNETREADBACK_REMOVEGROUND + to acknowledge FSNETCMD_REMOVEAIRPLANE or FSNETCMD_REMOVEGROUND + * Client sends FSNETREADBACK_ENVIRONMENT to acknowledge FSNETCMD_ENVIRONMENT + * Client sends FSNETREADBACK_JOINREQUEST to acknowledge FSNETCMD_JOINREQUEST + * Client sends FSNETREADBACK_PREPARE to acknowledge FSNETCMD_PREPARESIMULATION + * Client sends FSNETREADBACK_USEMISSILE to acknowledge FSNETCMD_USEMISSILE + * Client sends FSNETREADBACK_USEUNGUIDEDWEAPON to acknowledge FSNETCMD_USEUNGUIDEDWEAPON + * Client sends FSNETREADBACK_CTRLSHOWUSERNAME to acknowledge FSNETCMD_CTRLSHOWUSERNAME + + * Server sends FSNETREADBACK_JOINREQUEST to acknowledge FSNETCMD_JOINREQUEST - + Will punt the user if the server receives this from them + * There are probably more, but I've not gone into much detail here yet. + + """ + + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.read_back_type = None + self.read_back_param = None + if should_decode: + self.decode() + + def decode(self): + self.read_back_type, _, self.read_back_param = unpack("HHI", self.buffer[4:12]) + + @staticmethod + def encode(read_back_type, read_back_param, with_size:bool=False): + buffer = pack("IhhI", 6, read_back_type, 0, read_back_param) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_REJECTJOINREQ.py b/lib/PacketManager/packets/FSNETCMD_REJECTJOINREQ.py new file mode 100644 index 0000000..e19a007 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_REJECTJOINREQ.py @@ -0,0 +1,21 @@ +from struct import pack + +class FSNETCMD_REJECTJOINREQ: #10 + """ + If the server rejects the join request, they'll send this. + It's usually followed by a chat message saying why. + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + if should_decode: + self.decode() + + def decode(self): + pass + + @staticmethod + def encode(with_size:bool=False): + buffer = pack("I",10) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_REMOVEAIRPLANE.py b/lib/PacketManager/packets/FSNETCMD_REMOVEAIRPLANE.py new file mode 100644 index 0000000..b880a3e --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_REMOVEAIRPLANE.py @@ -0,0 +1,13 @@ +from .FSNETCMD_UNJOIN import FSNETCMD_UNJOIN +from struct import pack + +class FSNETCMD_REMOVEAIRPLANE(FSNETCMD_UNJOIN): #13 + """ + Seems to just be the same as 12. No idea why Soji made 2. + We'll just extend UNJOIN.""" + @staticmethod + def encode(object_id, explosion, with_size:bool=False): + buffer = pack("I", 12)+pack("IIhh", 13, object_id, explosion) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_REMOVEGROUND.py b/lib/PacketManager/packets/FSNETCMD_REMOVEGROUND.py new file mode 100644 index 0000000..9861add --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_REMOVEGROUND.py @@ -0,0 +1,13 @@ +from struct import pack +from .FSNETCMD_UNJOIN import FSNETCMD_UNJOIN + +class FSNETCMD_REMOVEGROUND(FSNETCMD_UNJOIN): #19 + """ + This is the same as FSNETCMD_UNJOIN/Remove aircraft, but for ground objects. + """ + @staticmethod + def encode(object_id, explosion, with_size:bool=False): + buffer =pack("I",19)+pack("IIhh", 19, object_id, explosion) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_REPORTSCORE.py b/lib/PacketManager/packets/FSNETCMD_REPORTSCORE.py new file mode 100644 index 0000000..96dfe68 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_REPORTSCORE.py @@ -0,0 +1,50 @@ +from struct import pack, unpack +from . import FSWEAPON_DICT +""" +This is the score card for when an aircraft/ground object is destroyed. +""" +class FSNETCMD_REPORTSCORE: + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.scored = None + self.weapon_type = None + self.position = [0,0,0] + self.score_time = None + self.killer_id = None + self.killer_name = None + self.killer_plane = None + self.victim_id = None + self.victim_name = None + self.victim_plane = None + + if should_decode: + self.decode() + + def decode(self): + self.scored = bool(unpack("H", self.buffer[4:6])[0]) + self.weapon_type = unpack("H", self.buffer[6:8])[0] + if self.weapon_type in FSWEAPON_DICT: + self.weapon_type = FSWEAPON_DICT[self.weapon_type] + self.position = list(unpack("fff", self.buffer[8:20])) + self.score_time = unpack("f", self.buffer[20:24])[0] + self.killer_id = unpack("I", self.buffer[28:32])[0] + self.killer_name = self.buffer[32:64].decode("utf-8").rstrip("\x00") + self.killer_plane = self.buffer[64:96].decode("utf-8").rstrip("\x00") + self.victim_id = unpack("I", self.buffer[100:104])[0] + self.victim_name = self.buffer[104:136].decode("utf-8").rstrip("\x00") + self.victim_plane = self.buffer[136:168].decode("utf-8").rstrip("\x00") + + @staticmethod + def encode(scored, weapon_type, position, score_time, killer_id, killer_name, + killer_plane, victim_id, victim_name, victim_plane, with_size:bool=False): + 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("IHHffffII32s32sII32s32s", 46, + int(scored), weapon_type, *position, score_time, 0, killer_id, + killer_name.encode("utf-8"), killer_plane.encode("utf-8"),0, + victim_id, victim_name.encode("utf-8"), victim_plane.encode("utf-8")) + if with_size: + return pack("I", len(buffer))+buffer + + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_REQUESTTESTAIRPLANE.py b/lib/PacketManager/packets/FSNETCMD_REQUESTTESTAIRPLANE.py new file mode 100644 index 0000000..f92667b --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_REQUESTTESTAIRPLANE.py @@ -0,0 +1,14 @@ +from struct import pack +from .FSNETCMD_EMPTYPACKET import FSNETCMD_EMPTYPACKET + +class FSNETCMD_REQUESTTESTAIRPLANE(FSNETCMD_EMPTYPACKET): #14 + """ + Spawns an F-15C at NORTH1000_01 in dogfight mode + There is no way of calling this from YS. + """ + @staticmethod + def encode(with_size:bool=False): + buffer = pack("I",14) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_SERVER_FORCE_JOIN.py b/lib/PacketManager/packets/FSNETCMD_SERVER_FORCE_JOIN.py new file mode 100644 index 0000000..a94aa17 --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_SERVER_FORCE_JOIN.py @@ -0,0 +1,14 @@ +from struct import pack, unpack +from .FSNETCMD_NULL import FSNETCMD_NULL + +class FSNETCMD_SERVER_FORCE_JOIN(FSNETCMD_NULL): + """ + Sent by the server to force the player to join + This literally just presses J. Wild. + """ + @staticmethod + def encode(player_id, with_size:bool=False): + buffer = pack("I", 47) + if with_size: + return pack("I", len(buffer)) + buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_SMOKECOLOR.py b/lib/PacketManager/packets/FSNETCMD_SMOKECOLOR.py new file mode 100644 index 0000000..76e254d --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_SMOKECOLOR.py @@ -0,0 +1,25 @@ +from struct import unpack, pack + +class FSNETCMD_SMOKECOLOR: #7 + """The server sends this to the client when another aircraft + joins with smoke, and the client sends it to the server if + they're joining with smoke. + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.aircraft_id = None + self.smoke_quantity = None + self.color = None + if should_decode: + self.decode() + + def decode(self): + self.aircraft_id, self.smoke_quantity, r, g, b = unpack("IBBBB", self.buffer[4:9]) + self.color = (r,g,b) + + @staticmethod + def encode(aircraft_id, smoke_quantity, color, with_size:bool=False): + buffer = pack("IIBBBB", 7, aircraft_id, smoke_quantity, color[0], color[1], color[2]) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_TESTPACKET.py b/lib/PacketManager/packets/FSNETCMD_TESTPACKET.py new file mode 100644 index 0000000..58c9bfc --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_TESTPACKET.py @@ -0,0 +1,14 @@ +from struct import pack +from .FSNETCMD_EMPTYPACKET import FSNETCMD_EMPTYPACKET + +class FSNETCMD_TESTPACKET(FSNETCMD_EMPTYPACKET): #17 + """ + This is just an empty packet. + Just overwrite the encode. + """ + @staticmethod + def encode(with_size:bool=False): + buffer = pack("I",17) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_TEXTMESSAGE.py b/lib/PacketManager/packets/FSNETCMD_TEXTMESSAGE.py new file mode 100644 index 0000000..f524b9f --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_TEXTMESSAGE.py @@ -0,0 +1,24 @@ +from struct import pack +import re + +class FSNETCMD_TEXTMESSAGE: #32 + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.raw_message = None + self.user = None + self.message = None + if should_decode: + self.decode() + + def decode(self): + self.raw_message = self.buffer[12:].decode("utf-8").strip("\x00") + match = re.match(r"^\(([^)]+)\)(.+)", self.raw_message) + if match: + self.user. self.message = match.groups() + + @staticmethod + def encode(message:str, with_size:bool=False): + buffer = pack("III",32,0,0)+message.encode("utf-8")+b"\x00" + if with_size: + return pack("I",len(buffer))+buffer + return buffer diff --git a/lib/PacketManager/packets/FSNETCMD_UNJOIN.py b/lib/PacketManager/packets/FSNETCMD_UNJOIN.py new file mode 100644 index 0000000..1f991ae --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_UNJOIN.py @@ -0,0 +1,26 @@ +from struct import pack, unpack + +class FSNETCMD_UNJOIN: #12 + """ + This is sent client to server when the client leaves. + The explosion doesn't seem to actually do anything in YS. + There is a comment saying "add explosion here"... Not helpful. + """ + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.object_id = None + self.explosion = None + if should_decode: + self.decode() + + def decode(self): + variables = unpack("IIhh", self.buffer[0:12]) + self.object_id = variables[1] + self.explosion = bool(variables[2]) + + @staticmethod + def encode(object_id, explosion, with_size:bool=False): + buffer = pack("I", 12)+pack("IIhh", 12, object_id, explosion) + if with_size: + return pack("I",len(buffer))+buffer + return buffer
\ No newline at end of file diff --git a/lib/PacketManager/packets/FSNETCMD_WEAPONCONFIG.py b/lib/PacketManager/packets/FSNETCMD_WEAPONCONFIG.py new file mode 100644 index 0000000..aa4876b --- /dev/null +++ b/lib/PacketManager/packets/FSNETCMD_WEAPONCONFIG.py @@ -0,0 +1,55 @@ +from struct import pack, unpack +from .constants import FSWEAPON_DICT + +class FSNETCMD_WEAPONCONFIG: + def __init__(self, buffer:bytes, should_decode:bool=True): + self.buffer = buffer + self.aircraft_id = None + self.number = None + self.weapon_config = {} + + + if should_decode: + self.decode() + + def decode(self): + self.aircraft_id, self.number = unpack("Ih",self.buffer[4:10]) + self.weapon_config = {} + self.number = self.number & (~1) + + for i in range(self.number // 2): + typ, count = unpack("hh",self.buffer[10+i*4:14+i*4]) + if typ in FSWEAPON_DICT: + typ = FSWEAPON_DICT[typ] + if "SMOKE" in typ: + #the count is actually the RGB value, formatted like a ballbag. + r = (count >>10)&31 + g = (count >>5)&31 + b = count&31 + r = (r>>2)+(r<<3) + g = (g>>2)+(g<<3) + b = (b>>2)+(b<<3) + count = [r,g,b] + self.weapon_config[typ] = count + print(self.weapon_config) + + @staticmethod + def encode(aircraft_id:int, weapon_config:dict, with_size:bool=False): + buffer = pack("IIh", 36, aircraft_id, len(weapon_config)*2) + for typ, count in weapon_config.items(): + if typ in FSWEAPON_DICT.values() and isinstance(typ, str): + typ = [k for k,v in FSWEAPON_DICT.items() if v == typ][0] + if typ >=32 and typ <=39 and isinstance(count,list): #Smoke + r,g,b = count + r = (r*31)/255 + g = (g*31)/255 + b = (b*31)/255 + count = (int(r)<<10)+(int(g)<<5)+int(b) + buffer += pack("hh", typ, count) + if with_size: + return pack("I",len(buffer))+buffer + return buffer + + @staticmethod + def addSmoke(aircraft_id:int): + return FSNETCMD_WEAPONCONFIG.encode(aircraft_id, {32:[66,66,66],33:[66,66,66],34:[66,66,66]}, True) diff --git a/lib/PacketManager/packets/__init__.py b/lib/PacketManager/packets/__init__.py new file mode 100644 index 0000000..43abcf0 --- /dev/null +++ b/lib/PacketManager/packets/__init__.py @@ -0,0 +1,66 @@ +from .FSNETCMD_LOGON import FSNETCMD_LOGON +from .FSNETCMD_LOGOFF import FSNETCMD_LOGOFF +from .FSNETCMD_ERROR import FSNETCMD_ERROR +from .FSNETCMD_LOADFIELD import FSNETCMD_LOADFIELD +from .FSNETCMD_ADDOBJECT import FSNETCMD_ADDOBJECT +from .FSNETCMD_READBACK import FSNETCMD_READBACK +from .FSNETCMD_SMOKECOLOR import FSNETCMD_SMOKECOLOR +from .FSNETCMD_JOINREQUEST import FSNETCMD_JOINREQUEST +from .FSNETCMD_JOINAPPROVAL import FSNETCMD_JOINAPPROVAL +from .FSNETCMD_REJECTJOINREQ import FSNETCMD_REJECTJOINREQ +from .FSNETCMD_AIRPLANESTATE import FSNETCMD_AIRPLANESTATE +from .FSNETCMD_UNJOIN import FSNETCMD_UNJOIN +from .FSNETCMD_REMOVEAIRPLANE import FSNETCMD_REMOVEAIRPLANE +from .FSNETCMD_REQUESTTESTAIRPLANE import FSNETCMD_REQUESTTESTAIRPLANE +from .FSNETCMD_KILLSERVER import FSNETCMD_KILLSERVER +from .FSNETCMD_PREPARESIMULATION import FSNETCMD_PREPARESIMULATION +from .FSNETCMD_TESTPACKET import FSNETCMD_TESTPACKET +from .FSNETCMD_LOCKON import FSNETCMD_LOCKON +from .FSNETCMD_REMOVEGROUND import FSNETCMD_REMOVEGROUND +from .FSNETCMD_MISSILELAUNCH import FSNETCMD_MISSILELAUNCH +#from .FSNETCMD_GROUNDSTATE import FSNETCMD_GROUNDSTATE +from .FSNETCMD_GETDAMAGE import FSNETCMD_GETDAMAGE +#from .FSNETCMD_GNDTURRETSTATE import FSNETCMD_GNDTURRETSTATE +#from .FSNETCMD_SETTESTAUTOPILOT import FSNETCMD_SETTESTAUTOPILOT +#from .FSNETCMD_REQTOBESIDEWINDOWOFSVR import FSNETCMD_REQTOBESIDEWINDOWOFSVR +#from .FSNETCMD_ASSIGNSIDEWINDOW import FSNETCMD_ASSIGNSIDEWINDOW +#from .FSNETCMD_RESENDAIRREQUEST import FSNETCMD_RESENDAIRREQUEST +#from .FSNETCMD_RESENDGNDREQUEST import FSNETCMD_RESENDGNDREQUEST +#from .FSNETCMD_VERSIONNOTIFY import FSNETCMD_VERSIONNOTIFY +from .FSNETCMD_AIRCMD import FSNETCMD_AIRCMD +#from .FSNETCMD_USEMISSILE import FSNETCMD_USEMISSILE +from .FSNETCMD_TEXTMESSAGE import FSNETCMD_TEXTMESSAGE +from .FSNETCMD_ENVIRONMENT import FSNETCMD_ENVIRONMENT +#from .FSNETCMD_NEEDRESENDJOINAPPROVAL import FSNETCMD_NEEDRESENDJOINAPPROVAL +#from .FSNETCMD_REVIVEGROUND import FSNETCMD_REVIVEGROUND +from .FSNETCMD_WEAPONCONFIG import FSNETCMD_WEAPONCONFIG +#from .FSNETCMD_LISTUSER import FSNETCMD_LISTUSER +#from .FSNETCMD_QUERYAIRSTATE import FSNETCMD_QUERYAIRSTATE +#from .FSNETCMD_USEUNGUIDEDWEAPON import FSNETCMD_USEUNGUIDEDWEAPON +#from .FSNETCMD_AIRTURRETSTATE import FSNETCMD_AIRTURRETSTATE +#from .FSNETCMD_CTRLSHOWUSERNAME import FSNETCMD_CTRLSHOWUSERNAME +#from .FSNETCMD_CONFIRMEXISTENCE import FSNETCMD_CONFIRMEXISTENCE +#from .FSNETCMD_CONFIGSTRING import FSNETCMD_CONFIGSTRING +#from .FSNETCMD_LIST import FSNETCMD_LIST +#from .FSNETCMD_GNDCMD import FSNETCMD_GNDCMD +#from .FSNETCMD_REPORTSCORE import FSNETCMD_REPORTSCORE +#from .FSNETCMD_SERVER_FORCE_JOIN import FSNETCMD_SERVER_FORCE_JOIN +#from .FSNETCMD_FOGCOLOR import FSNETCMD_FOGCOLOR +#from .FSNETCMD_SKYCOLOR import FSNETCMD_SKYCOLOR +#from .FSNETCMD_GNDCOLOR import FSNETCMD_GNDCOLOR +#from .FSNETCMD_RESERVED_FOR_LIGHTCOLOR import FSNETCMD_RESERVED_FOR_LIGHTCOLOR +#from .FSNETCMD_GENERATEATTACKER import FSNETCMD_GENERATEATTACKER + + +__all__ = ["FSNETCMD_LOGON", "FSNETCMD_LOGOFF", "FSNETCMD_ERROR", + "FSNETCMD_LOADFIELD", "FSNETCMD_ADDOBJECT", + "FSNETCMD_READBACK", "FSNETCMD_SMOKECOLOR", + "FSNETCMD_JOINREQUEST", "FSNETCMD_JOINAPPROVAL", + "FSNETCMD_REJECTJOINREQ", "FSNETCMD_AIRPLANESTATE", + "FSNETCMD_UNJOIN", "FSNETCMD_REMOVEAIRPLANE", + "FSNETCMD_REQUESTTESTAIRPLANE", "FSNETCMD_KILLSERVER", + "FSNETCMD_PREPARESIMULATION", "FSNETCMD_TESTPACKET", + "FSNETCMD_LOCKON", "FSNETCMD_REMOVEGROUND", + "FSNETCMD_MISSILELAUNCH", "FSNETCMD_GETDAMAGE", + "FSNETCMD_WEAPONCONFIG", "FSNETCMD_AIRCMD", + "FSNETCMD_TEXTMESSAGE", "FSNETCMD_ENVIRONMENT"] diff --git a/lib/PacketManager/packets/constants.py b/lib/PacketManager/packets/constants.py new file mode 100644 index 0000000..7a32e22 --- /dev/null +++ b/lib/PacketManager/packets/constants.py @@ -0,0 +1,472 @@ + + +MESSAGE_TYPES = [ + "FSNETCMD_NULL", # 0 + "FSNETCMD_LOGON", # 1 Cli ->Svr", (Svr->Cli for log-on complete acknowledgement.) + "FSNETCMD_LOGOFF", # 2 + "FSNETCMD_ERROR", # 3 + "FSNETCMD_LOADFIELD", # 4 Svr ->Cli", Cli->Svr for read back + "FSNETCMD_ADDOBJECT", # 5 Svr ->Cli + "FSNETCMD_READBACK", # 6 Svr<->Cli + "FSNETCMD_SMOKECOLOR", # 7 Svr<->Cli + "FSNETCMD_JOINREQUEST", # 8 Svr<- Cli + "FSNETCMD_JOINAPPROVAL", # 9 Svr ->Cli + "FSNETCMD_REJECTJOINREQ", # 10 + "FSNETCMD_AIRPLANESTATE", # 11 Svr<->Cli # Be careful in FsDeleteOldStatePacket when modify + "FSNETCMD_UNJOIN", # 12 Svr<- Cli + "FSNETCMD_REMOVEAIRPLANE", # 13 Svr<->Cli + "FSNETCMD_REQUESTTESTAIRPLANE", # 14 + "FSNETCMD_KILLSERVER", # 15 Svr<- Cli + "FSNETCMD_PREPARESIMULATION", # 16 Svr ->Cli + "FSNETCMD_TESTPACKET", # 17 + "FSNETCMD_LOCKON", # 18 Svr<->Cli + "FSNETCMD_REMOVEGROUND", # 19 Svr<->Cli + "FSNETCMD_MISSILELAUNCH", # 20 Svr<->Cli # fsweapon.cpp is responsible for encoding/decoding + "FSNETCMD_GROUNDSTATE", # 21 Svr<->Cli # Be careful in FsDeleteOldStatePacket when modify + "FSNETCMD_GETDAMAGE", # 22 Svr<->Cli + "FSNETCMD_GNDTURRETSTATE", # 23 Svr<->Cli + "FSNETCMD_SETTESTAUTOPILOT", # 24 Svr ->Cli + "FSNETCMD_REQTOBESIDEWINDOWOFSVR", # 25 Svr<- Cli + "FSNETCMD_ASSIGNSIDEWINDOW", # 26 Svr ->Cli + "FSNETCMD_RESENDAIRREQUEST", # 27 Svr<- Cli + "FSNETCMD_RESENDGNDREQUEST", # 28 Svr<- Cli + "FSNETCMD_VERSIONNOTIFY", # 29 Svr ->Cli + "FSNETCMD_AIRCMD", # 30 Svr<->Cli # After 2001/06/24 + "FSNETCMD_USEMISSILE", # 31 Svr ->Cli # After 2001/06/24 + "FSNETCMD_TEXTMESSAGE", # 32 Svr<->Cli + "FSNETCMD_ENVIRONMENT", # 33 Svr<->Cli (*1) + "FSNETCMD_NEEDRESENDJOINAPPROVAL", # 34 Svr<- Cli + "FSNETCMD_REVIVEGROUND", # 35 Svr ->Cli # After 2004 + "FSNETCMD_WEAPONCONFIG", # 36 Svr<->Cli # After 20040618 + "FSNETCMD_LISTUSER", # 37 Svr<->Cli # After 20040726 + "FSNETCMD_QUERYAIRSTATE", # 38 Cli ->Svr # After 20050207 + "FSNETCMD_USEUNGUIDEDWEAPON", # 39 Svr ->Cli # After 20050323 + "FSNETCMD_AIRTURRETSTATE", # 40 Svr<->Cli # After 20050701 + "FSNETCMD_CTRLSHOWUSERNAME", # 41 Svr ->Cli # After 20050914 + "FSNETCMD_CONFIRMEXISTENCE", # 42 Not Used + "FSNETCMD_CONFIGSTRING", # 43 Svr ->Cli # After 20060514 Cli->Svr for read back + "FSNETCMD_LIST", # 44 Svr ->Cli # After 20060514 Cli->Svr for read back + "FSNETCMD_GNDCMD", # 45 Svr<->Cli + "FSNETCMD_REPORTSCORE", # 46 Svr -> Cli # After 20100630 (Older version will ignore) + "FSNETCMD_SERVER_FORCE_JOIN", # 47 Svr -> Cli + "FSNETCMD_FOGCOLOR", # 48 Svr -> Cli + "FSNETCMD_SKYCOLOR", # 49 Svr -> Cli + "FSNETCMD_GNDCOLOR", # 50 Svr -> Cli + "FSNETCMD_RESERVED_FOR_LIGHTCOLOR",# 51 Svr -> Cli + "FSNETCMD_GENERATEATTACKER", # 52 + "FSNETCMD_RESERVED22", # 53 + "FSNETCMD_RESERVED23", # 54 + "FSNETCMD_RESERVED24", # 55 + "FSNETCMD_RESERVED25", # 56 + "FSNETCMD_RESERVED26", # 57 + "FSNETCMD_RESERVED27", # 58 + "FSNETCMD_RESERVED28", # 59 + "FSNETCMD_RESERVED29", # 60 + "FSNETCMD_RESERVED30", # 61 + "FSNETCMD_RESERVED31", # 62 + "FSNETCMD_RESERVED32", # 63 + "FSNETCMD_OPENYSF_RESERVED33", # 64 Reserved for OpenYSF + "FSNETCMD_OPENYSF_RESERVED34", # 65 Reserved for OpenYSF + "FSNETCMD_OPENYSF_RESERVED35", # 66 Reserved for OpenYSF + "FSNETCMD_OPENYSF_RESERVED36", # 67 Reserved for OpenYSF + "FSNETCMD_OPENYSF_RESERVED37", # 68 Reserved for OpenYSF + "FSNETCMD_OPENYSF_RESERVED38", # 69 Reserved for OpenYSF + "FSNETCMD_OPENYSF_RESERVED39", # 70 Reserved for OpenYSF + "FSNETCMD_OPENYSF_RESERVED40", # 71 Reserved for OpenYSF + "FSNETCMD_OPENYSF_RESERVED41", # 72 Reserved for OpenYSF + "FSNETCMD_OPENYSF_RESERVED42", # 73 Reserved for OpenYSF + "FSNETCMD_RESERVED43", # 74 + "FSNETCMD_RESERVED44", # 75 + "FSNETCMD_RESERVED45", # 76 + "FSNETCMD_RESERVED46", # 77 + "FSNETCMD_RESERVED47", # 78 + "FSNETCMD_RESERVED48", # 79 + "FSNETCMD_RESERVED49", # 80 + "FSNETCMD_NOP" +] + +READBACKS = ["FSNETREADBACK_ADDAIRPLANE", + "FSNETREADBACK_ADDGROUND", + "FSNETREADBACK_REMOVEAIRPLANE", + "FSNETREADBACK_REMOVEGROUND", + "FSNETREADBACK_ENVIRONMENT", + "FSNETREADBACK_JOINREQUEST", + "FSNETREADBACK_JOINAPPROVAL", + "FSNETREADBACK_PREPARE", + "FSNETREADBACK____UNUSED____", + "FSNETREADBACK_USEMISSILE", + "FSNETREADBACK_USEUNGUIDEDWEAPON", + "FSNETREADBACK_CTRLSHOWUSERNAME"] + +FSWEAPON_DICT = { + 0: "FSWEAPON_GUN", + 1: "FSWEAPON_AIM9", + 2: "FSWEAPON_AGM65", + 3: "FSWEAPON_BOMB", + 4: "FSWEAPON_ROCKET", + 5: "FSWEAPON_FLARE", + 6: "FSWEAPON_AIM120", + 7: "FSWEAPON_BOMB250", + 8: "FSWEAPON_SMOKE", + 9: "FSWEAPON_BOMB500HD", + 10: "FSWEAPON_AIM9X", + 11: "FSWEAPON_FLAREPOD", + 12: "FSWEAPON_FUELTANK", + 13: "FSWEAPON_RESERVED13", + 14: "FSWEAPON_RESERVED14", + 15: "FSWEAPON_RESERVED15", + 16: "FSWEAPON_RESERVED16", + 17: "FSWEAPON_RESERVED17", + 18: "FSWEAPON_RESERVED18", + 19: "FSWEAPON_RESERVED19", + 20: "FSWEAPON_RESERVED20", + 21: "FSWEAPON_RESERVED21", + 22: "FSWEAPON_RESERVED22", + 23: "FSWEAPON_RESERVED23", + 24: "FSWEAPON_RESERVED24", + 25: "FSWEAPON_RESERVED25", + 26: "FSWEAPON_RESERVED26", + 27: "FSWEAPON_RESERVED27", + 28: "FSWEAPON_RESERVED28", + 29: "FSWEAPON_RESERVED29", + 30: "FSWEAPON_RESERVED30", + 31: "FSWEAPON_RESERVED31", + 32: "FSWEAPON_SMOKE0", + 33: "FSWEAPON_SMOKE1", + 34: "FSWEAPON_SMOKE2", + 35: "FSWEAPON_SMOKE3", + 36: "FSWEAPON_SMOKE4", + 37: "FSWEAPON_SMOKE5", + 38: "FSWEAPON_SMOKE6", + 39: "FSWEAPON_SMOKE7", + 40: "FSWEAPON_RESERVED40", + 41: "FSWEAPON_RESERVED41", + 42: "FSWEAPON_RESERVED42", + 43: "FSWEAPON_RESERVED43", + 44: "FSWEAPON_RESERVED44", + 45: "FSWEAPON_RESERVED45", + 46: "FSWEAPON_RESERVED46", + 47: "FSWEAPON_RESERVED47", + 48: "FSWEAPON_NUMWEAPONTYPE", + 127: "FSWEAPON_NULL", + 128: "FSWEAPON_DEBRIS", + 200: "FSWEAPON_FLARE_INTERNAL" +} + +GUIDEDWEAPONS = missiles = ["FSWEAPON_AGM65", "FSWEAPON_AIM9", "FSWEAPON_AIM120", + "FSWEAPON_AIM9X", "FSWEAPON_ROCKET"] + +ERROR_CODES = ["FSNETERR_NOERR", + "FSNETERR_VERSIONCONFLICT", + "FSNETERR_CANNOTADDOBJECT", + "FSNETERR_REJECT", + "FSNETERR_CANNOTSUSTAIN"] + +AIRCMD_KEYWORDS = [ + "AFTBURNR", #TRUE/FALSE HAS AFTERBURNER + "THRAFTBN", ###[N][KG][LB] AFTERBURNER POWER + "THRMILIT", ###[N][KG][LB] MILITARY POWER + "WEIGHCLN", ###[KG][LB] CLEAN WEIGHT + "WEIGFUEL", ###[KG][LB] MAX WEIGHT OF FUEL + "WEIGLOAD", ###[KG][LB] MAX WEIGHT OF PAYLOAD + "FUELABRN", ###[KG][LB] FUEL CONSUMPTION/SEC WHEN BURNER ON + "FUELMILI", ###[KG][LB] FUEL CONSUMPTION/SEC WHEN MIL POWER + + "LEFTGEAR", #X Y Z [M][IN] LEFT MAIN GEAR POSITION + "RIGHGEAR", #X Y Z [M][IN] RIGHT MAIN GEAR POSITION + "WHELGEAR", #X Y Z [M][IN] WHEEL POSITION + + "CRITAOAP", ###[RAD][DEG] CRITICAL AOA (PLUS) + "CRITAOAM", ###[RAD][DEG] CRITICAL AOA (MINUS + + "CRITSPED", ###[KT][KM/H][M/S][MACH]CRITICAL AIRSPEED + "MAXSPEED", ###[KT][KM/H][M/S][MACH]MAXIMUM AIRSPEED + + "HASSPOIL", #TRUE/FALSE HAS SPOILER + "RETRGEAR", #TRUE/FALSE LANDING GEAR IS RETRACTABLE + "VARGEOMW", #TRUE/FALSE HAS VARIABLE GEOMETRY WING + + "CLVARGEO", ###(DIMENSIONLESS) INCREASE OF CL WHEN VGW IS EXTENDED + "CDVARGEO", ###(DIMENSIONLESS) INCREASE OF CD WHEN VGW IS EXTENDED + "CLBYFLAP", ###(DIMENSIONLESS) INCREASE OF CL WHEN FLAP FULL DOWN + "CDBYFLAP", ###(DIMENSIONLESS) INCREASE OF CD WHEN FLAP FULL DOWN + "CDBYGEAR", ###(DIMENSIONLESS) INCREASE OF CD WHEN GEAR DOWN + "CDSPOILR", ###(DIMENSIONLESS) INCREASE OF CD WHEN SPOILER IS DEPLOYED + + "WINGAREA", ###[M^2][IN^2] AREA OF WING + + "MXIPTAOA", ###[RAD][DEG] MAX INPUT AOA + "MXIPTSSA", ###[RAD][DEG] MAX INPUT YAW + "MXIPTROL", ###[RAD][DEG] MAX INPUT ROLL RATIO + + "CPITMANE", ###(DIMENSIONLESS) PITCH MANEUVABILITY CONSTANT + "CPITSTAB", ###(DIMENSIONLESS) PITCH STABILITY CONSTANT + "CYAWMANE", ###(DIMENSIONLESS) YAW MANEUVABILITY CONSTANT + "CYAWSTAB", ###(DIMENSIONLESS) YAW STABILITY CONSTANT + "CROLLMAN", ###(DIMENSIONLESS) ROLL MANEUVABILITY CONSTANT + + + "CTLLDGEA", #TRUE/FALSE INITIAL GEAR + "CTLBRAKE", #TRUE/FALSE INITIAL BRAKE + "CTLSPOIL", #0.0-1.0 INITIAL SPOILER + "CTLABRNR", #TRUE/FALSE INITIAL AFTERBURNER + "CTLTHROT", #0.0-1.0 INITIAL THROTTLE + "CTLIFLAP", #0.0-1.0 INITIAL FLAP + "CTLINVGW", #0.0-1.0 INITIAL VGW + "CTLATVGW", #TRUE/FALSE INITIAL AUTO VGW + + "POSITION", #X Y Z [M][IN] + "ATTITUDE", #H P B [DEG][RAD] + "INITFUEL", ###[KG][LB] + "INITLOAD", ###[KG][LB] + "INITSPED", ###[M/S][KT][MACH] + + + + "REFVCRUS", ###[M/S][KM/H][KT] CRUISING SPEED + "REFACRUS", ###[M][FT] CRUISING ALTITUDE + "REFVLAND", ###[M/S][KM/H][KT] LANDING SPEED + "REFAOALD", ###[DEG][RAD] AOA WHILE APPROACHING + "REFLNRWY", ###[M][FT][KM] RUNWAY LENGTH REQUIRED TO LAND + + "REM", + + "COCKPITP", + "REFTHRLD", + "REFTCRUS", + + "AUTOCALC", + + "IDENTIFY", + + "MANESPD1", + "MANESPD2", + + "MACHNGUN", + "SMOKEGEN", + "HTRADIUS", + "TRIGGER1", + "TRIGGER2", + "TRIGGER3", + "TRIGGER4", + + "STRENGTH", + + "PROPELLR", + + "VAPORPO0", + "VAPORPO1", + + "INITIGUN", + "INITIAAM", + "INITIAGM", + + "MANESPD3", + + "RADARCRS", + + "MACHNGN2", + + "SMOKEOIL", + "WEAPONCH", + "INITBOMB", + + "MONTRILS", + + "GUNPOWER", + + "CATEGORY", # Normal,Utility or Aerobatic (+fighter, attacker) + + "VGWSPED1", # Auto Vgw Reference Speed (Slower Speed) + "VGWSPED2", # Auto Vgw Reference Speed (Faster Speed) + + "GUNDIREC", # GUN direction + + # 2001/05/06 >> + "INITRCKT", # Initial number of rockets + "MAXNMGUN", # chMaxNumGunBullet + "MAXNMAAM", # chMaxNumAAM Deprecated 2010/08/04 + "MAXNMAGM", # chMaxNumAGM Deprecated 2010/08/04 + "MAXNMRKT", # chMaxNumRocket Deprecated 2010/08/04 + + # 2001/06/05 >> + "AAMSLOT_", # chAAMSlot[chNumAAMSlot++] + "AGMSLOT_", # chAGMSlot[chNumAGMSlot++] + "RKTSLOT_", # chRocketSlot[chNumRocketSlot++] + "BOMBSLOT", # chBombSlot[chNumBombSlot++] + "AAMVISIB", # chAAMVisible; + "AGMVISIB", # chAGMVisible; + "BOMVISIB", # chBombVisible; + "RKTVISIB", # chRocketVisible + "MAXNBOMB", # chMaxNumBomb Deprecated 2010/08/04 + + # 2002/12/11 >> + "ARRESTER", # chArrestingHook + + # 2003/02/02 >> + "TRSTVCTR", # chHasThrustVector + "TRSTDIR0", # chThrVec0 + "TRSTDIR1", # chThrVec1 + "PSTMPTCH", # Post-Stall VPitch + "PSTMYAW_", # Post-Stall VYaw + "PSTMROLL", # Post-Stall VRoll + + # 2003/02/12 + "AIRCLASS", # Aircraft class + + # 2003#02/15 + "PROPEFCY", # Propeller efficiency + "PROPVMIN", # Minimum speed that T=P/v becomes valid + + # 2003/09/19 + "VRGMNOSE", # Variable Geometry Nose : Concorde only + + + # 2003/11/25 + "THRSTREV", # Effectiveness of the Thrust Reverser + + + # 2004/05/22 + "GUNSIGHT", # Lead Gun Sight + + + # 2004/06/14 + "HRDPOINT", # Defining a hardpoint + "LOADWEPN", # Load weapons + "LMTBYHDP", # Limit weapons by hardpoint definition. + "UNLOADWP", # Unload All Weapons (Missiles, Bombs, Rockets. Excluding Guns, Smokes, and Flare) + + # 2005/01/03 + "INSTPANL", # Draw an instrument panel instead of a hud. (av[1] for inst panel definition file.) + + # 2005/01/05 + "MACHNGN3", + "MACHNGN4", + "MACHNGN5", + "MACHNGN6", + "MACHNGN7", + "MACHNGN8", + + # 2005/01/11 + "BOMINBAY", + "BMBAYRCS", + + # 2005/01/23 + "INITAAMM", # Mid-Range AAM + "MAXNAAMM", # Max # Mid-Range AAM + "INITB250", # 250lb Bomb + "MAXNB250", # Max # 250lb Bomb + + # 2005/03/08 + "GUNINTVL", # Gun Interval + + # 2005/06/26 + "NMTURRET", # Number of turret + "TURRETPO", # 0 0m -0.8m 2.7m 0deg 0deg 0deg # Number x y z h p b + "TURRETPT", # 0 -40deg 0deg 0deg # Number MinPitch MaxPitch NeutralPitch + "TURRETHD", # 0 -120deg 120deg 0deg # Number MinHdg MaxHdg NeutralHdg + "TURRETAM", # 0 0 # Ammo(zero -> staGunBullet will be used) + "TURRETIV", # 0 0.5sec # Number ShootingInterval + "TURRETNM", # 0 GUN # DNM Node Name + "TURRETAR", # 0 FALSE # TRUE -> Anti Air Capable + "TURRETGD", # 0 TRUE # TRUE -> Anti Ground Capable + "TURRETCT", # "PILOT" or "GUNNER" + "TURRETRG", # Range + # 2005/09/28 + "TURRETNH", # DNM Node Name (Heading Rotation) + "TURRETNP", # DNM Node Name (Pitch Rotation) + + # 2006/04/25 + "SETCNTRL", # Set Control eg. ILS TRIM:0.3 etc. + + # 2006/07/19 + "EXCAMERA", # Extra Camera + + # 2006/08/05 + "NMACHNGN", # Number of machine guns. + + # 2007/04/06 + "SMOKECOL", # Smoke Color #dmy# R G B + + # 2007/09/16 + "SUBSTNAM", # Substitute airplane (In case the airplane was not installed) + + # 2010/06/26 + "ISPNLPOS", # Instrument Panel Position + "ISPNLSCL", # Instrument Panel Scaling + + # 2010/06/29 + "ISPNLHUD", # Use both inst panel and HUD + "COCKPITA", # Neutral Head Direction + + # 2010/06/30 + "SCRNCNTR", # Screen center (Relative. (-1.0,-1.0)-(1.0,1.0) + "ISPNLATT", # Instrument Panel Orientation + "MAXNMFLR", # Maximum number of flare + + # 2010/07/01 + "FLAPPOSI", # Flap position + "FLAREPOS", # Flare Dispenser Position and Direction + + # 2010/12/11 + "INITAAAM", # Initialize AIM9X + "INITHDBM", # Initialize High-Drag bomb + "ULOADAAM", # Unload all AAMs + "ULOADAGM", # Unload all AGMs + "ULOADBOM", # Unload all Bombs + "ULOADFLR", # Unload all Flare + "ULOADGUN", # Unload all Gun + "ULOADRKT", # Unload all Rocket + + # 2011/12/25 + "LOOKOFST", # Look-at Offset + + # 2012/02/02 + "WPNSHAPE", # Weapon-shape override + + # 2012/02/21 + "GEARHORN", # Landing-gear warning horn + "STALHORN", # Stall-warning horn + + # 2013/04/14 + "CKPITIST", # To Make inst panel available in only one of EXCAMERAs, it can be hidden in the default cockpit view. + "CKPITHUD", # To Make HUD available in only one of EXCAMERAs, it can be hidden in the default cockpit view. + + # 2013/04/25 + "MALFUNCT", # Malfunction + "REPAIRAL", # Repair all + + # 2013/04/25 + "REPAIRFN", # Repair functionality + + # 2013/06/02 + "NOLDGFLR", # No landing flare + + # 2014/06/05 + "NREALPRP", # Number of (real) propeller engines + "REALPROP", # Support for realistic propeller engine + + # 2014/06/13 + "TIREFRIC", # Tire friction coefficient + + # 2014/06/24 + "PSTMSPD1", # Maximum speed that the direct attitude control is fully effective. + "PSTMSPD2", # Speed at which the direct attitude control becomes ineffective. + "PSTMPWR1", # Minimum required power setting for direct attitude control + "PSTMPWR2", # Power setting at which the direct attitude control is fully effective + + # 2014/07/11 + "MAXCDAOA", + "FLATCLR1", + "FLATCLR2", + "CLDECAY1", + "CLDECAY2", + + # 2014/10/17 + "AIRSTATE", # I'm shocked that I didn't have it yet. + + # 2018/10/07 + "INITZOOM", # Initial zoom factor + + None +] |
