Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ida/data-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ try {
errors.push(`Invalid value for classes.${key}.vtbls.${i}.base: ${vtbl.base}`);
else if (!vtbl.hasOwnProperty('base') && i !== 0)
errors.push(`Missing value for classes.${key}.vtbls.${i}.base`);
if (vtbl.hasOwnProperty('size') && !isNumeric(vtbl.size))
errors.push(`Invalid value for classes.${key}.vtbls.${i}.size: ${vtbl.size}`);
});
if (classI.hasOwnProperty('vfuncs') && classI["vfuncs"])
Object.keys(classI.vfuncs).forEach(subkey => {
Expand Down
10 changes: 10 additions & 0 deletions ida/data.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,10 @@ classes:
0x140E366A0: GetPlotIcon # (this, plotIndex) # inlined @ 140D1ECF0
0x140E33FA0: IsEstateShared # (this, plotIndex)
0x140E33E80: IsEstateResident # (this, plotIndex)
Client::Game::IndoorTerritory::OutdoorTerritoryUIEventListener:
vtbls:
- ea: 0x1421CEC88
base: Component::GUI::AtkModuleInterface::AtkEventInterface # technically Client::Game::HousingUIEventListener<Client::Game::OutdoorTerritory>
Client::Game::IndoorTerritory::IndoorTerritoryUIEventListener:
vtbls:
- ea: 0x1421CECA0
Expand Down Expand Up @@ -5408,13 +5412,15 @@ classes:
vtbls:
- ea: 0x1421344A0
base: Client::UI::RaptureAtkModule::ItemCache
size: 4 # script detects this as 1 due to xref to vfunc 1
Client::UI::RaptureAtkModule::CrystalCache:
vtbls:
- ea: 0x1421344C0
base: Client::UI::RaptureAtkModule::ItemCache
Component::GUI::AtkModuleInterface::AtkHistoryInterface:
vtbls:
- ea: 0x1421340B0
size: 6 # script detects this as 8 due to following vtbl with no xref
vfuncs:
0: dtor
1: Previous
Expand Down Expand Up @@ -17819,6 +17825,7 @@ classes:
vtbls:
- ea: 0x1421DE420
base: Client::Game::Event::GatheringEventHandler
size: 291 # base class for an AtkModuleInterface::AtkEventInterface child for specific handler with no xrefs after this
funcs:
0x140E97DE0: ctor # not used due to being inlined
Client::Game::Event::SpearFishingEventHandler:
Expand Down Expand Up @@ -17947,6 +17954,7 @@ classes:
vtbls:
- ea: 0x1421DD1F0
base: Client::Game::Event::EventHandler
size: 291 # base class for an AtkModuleInterface::AtkEventInterface child for specific handler with no xrefs after this
funcs:
0x140E90680: ctor
0x140E8E000: Setup
Expand Down Expand Up @@ -18262,6 +18270,7 @@ classes:
vtbls:
- ea: 0x142394E90
base: Client::Game::Event::LuaEventHandler
size: 278 # base class for an AtkModuleInterface::AtkEventInterface child for specific handler with no xrefs after this
funcs:
0x1419F4910: GetChocoboTaxiStandId
0x1419F49B0: GetFare
Expand Down Expand Up @@ -18532,6 +18541,7 @@ classes:
vtbls:
- ea: 0x142419130
base: Client::Game::Event::CustomTalkResidentEventHandler
size: 286 # base class for an AtkModuleInterface::AtkEventInterface child for specific handler with no xrefs after this
Client::Game::Event::JournalCallback:
vtbls:
- ea: 0x1421CC3C8
Expand Down
5 changes: 3 additions & 2 deletions ida/data_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ def __init__(self, ea, pointer=False, name=None):
self.name = name

class DefinedDataClassVtable:
def __init__(self, ea, base=None):
# type: (int, None | str) -> None
def __init__(self, ea, base=None, size=None):
# type: (int, None | str, None | int) -> None
self.ea = ea
self.base = base
self.size = size

class DefinedDataClassFunction:
def __init__(self, num, name):
Expand Down
18 changes: 13 additions & 5 deletions ida/ffxiv_idarename.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ def load_data():
class_data = {}

vtbls_raw = class_data.pop("vtbls", [])
vtbls = [(vtbl["ea"], vtbl["base"] if "base" in vtbl else None) for vtbl in vtbls_raw]
vtbls = [(vtbl["ea"], vtbl["base"] if "base" in vtbl else None, vtbl["size"] if "size" in vtbl else None) for vtbl in vtbls_raw]
vfuncs = class_data.pop("vfuncs", {})
funcs = class_data.pop("funcs", {})
instances_raw = class_data.pop("instances", [])
Expand Down Expand Up @@ -599,15 +599,15 @@ def register(self, class_name, vtbls=None, vfuncs=None, funcs=None, instances=No
if not funcs:
funcs = {}

for (vtbl_ea, _) in vtbls:
for (vtbl_ea, _, _) in vtbls:
if vtbl_ea != 0x0 and vtbl_ea in self._vtbl_addresses:
print("Error: Multiple vtables are defined at 0x{0:X}".format(vtbl_ea))
return

if class_name in self._classes:
print("Error: Multiple classes are registered with the name \"{0}\"".format(class_name))
return
for (vtbl_ea, _) in vtbls:
for (vtbl_ea, _, _) in vtbls:
self._vtbl_addresses.append(vtbl_ea)

if not instances:
Expand Down Expand Up @@ -680,16 +680,19 @@ def _finalize_class(self, cls):
class Vtbl:
resolved_base = None # type: FfxivClass

def __init__(self, ea, base_name=None):
def __init__(self, ea, base_name=None, size=None):
"""
Object representing a class's vtbl
:param ea: Address of vtbl
:type ea: int
:param base_name: Name of the base class this vtbl inherits, if it exists
:type base_name: str
:param size: Explicit size of vtbl used to override cases where size detection fails
:type size: int
"""
self.ea = ea
self.base_name = base_name
self.size = size


class FfxivClass:
Expand All @@ -713,7 +716,7 @@ def __init__(self, class_name, vtbls, vfuncs, funcs, instances):
"""
self.name = class_name
if vtbls:
self.vtbls = [Vtbl(ea, base_name) for (ea, base_name) in vtbls]
self.vtbls = [Vtbl(ea, base_name, size) for (ea, base_name, size) in vtbls]
self.vfuncs = vfuncs
self.funcs = funcs
self.instances = instances
Expand All @@ -737,12 +740,17 @@ def main_vtbl_size(self):
"""
Iterate from the vtbl start until a non-offset or xref is encountered.
This strategy implies that the only xref in a vtbl is the first vfunc.
Can be overriden by explicit size in the vtbl definition.
:return: VTable func count
:rtype: int
"""
if not self.vtbls:
return self._main_vtbl_size

if self.vtbls[0].size:
self._main_vtbl_size = self.vtbls[0].size
return self._main_vtbl_size

if self._main_vtbl_size == 0:
self._main_vtbl_size = 1 # Set to 1, skip the first entry
for ea in itertools.count(self.vtbls[0].ea + 8, 8):
Expand Down
Loading