FT SDK
Overview
This page documents the current reverse engineering progress for the Fantasy Tennis client-side SDK used by JFTSE tooling. The SDK maps known client structures, virtual functions, GUI objects, stage management, XML dialog loading, popup ownership and input routing into C++ wrappers that can be used from injected debugging or extension code.
The current focus is the client GUI layer around StageManager, ScreenRoot, StageBase, GameDialogStage and Adu GUI controls. Confirmed areas include the fixed 24-stage model, current-stage lookup, parent-chain/process/open-state behavior, built-in popup slot creation, XML dialog loading, command-ID binding, callback dispatch and Adu object state handling.
This page is the current reverse engineering handoff for the SDK. Names, offsets and layouts are updated only after they are verified through disassembly, runtime dumps and real client call sites.
Scope
StageManagerstate tracking, stage switching and current-stage access.- Fixed 24-stage owner list and safe current-stage attachment.
ScreenRootparent/child ownership, input routing, open state and processing state.StageBaseXML dialog ownership, child-owner lists, priority input child handling and GUI event dispatch.GameDialogStagebuilt-in popup slots, popup factory behavior, selected/active popup index and tray-popup related state.- Game-dialog lifecycle hooks, including XML initialization, activation, update, back/default action and popup close paths.
- Adu GUI object hierarchy, including active/update/visible flags, timers, child traversal and recursive processing.
- Adu dialog/control layouts, including object arrays, command IDs, control names, control types, state sets and basic runtime flags.
- XML GUI binding through
GuiBindarrays, command IDs and control type IDs. - Default GUI callback routing through
AduGuiDialogcallback/user-data fields. - Confirmed event dispatch for buttons, radio buttons, edit boxes, context menus and related GUI events.
- Confirmed edit-box text access through the wide-character text pointer at the current
AduGuiEditBoxlayout. - Group-style control activation behavior used by ranking and popup XML, especially active/visible state synchronization.
Stability Notes
Offsets and function addresses are version specific to the currently analyzed Fantasy Tennis client build. Names describe current understanding, not original source names. Any field marked unknown, maybe or conservative should be treated as subject to change until confirmed by call sites, runtime tests or additional disassembly.
Important caveat: custom GUI work should not add another stage. The client uses a fixed set of 24 stage owners. Custom UI should attach to the current stage owner, an existing popup path or the embedded modal/input owner where appropriate.
Current SDK Header
#pragma once
#include <cstdint>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <cwchar>
#include <string>
#include <type_traits>
#define FTSDK_THISCALL __thiscall
#define FTSDK_CDECL __cdecl
#define FTSDK_STDCALL __stdcall
#define FTSDK_FASTCALL __fastcall
namespace FTSDK {
namespace Structs {
struct FTStringA {
uint32_t unknown_00;
union {
char inlineBuffer[16];
char* heapPtr;
};
uint32_t length;
uint32_t capacity;
bool IsInline() const {
return capacity < 16;
}
bool IsValid() const {
if (length > capacity || length > 4096)
return false;
if (capacity > 0xFFFFFFFEu)
return false;
if (!IsInline() && !heapPtr)
return false;
return true;
}
const char* Data() const {
if (!IsValid())
return "";
return IsInline() ? inlineBuffer : heapPtr;
}
int32_t Length() const {
return IsValid() ? static_cast<int32_t>(length) : 0;
}
bool Equals(const char* text) const {
if (!text || !IsValid())
return false;
const size_t textLen = std::strlen(text);
return textLen == length && std::memcmp(Data(), text, length) == 0;
}
};
struct FTStringW {
uint32_t unknown_00;
union {
wchar_t inlineBuffer[8];
wchar_t* heapPtr;
};
uint32_t length;
uint32_t capacity;
bool IsInline() const {
return capacity < 8;
}
bool IsValid() const {
if (length > capacity || length > 4096)
return false;
if (capacity > 0x7FFFFFFEu)
return false;
if (!IsInline() && !heapPtr)
return false;
return true;
}
const wchar_t* Data() const {
if (!IsValid())
return L"";
return IsInline() ? inlineBuffer : heapPtr;
}
int32_t Length() const {
return IsValid() ? static_cast<int32_t>(length) : 0;
}
bool Equals(const wchar_t* text) const {
if (!text || !IsValid())
return false;
const size_t textLen = std::wcslen(text);
return textLen == length && std::memcmp(Data(), text, length * sizeof(wchar_t)) == 0;
}
};
template <typename T>
struct FTVector {
uint32_t unknown_00;
T* first;
T* last;
T* end;
int32_t Size() const {
if (!first || !last || last < first)
return 0;
return static_cast<int32_t>(last - first);
}
int32_t Capacity() const {
if (!first || !end || end < first)
return 0;
return static_cast<int32_t>(end - first);
}
bool IsEmpty() const {
return Size() == 0;
}
T& operator[](size_t index) {
return first[index];
}
const T& operator[](size_t index) const {
return first[index];
}
T* Begin() {
return first;
}
T* End() {
return last;
}
const T* Begin() const {
return first;
}
const T* End() const {
return last;
}
};
template <typename T>
struct FTList {
uint32_t unknown_00;
T* next;
uint32_t count;
};
struct GuiBind {
int32_t commandId;
const char* controlName;
int32_t controlTypeId;
};
struct Rect {
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
};
struct GuiRectStorage {
void* vtable;
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
};
struct StageOwnedResource {
uint8_t unknown00[0x1C];
void* object;
};
struct StageOverlayVertex {
float x;
float y;
float unknown08;
float rhwOrOne;
uint32_t color;
float unknown14;
float unknown18;
};
struct StageOverlayQuad {
StageOverlayVertex vertices[4];
int32_t unknown70;
int32_t unknown74;
int32_t widthInt;
int32_t heightInt;
float x;
float y;
float width;
float height;
float scaleX;
float alpha;
float rotationOrAngle;
uint8_t unknown9C;
uint8_t unknown9D;
uint8_t visibleOrEnabled;
uint8_t pad9F;
uint8_t unknownA0[0x0C];
};
static_assert(sizeof(Rect) == 0x10);
static_assert(sizeof(GuiRectStorage) == 0x14);
static_assert(sizeof(StageOwnedResource) == 0x20);
static_assert(sizeof(FTStringA) == 0x1C);
static_assert(sizeof(FTStringW) == 0x1C);
static_assert(sizeof(GuiBind) == 0x0C);
static_assert(sizeof(FTVector<void*>) == 0x10);
static_assert(sizeof(StageOverlayQuad) == 0xAC);
static_assert(sizeof(StageOverlayVertex) == 0x1C);
static_assert(sizeof(FTList<void*>) == 0x0C);
}
enum GuiEventType : int32_t {
ButtonClick = 0,
ButtonOver = 1,
ComboBoxOpen = 2,
ComboBoxClose = 3,
ComboBoxSelectChange = 4,
RadioButtonChange = 5,
CheckBoxChange = 6,
SliderValueChange = 7,
EditBoxEnter = 8,
EditBoxChange = 9,
EditBoxTAB = 10,
EditBoxESC = 11,
EditBoxCharLimit = 12,
EditBoxKeyUp = 13,
EditBoxKeyDown = 14,
ListBoxDBClick = 15,
ListBoxSelect = 16,
ListBoxSelectEnd = 17,
ContextMenuClick = 18,
ScrollBarPosChange = 19
};
enum GuiControlType : int32_t {
Static = 0,
Button = 1,
CheckBox = 2,
RadioButton = 3,
ComboBox = 4,
Slider = 5,
Gauge = 6,
EditBox = 7,
IMEEditBox = 8,
ListBox = 9,
ScrollBar = 10,
ContextMenu = 11
};
using GuiCallbackFn = void(FTSDK_STDCALL*)(
GuiEventType eventType,
int commandId,
int param,
void* userData
);
struct AduGuiStateSet;
namespace Constants {
// Confirmed by StageManager InitStages / SwitchStateNow bounds.
// Do not add a custom 25th stage; attach custom UI to an existing owner/modal
constexpr int32_t StageOwnerCount = 24;
// These are built-in popup owner slots at FTGameDialogOwner + 0x1E8
// Not proof that every stage uses all 10 slots
constexpr int32_t KnownBuiltinPopupSlotCount = 10;
}
class AduBase {
public:
virtual AduBase* FTSDK_THISCALL Destroy(uint32_t flags) = 0;
};
class AduGameObj : public AduBase {
public:
virtual AduGameObj* FTSDK_THISCALL Destroy(uint32_t flags) = 0;
virtual bool FTSDK_THISCALL SetField08AndMark(int32_t value) = 0;
virtual int32_t FTSDK_THISCALL ResetTimerRecursive() = 0;
virtual bool FTSDK_THISCALL SetActive(bool value) = 0;
virtual bool FTSDK_THISCALL SetUpdateBlocked(bool value) = 0;
virtual bool FTSDK_THISCALL SetVisible(bool value) = 0;
virtual bool FTSDK_THISCALL UpdateRecursive(float dt) = 0;
virtual int32_t FTSDK_THISCALL ProcessVisibleRecursive() = 0;
public:
void* VTable() const {
return *reinterpret_cast<void* const*>(this);
}
int32_t Field04() const {
return Read<int32_t>(0x04);
}
int32_t Field08() const {
return Read<int32_t>(0x08);
}
AduGameObj* FirstChild() const {
return Read<AduGameObj*>(0x0C);
}
AduGameObj* NextSibling() const {
return Read<AduGameObj*>(0x10);
}
bool IsMarked() const {
return ReadBool(0x14);
}
bool IsActive() const {
return ReadBool(0x15);
}
bool IsUpdateBlocked() const {
return ReadBool(0x16);
}
bool IsVisible() const {
return ReadBool(0x17);
}
float ElapsedOrTime() const {
return Read<float>(0x18);
}
float LastDelta() const {
return Read<float>(0x1C);
}
template <typename Callback>
void ForEachChild(Callback&& callback) {
for (AduGameObj* child = FirstChild(); child; child = child->NextSibling())
callback(child);
}
template <typename Callback>
void ForEachChild(Callback&& callback) const {
for (AduGameObj* child = FirstChild(); child; child = child->NextSibling())
callback(child);
}
protected:
template <typename T>
T Read(uintptr_t offset) const {
return *reinterpret_cast<const T*>(reinterpret_cast<uintptr_t>(this) + offset);
}
template <typename T>
void Write(uintptr_t offset, T value) {
*reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(this) + offset) = value;
}
bool ReadBool(uintptr_t offset) const {
return Read<uint8_t>(offset) != 0;
}
};
class AduGuiControl : public AduGameObj {
public:
AduGuiStateSet** StateSets() const {
return Read<AduGuiStateSet**>(0x20);
}
int32_t StateCount() const {
return Read<int32_t>(0x24);
}
int32_t StateCapacityMaybe() const {
return Read<int32_t>(0x28);
}
const Structs::FTStringA& Name() const {
return *reinterpret_cast<const Structs::FTStringA*>(
reinterpret_cast<uintptr_t>(this) + 0x2C
);
}
int32_t CommandId() const {
return Read<int32_t>(0x48);
}
uint32_t Field4C() const {
return Read<uint32_t>(0x4C);
}
int32_t ControlTypeId() const {
return Read<int32_t>(0x50);
}
bool IsControlEnabledFlag() const {
return Read<uint8_t>(0x5C) != 0;
}
bool IsHoverOrState3Flag() const {
return Read<uint8_t>(0x5D) != 0;
}
const Structs::Rect& Rect() const {
return *reinterpret_cast<const Structs::Rect*>(
reinterpret_cast<uintptr_t>(this) + 0x60
);
}
int32_t CurrentVisualState() const {
return Read<int32_t>(0x70);
}
int32_t DefaultStateIndex() const {
return Read<int32_t>(0x74);
}
bool IsDebugFlag() const {
return Read<uint8_t>(0x79) != 0;
}
bool IsOverFlag() const {
return Read<uint8_t>(0x7A) != 0;
}
bool IsPressedFlag() const {
return Read<uint8_t>(0x7B) != 0;
}
int32_t X() const {
return Read<int32_t>(0x80);
}
int32_t Y() const {
return Read<int32_t>(0x84);
}
int32_t Width() const {
return Read<int32_t>(0x88);
}
int32_t Height() const {
return Read<int32_t>(0x8C);
}
float ControlTimer() const {
return Read<float>(0x18);
}
};
class AduGuiEditBox : public AduGuiControl {
public:
const wchar_t* TextW() const {
const wchar_t* text = Read<const wchar_t*>(0x218);
return text ? text : L"";
}
std::size_t TextLength() const {
return std::wcslen(TextW());
}
uint32_t TextField21C() const {
return Read<uint32_t>(0x21C);
}
void DumpText() const {
std::printf(
"[EditBox] this=%p textPtr=%p strlen=%u field21C=%u text=\"%ls\"\n",
this,
TextW(),
static_cast<unsigned>(TextLength()),
TextField21C(),
TextW()
);
}
};
class AduGuiDialog : public AduGameObj {
public:
AduGameObj** ObjectArray() const {
return Read<AduGameObj**>(0x8C);
}
int32_t ObjectCount() const {
return Read<int32_t>(0x90);
}
AduGameObj* ObjectAt(int32_t index) const {
auto arr = ObjectArray();
if (!arr || index < 0 || index >= ObjectCount())
return nullptr;
return arr[index];
}
AduGuiControl* ControlAt(int32_t index) const {
return reinterpret_cast<AduGuiControl*>(ObjectAt(index));
}
AduGuiControl* FindControlByCommandId(int32_t commandId) const {
const int32_t count = ObjectCount();
for (int32_t i = 0; i < count; ++i) {
auto* control = ControlAt(i);
if (!control)
continue;
if (control->CommandId() == commandId)
return control;
}
return nullptr;
}
AduGuiControl* FindControlByName(const char* name) const {
if (!name)
return nullptr;
const int32_t count = ObjectCount();
for (int32_t i = 0; i < count; ++i) {
auto* control = ControlAt(i);
if (!control)
continue;
if (control->Name().Equals(name))
return control;
}
return nullptr;
}
void SetCallback(GuiCallbackFn callback, void* userData) {
Write<GuiCallbackFn>(27 * 4, callback);
Write<void*>(28 * 4, userData);
}
GuiCallbackFn Callback() const {
return Read<GuiCallbackFn>(27 * 4);
}
void* CallbackUserData() const {
return Read<void*>(28 * 4);
}
};
class StageManager;
class ScreenRoot {
public:
virtual void FTSDK_THISCALL Reserved00() = 0;
virtual void FTSDK_THISCALL Reserved04() = 0;
virtual void FTSDK_THISCALL Reserved08() = 0;
virtual void FTSDK_THISCALL Reserved0C() = 0;
virtual void FTSDK_THISCALL Reserved10() = 0;
virtual void FTSDK_THISCALL Reserved14() = 0;
virtual void FTSDK_THISCALL Reserved18() = 0;
virtual void FTSDK_THISCALL Reserved1C() = 0;
virtual void FTSDK_THISCALL Reserved20() = 0;
virtual void FTSDK_THISCALL Reserved24() = 0;
virtual void FTSDK_THISCALL Reserved28() = 0;
virtual int FTSDK_THISCALL OnFocusEnter() = 0;
virtual int FTSDK_THISCALL OnFocusLeave() = 0;
virtual void* FTSDK_THISCALL Destroy(uint32_t flags) = 0;
virtual void FTSDK_THISCALL AttachRaw(ScreenRoot* parentOrManager, int32_t rectVtableOrTemp, int32_t left, int32_t top, int32_t right, int32_t bottom, int32_t id) = 0;
virtual int FTSDK_THISCALL Shutdown() = 0;
virtual int FTSDK_THISCALL Update() = 0;
virtual int FTSDK_THISCALL OffsetRect(int32_t dx, int32_t dy) = 0;
virtual void FTSDK_THISCALL CenterRectInParent() = 0;
virtual ScreenRoot* FTSDK_THISCALL ActivateProcessing() = 0;
virtual void FTSDK_THISCALL DeactivateProcessing() = 0;
virtual void FTSDK_THISCALL OnStageCommand(int commandId) = 0;
virtual void FTSDK_THISCALL Reserved58() = 0;
virtual void FTSDK_THISCALL Reserved5C() = 0;
virtual void FTSDK_THISCALL Reserved60() = 0;
virtual void FTSDK_THISCALL Reserved64() = 0;
virtual void FTSDK_THISCALL Reserved68() = 0;
virtual void FTSDK_THISCALL Reserved6C() = 0;
virtual void FTSDK_THISCALL Reserved70() = 0;
virtual void FTSDK_THISCALL Reserved74() = 0;
virtual void FTSDK_THISCALL Reserved78() = 0;
virtual void FTSDK_THISCALL Reserved7C() = 0;
virtual void FTSDK_THISCALL Reserved80() = 0;
virtual void FTSDK_THISCALL SetOpenFlag() = 0;
virtual void FTSDK_THISCALL ClearOpenFlag() = 0;
virtual void FTSDK_STDCALL RectCleanupThunk(int32_t a1, uint8_t rectObj, int32_t a3, int32_t a4) = 0;
virtual void FTSDK_THISCALL HandleSystemEvent(int32_t eventType, void* data, int32_t param) = 0;
virtual void FTSDK_STDCALL RectCleanupThunk2(uint8_t rectObj, int32_t a2, int32_t a3) = 0;
virtual bool FTSDK_THISCALL HandleInput(uint32_t msg, int32_t wParam, int32_t lParam) = 0;
public:
int32_t id;
float field08;
float field0C;
uint8_t unknown10[0x80];
Structs::GuiRectStorage rect;
Structs::FTVector<ScreenRoot*> children;
ScreenRoot* parent;
int32_t parentChainEnabled;
int32_t processEnabled;
int32_t openFlag;
int32_t rectOffsetEnabled;
uint8_t unknownC8[0x70];
char resourceName[0x80];
void* lazyResource;
uint8_t lazyResourceAllowed;
uint8_t pad1BD[3];
};
static_assert(sizeof(ScreenRoot) == 0x1C0);
class ScreenInputRoot : public ScreenRoot {
public:
uint8_t unknown1C0[0x0C];
ScreenRoot* rootFocusOwner;
ScreenRoot* inputFocusOwner;
ScreenRoot* previousFocusOwner;
ScreenRoot* activeFocusOwner;
uint8_t unknown1DC[0x08];
int32_t cursorX;
int32_t cursorY;
uint8_t inputState[0x26C];
ScreenRoot* hoverOrCapturedOwner;
char resourceBasePath[0x104];
};
static_assert(sizeof(ScreenInputRoot) == 0x560);
class StageBase : public ScreenRoot {
public:
virtual void FTSDK_THISCALL AttachOwnerWithDefaultRect(ScreenRoot* parent, int32_t id) = 0;
virtual int FTSDK_THISCALL InitDialogWithParentOwner(StageBase* parent) = 0;
virtual bool FTSDK_THISCALL LoadXml(const char* xmlName, const Structs::GuiBind* binds, int32_t bindCount, GuiCallbackFn callback, bool reload) = 0;
virtual int FTSDK_THISCALL OnActivate() = 0;
virtual int FTSDK_THISCALL OnDeactivate() = 0;
virtual int FTSDK_THISCALL OnUpdate() = 0;
virtual bool FTSDK_THISCALL ProcessChildOwners(float dt) = 0;
virtual int FTSDK_THISCALL HandleStagePacket(void* packet) = 0;
virtual int FTSDK_THISCALL HandleGuiEvent(GuiEventType eventType, int commandId, int param) = 0;
virtual int FTSDK_THISCALL OnCommandAction(int commandId) = 0;
virtual int FTSDK_THISCALL OnEditBoxEnter(int commandId) = 0;
virtual int FTSDK_THISCALL OnEditBoxChange(int commandId) = 0;
virtual int FTSDK_THISCALL OnEditBoxTab(int commandId) = 0;
virtual int FTSDK_THISCALL OnEditBoxEsc(int commandId) = 0;
virtual int FTSDK_THISCALL OnEditBoxKeyUp(int commandId) = 0;
virtual int FTSDK_THISCALL OnEditBoxKeyDown(int commandId) = 0;
virtual int FTSDK_THISCALL OnContextMenuClick(int commandId, int selectedValue, AduGuiControl* contextMenuControl, int selectedData) = 0;
public:
StageBase* priorityInputChildOwner;
uint8_t inputConsumedFlag;
uint8_t padOrUnknown1C5[3];
AduGuiDialog* xmlDialog;
Structs::FTList<void> internalOwnerList;
Structs::FTVector<StageBase*> processingChildOwners;
public:
bool InputConsumedFlag() const {
return inputConsumedFlag != 0;
}
AduGuiDialog* XmlDialog() const {
return xmlDialog;
}
bool HasXmlDialog() const {
return xmlDialog != nullptr;
}
StageBase* PriorityInputChildOwner() const {
return priorityInputChildOwner;
}
Structs::FTVector<StageBase*>& ProcessingChildOwners() {
return processingChildOwners;
}
const Structs::FTVector<StageBase*>& ProcessingChildOwners() const {
return processingChildOwners;
}
void SetPriorityInputChildOwner(StageBase* child) {
priorityInputChildOwner = child;
}
void ClearPriorityInputChildOwnerIf(StageBase* child) {
if (PriorityInputChildOwner() == child)
SetPriorityInputChildOwner(nullptr);
}
using AddChildOwnerFn = int(FTSDK_THISCALL*)(StageBase* self, StageBase* child);
void AddChildOwner(StageBase* child) {
reinterpret_cast<AddChildOwnerFn>(0x005AA720)(this, child);
}
using BringChildOwnerToFrontFn = int(FTSDK_THISCALL*)(StageBase* self, StageBase* child);
void BringChildOwnerToFront(StageBase* child) {
reinterpret_cast<BringChildOwnerToFrontFn>(0x005AA780)(this, child);
}
using IsOwnerReachableFn = int(FTSDK_FASTCALL*)(StageBase* self);
bool IsReachableThroughParentChain() const {
return reinterpret_cast<IsOwnerReachableFn>(0x005A99E0)(const_cast<StageBase*>(this)) != 0;
}
using GetControlByCommandIdFn = AduGuiControl* (FTSDK_THISCALL*)(StageBase* self, int32_t commandId, int32_t expectedType);
AduGuiControl* GetControlByCommandId(int32_t commandId, int32_t expectedType = -1) {
return reinterpret_cast<GetControlByCommandIdFn>(0x005AE7D0)(this, commandId, expectedType);
}
using GetControlInnerObjectFn = void* (FTSDK_THISCALL*)(StageBase* self, int32_t commandId);
void* GetControlInnerObject(int32_t commandId) {
return reinterpret_cast<GetControlInnerObjectFn>(0x005AE840)(this, commandId);
}
};
class GameDialogStage : public StageBase {
public:
virtual void FTSDK_THISCALL AttachOwnerAndCreateUserNotice(ScreenRoot* parent, int32_t id) = 0;
virtual int FTSDK_THISCALL InitStageXml() = 0;
virtual int FTSDK_THISCALL SetSelectedOrActivePopupIndex(int32_t index) = 0;
virtual int FTSDK_THISCALL CanLeaveStageOrPopup(int32_t reason) = 0;
virtual void FTSDK_THISCALL ReservedF0() = 0;
virtual int FTSDK_THISCALL OnBackOrDefaultAction() = 0;
public:
StageBase* builtinPopupOwners[10];
uint8_t xmlLoadedFlag;
uint8_t pad211[3];
int32_t selectedOrActivePopupIndex;
void* trayPopupOwner;
public:
bool IsXmlLoaded() const {
return xmlLoadedFlag != 0;
}
StageBase* BuiltinPopupOwnerAt(int32_t index) const {
if (index < 0 || index >= 10)
return nullptr;
return builtinPopupOwners[index];
}
using GetOrCreateBuiltinPopupOwnerFn = StageBase * (FTSDK_THISCALL*)(StageBase* self, uint32_t popupIndex);
StageBase* GetOrCreateBuiltinPopupOwner(uint32_t popupIndex) {
if (popupIndex >= Constants::KnownBuiltinPopupSlotCount)
return nullptr;
return reinterpret_cast<GetOrCreateBuiltinPopupOwnerFn>(0x00498890)(this, popupIndex);
}
};
class StageManager : public ScreenInputRoot {
public:
void* hwnd;
int32_t previousStageId;
int32_t pendingStageId;
int32_t currentStageId;
int32_t transitionStageScratchId;
GameDialogStage* currentStage;
uint8_t embeddedDialogStageStorage[0x21C];
Structs::FTVector<GameDialogStage*> stages;
void* currentOverlayRaw;
Structs::StageOverlayQuad overlayQuad;
float overlayTimer;
Structs::StageOwnedResource ownedEffectResource;
int32_t frameUpdating;
uint8_t unknown87C[0x10];
uint8_t delayedReconnectFlag;
uint8_t pad88D[3];
float periodicTimer;
uint8_t hourlyPacketReadyFlag;
uint8_t pad895[3];
float hourlyPacketTimer;
int32_t unknown89C;
GameDialogStage* EmbeddedDialogStage() {
return reinterpret_cast<GameDialogStage*>(embeddedDialogStageStorage);
}
const GameDialogStage* EmbeddedDialogStage() const {
return reinterpret_cast<const GameDialogStage*>(embeddedDialogStageStorage);
}
GameDialogStage* CurrentStage() const {
if (currentStage)
return currentStage;
if (currentStageId < 0 || currentStageId >= stages.Size())
return nullptr;
return stages[currentStageId];
}
bool IsValidStageIndex(uint32_t index) const {
return index < Constants::StageOwnerCount;
}
using RequestStateFn = void(FTSDK_THISCALL*)(
StageManager* self,
uint32_t state
);
void RequestState(uint32_t state) {
if (!IsValidStageIndex(state))
return;
reinterpret_cast<RequestStateFn>(0x004AE9A0)(this, state);
}
using SwitchStateNowFn = void(FTSDK_THISCALL*)(
StageManager* self,
uint32_t state
);
void SwitchStateNow(uint32_t state) {
if (!IsValidStageIndex(state))
return;
reinterpret_cast<SwitchStateNowFn>(0x004AD7D0)(this, state);
}
using InitStagesFn = bool(FTSDK_THISCALL*)(
StageManager* self,
void* hwnd,
int startupParam
);
bool InitStages(void* hwnd, int startupParam) {
return reinterpret_cast<InitStagesFn>(0x004B0590)(this, hwnd, startupParam);
}
};
using GetStageManagerFn = StageManager* (FTSDK_CDECL*)();
inline StageManager* GetStageManager() {
return reinterpret_cast<GetStageManagerFn>(0x004B0520)();
}
using ConstructGuiOwnerBaseFn = StageBase* (FTSDK_THISCALL*)(StageBase* self);
inline StageBase* ConstructStageBase(StageBase* memory) {
return reinterpret_cast<ConstructGuiOwnerBaseFn>(0x005AEC40)(memory);
}
using ConstructGameDialogStageFn = GameDialogStage* (FTSDK_THISCALL*)(GameDialogStage* self);
inline GameDialogStage* ConstructGameDialogStage(GameDialogStage* memory) {
return reinterpret_cast<ConstructGameDialogStageFn>(0x004987C0)(memory);
}
}