class WayMarkStruct( OffsetStruct({ 'x': (c_float, 0x0), 'z': (c_float, 0x4), 'y': (c_float, 0x8), '_x': (c_int, 0x10), '_z': (c_int, 0x14), '_y': (c_int, 0x18), 'is_active': (c_bool, 0x1c), })): def set(self, x: float = None, y: float = None, z: float = None, is_active: bool = None): if x is not None: self.x = x self._x = int(x * 1000) if y is not None: self.y = y self._y = int(y * 1000) if z is not None: self.z = z self._z = int(z * 1000) if is_active is not None: self.is_active = is_active def get_dict(self): return { 'x': self.x, 'y': self.y, 'z': self.z, 'is_active': self.is_active }
class ServerItemInfo(OffsetStruct({ 'index': c_uint, 'unk0': c_uint, 'container_id': c_ushort, 'slot': c_ushort, 'count': c_uint, 'item_id': c_uint, 'reserved_flag': c_uint, 'signature_id': c_ulonglong, 'quality': c_ubyte, 'attribute2': c_ubyte, 'condition': c_ushort, 'spiritbond': c_ushort, 'stain': c_ushort, 'glamour_catalog_id': c_ushort, 'unk6': c_ushort, 'materia1': c_ushort, 'materia2': c_ushort, 'materia3': c_ushort, 'materia4': c_ushort, 'materia5': c_ushort, 'materia1_tier': c_ubyte, 'materia2_tier': c_ubyte, 'materia3_tier': c_ubyte, 'materia4_tier': c_ubyte, 'materia5_tier': c_ubyte, 'unk10': c_ubyte, 'unk11': c_uint, }, 0x40)): pass
class PartyList( OffsetStruct({ "members": (PartyMember * 28, 0), 'flag': (c_ubyte, 15700), 'main_size': (c_ubyte, 15708), })): def main_party(self): for i in range(self.main_size): if self.members[i].id != 0xe0000000: yield self.members[i] def party_2(self): for i in range(8, 16): if self.members[i].id != 0xe0000000: yield self.members[i] def party_3(self): for i in range(16, 24): if self.members[i].id != 0xe0000000: yield self.members[i] def alliance(self): for i in self.main_party(): yield i for i in self.party_2(): yield i for i in self.party_3(): yield i
class CoolDownGroup( OffsetStruct({ 'duration': (c_float, 8), 'total': (c_float, 12), }, 0x14)): @property def remain(self): return self.total - self.duration
class ServerContainerInfo( OffsetStruct( { 'container_sequence': c_uint, 'item_count': c_uint, 'container_id': c_uint, 'unk': c_uint, }, 16)): pass
def _do_text_command(command: str) -> int: encoded_command = command.encode('utf-8') cmd_size = len(encoded_command) cmd = OffsetStruct({"cmd": c_char * cmd_size}, full_size=cmd_size + 30)(cmd=encoded_command) arg = TextCommandStruct(cmd=addressof(cmd), t1=64, tLength=cmd_size + 1, t3=0) return _text_command_func(ui_module.value, addressof(arg), 0, 0)
class MinMax(OffsetStruct({'min': c_float, 'max': c_float})): def set_min(self, num: float): write_float(addressof(self), float(num)) def set_max(self, num: float): write_float(addressof(self) + 4, float(num)) def set(self, data: dict): self.set_min(data['min']) self.set_max(data['max'])
class BardGauge( OffsetStruct({ 'songMilliseconds': (c_ushort, 0), 'songProcs': (c_ubyte, 2), 'soulGauge': (c_ubyte, 3), 'songType': (c_ubyte, 4) })): class Song(object): none = 0 ballad = 5 # Mage's Ballad. paeon = 10 # Army's Paeon. minuet = 15 # The Wanderer's Minuet.
class InventoryPage( OffsetStruct( { 'page': POINTER(InventoryItem), 'type': c_uint, 'size': c_uint }, full_size=24)): def get_items(self): if not self.page: return for i in range(self.size): yield self.page[i]
class ServerWardLandInfo( OffsetStruct({ 'land_id': c_ushort, 'ward_id': c_ushort, 'territory_type': c_ushort, 'world_id': c_ushort, 'houses': LandHouseEntry * 60 })): def houses_without_owner(self): for house in self.houses: if not house.owner: yield house
class Actor( OffsetStruct({ 'name': (c_char * 68, 48), 'id': (c_uint, 116), 'bNpcId': (c_uint, 120), 'ownerId': (c_uint, 132), 'type': (c_byte, 140), 'subType': (c_byte, 141), 'isFriendly': (c_byte, 142), 'effectiveDistanceX': (c_byte, 144), 'playerTargetStatus': (c_byte, 145), 'effectiveDistanceY': (c_byte, 146), 'unitStatus1': (c_byte, 148), 'unitStatus2': (c_uint, 260), 'pos': (Position, 160), 'pcTargetId': (c_uint, 496), 'pcTargetId2': (c_uint, 560), 'npcTargetId': (c_uint, 6136), 'bNpcNameId': (c_uint, 6328), 'currentWorldID': (c_ushort, 6460), 'homeWorldID': (c_ushort, 6462), 'currentHP': (c_uint, 452), 'maxHP': (c_uint, 456), 'currentMP': (c_uint, 460), 'maxMP': (c_uint, 464), 'currentGP': (c_ushort, 468), 'maxGP': (c_ushort, 470), 'currentCP': (c_ushort, 472), 'maxCP': (c_ushort, 474), 'job': (c_byte, 482), 'level': (c_byte, 483), 'effects': (Effects, 6616), "IsCasting1": (c_bool, 7008), "IsCasting2": (c_bool, 7010), "CastingID": (c_uint, 7012), "CastingTargetID": (c_uint, 7024), "CastingProgress": (c_float, 7060), "CastingTime": (c_float, 7064), 'HitboxRadius': (c_float, 192), })): @property def Name(self): return self.name.decode('utf-8', errors='ignore') decoded_name = Name @property def can_select(self): a1 = self.unitStatus1 a2 = self.unitStatus2 return bool(a1 & 2 and a1 & 4 and ((a2 >> 11 & 1) <= 0 or a1 >= 128) and not a2 & 0xffffe7f7)
class ClientTrigger( OffsetStruct( { 'param1': c_uint, 'param2': c_uint, 'param3': c_uint, 'param4': c_uint, 'param5': c_uint, 'param6': c_uint, 'param7': c_uint, 'param8': c_uint, }, 32)): pass
class DragoonGauge( OffsetStruct({ 'blood_or_life_ms': (c_ushort, 0), 'stance': (c_ubyte, 2), # 0 = None, 1 = Blood, 2 = Life 'eyesAmount': (c_ubyte, 3), })): @property def bloodMilliseconds(self): return self.blood_or_life_ms if self.stance == 1 else 0 @property def lifeMilliseconds(self): return self.blood_or_life_ms if self.stance == 2 else 0
class DancerGauge( OffsetStruct({ 'feathers': (c_ubyte, 0), 'esprit': (c_ubyte, 1), 'step': (c_ubyte * 4, 2), 'currentStep': (c_ubyte, 6) })): class Step(object): none = 0 emboite = 1 # red entrechat = 2 # blue jete = 3 # green pirouette = 4 # yellow
class ServerCurrencyCrystalInfo( OffsetStruct( { 'container_sequence': c_uint, 'container_id': c_ushort, 'slot': c_ushort, 'count': c_uint, 'unk0': c_uint, 'item_id': c_uint, 'unk1': c_uint, 'unk2': c_uint, 'unk3': c_uint, }, 32)): pass
class LandHouseEntry( OffsetStruct({ 'price': c_uint, '_flag': c_uint, '_owner': c_char * 32 }, extra_properties=['owner', 'is_fc'])): @property def owner(self): return self._owner.decode('utf-8', errors='ignore') @property def is_fc(self): return bool(self._flag & (1 << 4))
class BardGauge( OffsetStruct( { 'songMilliseconds': (c_ushort, 0), 'songProcs': (c_ubyte, 2), 'soulGauge': (c_ubyte, 3), 'songType': (EnumStruct(c_ubyte, { 0: '', 5: 'ballad', 10: 'paeon', 15: 'minuet', }, default=''), 4) }, 16)): pass
class SamuraiGauge( OffsetStruct({ 'kenki': (c_ubyte, 4), 'sen_bits': (c_ubyte, 5) }, 16)): @property def snow(self): return (self.sen_bits & 1) != 0 @property def moon(self): return (self.sen_bits & 2) != 0 @property def flower(self): return (self.sen_bits & 4) != 0
class SkillQueue( OffsetStruct({ 'mark1': (c_ulong, 0), 'mark2': (c_ulong, 4), 'ability_id': (c_ulong, 8), 'target_id': (c_ulong, 16), })): @property def has_skill(self): return bool(self.mark1) def use_skill(self, skill_id, target_id=0xe0000000): self.target_id = target_id self.ability_id = skill_id self.mark1 = 1 self.mark2 = 1
class BlackMageGauge( OffsetStruct({ 'nextPolyglotMilliseconds': (c_ushort, 0), 'umbralMilliseconds': (c_ushort, 2), 'umbralStacks': (c_byte, 4), 'umbralHearts': (c_ubyte, 5), 'foulCount': (c_ubyte, 6), 'enochain_state': (c_ubyte, 7), })): @property def enochain_active(self): return byte_get_bit(self.enochain_state, 0, 1) @property def polygot_active(self): return byte_get_bit(self.enochain_state, 1, 1)
class ChatLogTable(OffsetStruct({ 'count': (c_ulong, 5 * 4), 'check_update': (c_ulonglong, 5 * 8), 'lengths': (POINTER(c_uint), 9 * 8) , 'data': (POINTER(c_ubyte), (12 * 8)) })): def get_raw(self, idx: int): if idx < 0: idx = self.count + idx if not max(-1, self.count - 1000) < idx < self.count: raise IndexError('list index %s out of range' % idx) idx %= 1000 start = self.lengths[idx - 1] if idx > 0 else 0 return bytes(self.data[start:self.lengths[idx]]) def get(self, idx: int): return ChatLog(self.get_raw(idx))
class FFXIVBundleHeader( OffsetStruct({ 'magic0': c_uint, 'magic1': c_uint, 'magic2': c_uint, 'magic3': c_uint, 'epoch': c_ulonglong, 'length': c_ushort, 'unk1': c_ushort, 'unk2': c_ushort, 'msg_count': c_ushort, 'encoding': c_ushort, 'unk3': c_ushort, 'unk4': c_ushort, 'unk5': c_ushort, })): pass
class SummonerGauge( OffsetStruct({ 'stanceMilliseconds': (c_ushort, 0), 'bahamutStance': (c_ubyte, 2), 'bahamutSummoned': (c_ubyte, 3), 'stacks': (c_ubyte, 4), })): @property def aetherflowStacks(self): return byte_get_bit(self.stacks, 0, 2) @property def dreadwyrmStacks(self): return byte_get_bit(self.stacks, 2, 2) @property def phoenixReady(self): return byte_get_bit(self.stacks, 4, 1)
class SummonerGauge( OffsetStruct({ 'stanceMilliseconds': (c_ushort, 0), 'ReturnSummon': (c_ubyte, 2), 'ReturnSummonGlam': (c_ubyte, 3), 'stacks': (c_ubyte, 4), })): @property def aetherflowStacks(self): return byte_get_bit(self.stacks, 0, 2) @property def bahamutReady(self): return self.stacks & 0b1000 > 0 @property def phoenixReady(self): return self.stacks & 0b10000 > 0
class ServerCraftStatus( OffsetStruct( { 'actor_id': (c_uint, 0), 'prev_action_id': (c_uint, 0x2c), 'round': (c_uint, 0x34), 'current_progress': (c_int, 0x38), 'add_progress': (c_int, 0x3c), 'current_quality': (c_int, 0x40), 'add_quality': (c_int, 0x44), 'current_durability': (c_int, 0x4c), 'add_durability': (c_int, 0x50), 'status_id': (c_ushort, 0x54), 'prev_action_flag': (c_ushort, 0x5c), }, 160, ['prev_action_success'])): @property def prev_action_success(self): return bool(self.prev_action_flag & 0x10)
class FFXIVBundleHeader(OffsetStruct({ 'magic0': c_uint, 'magic1': c_uint, 'magic2': c_uint, 'magic3': c_uint, '_epoch': c_ulonglong, 'length': c_ushort, 'unk1': c_ushort, 'unk2': c_ushort, 'msg_count': c_ushort, 'encoding': c_ushort, 'unk3': c_ushort, 'unk4': c_ushort, 'unk5': c_ushort, })): @property def epoch(self): return (ntohl(self._epoch & 0xFFFFFFFF) << 32) + ntohl(self._epoch >> 32)
class PartyMember( OffsetStruct( { "effects": (Effects, 0x8), "currentHP": (c_uint, 0x1b4), "maxHp": (c_uint, 0x1b8), "currentMP": (c_ushort, 0x1bc), "maxMp": (c_ushort, 0x1be), "pos": (Vector3, 0x190), "id": (c_uint, 0x1a8), "name": (c_char * 64, 0x1c4), "job": (Jobs, 0x205), "flag": (c_ubyte, 544), }, full_size=0x230)): @property def Name(self): return self.name.decode('utf-8')
class AstrologianGauge( OffsetStruct({ 'heldCard': (c_ubyte, 4), 'arcanums': (c_ubyte * 3, 5), }, 16)): class Card(object): none = 0 balance = 1 bole = 2 arrow = 3 spear = 4 ewer = 5 spire = 6 class Arcanum(object): none = 0 solar = 1 lunar = 2 celestial = 3
class SamuraiGauge( OffsetStruct( { 'prev_kaeshi_time': (c_ushort, 0), 'prev_kaeshi_lv': (c_ubyte, 2), 'kenki': (c_ubyte, 3), 'meditation': (c_ubyte, 4), 'sen_bits': (c_ubyte, 5) }, 16)): @property def snow(self): return bool(self.sen_bits & 1) @property def moon(self): return bool(self.sen_bits & 2) @property def flower(self): return bool(self.sen_bits & 4)
class DancerGauge( OffsetStruct( { 'feathers': (c_ubyte, 0), 'esprit': (c_ubyte, 1), 'step': ( EnumStruct( c_ubyte, { 0: '', 1: 'emboite', # red 2: 'entrechat', # blue 3: 'jete', # green 4: 'pirouette', # yellow }) * 4, 2), 'currentStep': (c_ubyte, 6) }, 16)): pass