Giter Club home page Giter Club logo

ffxivclientstructs's Introduction

FFXIVClientStructs

This library encapsulates community efforts to reverse engineer the object layout of native classes in the game Final Fantasy XIV and provide tools to assist in interop with native objects and functions in the running game. The library is written in C# as the main third party plug-in loader, Dalamud, is also written in C#.

Interacting with native game code is fundamentally unsafe and the library makes no attempt to prevent the user from shooting themselves in the foot. There is no type marshalling and all types are represented as explicit layout unmanaged structs that map 1:1 in memory with the game's objects. Since the game is written in C++, pointers are everywhere and you will likely need unsafe blocks when doing much of anything.

We make extensive use of C# Source Generators to reduce the boilerplate necessary to call native functions. Rather than marshalled delegates, all functions are represented by function pointers resolved by the library from signatures and wrapped in a null safety check. From the user standpoint, calling these functions is as simple as calling a native C# method.

Reverse Engineering Rename Database

A database and script(s) are maintained in the ida folder which can be used to import a large number of location names to IDA or Ghidra. This database is updated with every patch, although keep in mind this is volunteer work and some patches require more effort than others. There is more info in the readme in the folder itself.

Credits

This project would not be possible without significant work from many members of the FFXIV RE/Dalamud communities.

Project Maintainers

Contributors

Too many to list.

For Library Users

Signature Resolution

The library uses signatures to resolve locations at runtime. In order to populate locations from signatures to call functions, you need to initialize the library once at load. However, if you're writing a Dalamud plugin using the built-in copy of the library, you can just reference it in the project and Dalamud will have already initialized it for you.

The following code is only necessary if you are not using Dalamud or using a local copy of the library in your plugin.

FFXIVClientStructs.Interop.Resolver.GetInstance.SetupSearchSpace();
FFXIVClientStructs.Interop.Resolver.GetInstance.Resolve();

SetupSearchSpace has two optional arguments. The first allows you to pass a pointer to a copy of the FFXIV module somewhere in memory. The primary use of this is to allow the resolver to scan a fresh copy of the binary rather than one modified by active hooks from other sources. You can access Dalamud's module copy via the SigScanner service's SearchBase argument if you are trying to resolve your local copy within a Dalamud plugin. The second argument takes a path to a json file as a C# FileInfo object. This will cause the resolver to use that json file as a signature cache, speeding up resolving on future runs. The resolver is relatively fast, but using the cache is near-instant, so using it is your choice.

Library Design

Native classes are represented as fixed-offset structs. If you have a pointer or reference to one of these structs, you can access native memory the same way you'd access a field on any C# class or struct. Native function calls are wrapped in methods on these structs and can be called the same way you would call a C# method. Source generation creates wrappers that automatically pass the struct's pointer to C++ member and virtual functions making them mostly-seamless.

Many native singletons can be accessed via static instance methods, which should get you started accessing native objects.

Caveats

C# is not C++. There are some constructs that aren't possible to represent properly as well and some rough edges around the interop process.

String types

The game has a string class, Utf8String, which is roughly analogous to std::string and is used in most places where strings are stored. However, it also uses C-style strings, aka pointers to null terminated character (UTF-8-encoded) arrays. C# strings are UTF-16 and pointers to them cannot be passed directly to functions requiring these C string pointers. Also, the C# char type is 16-bit and cannot be used to represent the arguments. All functions that take C string arguments therefore have byte* as the argument type.

The library generates overloads for these methods that take string and perform the UTF-16 -> UTF-8 byte array conversion for you. Be aware this conversion is happening and consider storing your own copies of UTF-8 converted strings if you are noticing a performance hit from the string conversions. This is unlikely, but could happen.

There are also generated overloads that take ReadOnlySpan<byte> arguments. This is primarily to allow the use of UTF-8 string literals as function arguments.

No functions will ever return a C# string type in order to avoid making assumptions about the memory lifetime of pointers returned by the game.

Fixed-Size Arrays

C# does not support fixed-sized buffers of arbitrary types. While this feature is being worked on for a future version of the language (see the fixed buffer section of this), there is no ETA. All fixed-sized buffers of native types are represented as a buffer of byte instead. A future version of the library will support generation of convenience accessors for these, but that is currently not implemented. You will need to cast the type to access the array properly.

Generic Pointers

C# doesn't allow pointer types in generics. This makes it impossible to represent constructs like std::vector<T*>. The library uses a wrapper type Pointer<T> to get around this. Pointer<T> will implicitly convert to T* but you might need to do explicit conversions when working with collections of pointers.

STD collections

There are wrappers for accessing data from a handful of C++ std library collections used by the game such as vector and map. These do not support writing to those collections, and you will have to implement that yourself if you want to update them.

For Library Developers

FFXIV is built with the MSVC 64-bit compiler and any mention of the way the compiler works applies to that compiler.

Signatures

All signatures in the library must use ?? for wildcard bytes and include 2 characters per byte.

Native Game Classes

namespace FFXIVClientStructs.FFXIV.Component.GUI;
[StructLayout(LayoutKind.Explicit, Size = 0xA8)]
public unsafe partial struct AtkResNode : ICreatable { }

Native game classes are represented as explicit layout structs. If the official name of the class is available (via old rtti) use that for the name and namespace. For new classes or classes without virtual functions, make up a name that seems appropriate.

If the struct has unsafe members, mark the struct unsafe rather than the individual members. If you are using a generator, the struct must also be partial. If you are unable to get the exact size, use your best estimate.

ICreatable

If you give the struct a CTor function and the interface ICreatable it will be creatable using game allocators via convenience methods on IMemorySpace. This is only relevant for objects that you might want to create, which at this point in time is entirely UI objects.

Class Fields

    [FieldOffset(0x20)] public AtkResNode* ParentNode;
    [FieldOffset(0x28)] public AtkResNode* PrevSiblingNode;
    [FieldOffset(0x30)] public AtkResNode* NextSiblingNode;
    [FieldOffset(0x38)] public AtkResNode* ChildNode;

Because struct layouts are explicit, all fields are required to have a FieldOffset defined.

Field types can (generally) only be types that the runtime considers unmanaged. This boils down to most primitive integer/float types, enums, pointers, fixed-size primitive arrays, and structs that only contain fields meeting the definition.

Arrays

Native fixed size arrays such as

AtkResNode resNodeArray[10];

cannot be represented in C# because the runtime does not currently allow fixed sized arrays of arbitrary types in structs, only integer primitives. Until this feature arrives, define all arrays that aren't integer primitives as byte arrays of sizeof(T) * length.

public fixed byte resNodeArray[4 * 0xA8]; // AtkResNode array

There are plans to implement a source generator to make interop with these arrays better, but that hasn't been developed yet.

Native Game Functions

Native game functions are represented by methods with the correct signature and annotated with an attribute that causes generation of the appropriate wrapper to call the native function.

It is important to note that this assembly has the DisableRuntimeMarshalling attribute enabled, so only types that can be sent to native functions without marshalling are allowed (no string - use byte* and the CStr generator).

All native functions are called via C# function pointers and incur the minimum possible managed<->unmanaged penalty.

[MemberFunction]

public MemberFunctionAttribute(string signature)
[MemberFunction("E8 ?? ?? ?? ?? C1 E7 0C")]
public partial void AddEvent(ushort eventType, uint eventParam, AtkEventListener* listener,
        AtkResNode* nodeParam, bool isSystemEvent);

Used for functions that are non-virtual members of native classes. This includes static functions.

This will generate the following wrapper:

public partial void AddEvent(ushort eventType, uint eventParam, global::FFXIVClientStructs.FFXIV.Component.GUI.AtkEventListener* listener, global::FFXIVClientStructs.FFXIV.Component.GUI.AtkResNode* nodeParam, bool isSystemEvent)
{
    if (MemberFunctionPointers.AddEvent is null)
        throw new InvalidOperationException("Function pointer for AtkResNode.AddEvent is null. The resolver was either uninitialized or failed to resolve address with signature E8 ?? ?? ?? ?? C1 E7 0C ?? ?? ?? ?? ?? ?? ?? ??.");

     fixed(AtkResNode* thisPtr = &this)
    {
        MemberFunctionPointers.AddEvent(thisPtr, eventType, eventParam, listener, nodeParam, isSystemEvent);
    }
}

Note that the wrapper takes care of passing the object instance pointer (known as the this pointer) to the function for you. This allows you to call native functions on library struct types as if they were regular C# methods. Static functions do not pass an object instance and the generator will not do this if the method is marked static.

[VirtualFunction]

public VirtualFunctionAttribute(uint index)
[VirtualFunction(78)]
public partial StatusManager* GetStatusManager();

Used for functions that are virtual members of native classes.

This will generate the following wrapper:

[StructLayout(LayoutKind.Explicit)]
public unsafe struct CharacterVTable
{
    [FieldOffset(624)] public delegate* unmanaged[Stdcall] <Character*, global::FFXIVClientStructs.FFXIV.Client.Game.StatusManager*> GetStatusManager;
}

[FieldOffset(0x0)] public CharacterVTable* VTable;
  
public partial global::FFXIVClientStructs.FFXIV.Client.Game.StatusManager* GetStatusManager()
{
    fixed(Character* thisPtr = &this)
    {
        return VTable->GetStatusManager(thisPtr);
    }
}

Virtual functions are referenced via the index in the class's virtual table. These cannot be static and always include the object instance pointer. Since these calls resolve the function pointer via the instance object's virtual table they will work the same way they do in native code and call the appropriate virtual overload for the class.

[StaticAddress]

public StaticAddressAttribute(string signature, int offset, bool isPointer = false)
[StaticAddress("44 0F B6 C0 48 8B 0D ?? ?? ?? ??", 7, isPointer: true)]
public static partial Framework* Instance();

Used for returning the location of static objects in the binary. This is mostly used for returning the location of singletons that are accessed directly rather than via a function call. All of these methods should return a pointer.

This will generate the following wrapper:

public unsafe static class StaticAddressPointers
{
    public static global::FFXIVClientStructs.FFXIV.Client.System.Framework.Framework** ppInstance => (global::FFXIVClientStructs.FFXIV.Client.System.Framework.Framework**)Framework.Addresses.Instance.Value;
}

public static partial global::FFXIVClientStructs.FFXIV.Client.System.Framework.Framework* Instance()
{
    if (StaticAddressPointers.ppInstance is null)
        throw new InvalidOperationException("Pointer for Framework.Instance is null. The resolver was either uninitialized or failed to resolve address with signature 44 0F B6 C0 48 8B 0D ?? ?? ?? ?? ?? ?? ?? ?? ??.");
    return *StaticAddressPointers.ppInstance;
}

Note that in this case the static address is a pointer, so the attribute argument isPointer is true and our pointer turns into a pointer to a pointer which is handled by the wrapper. Some static locations in the client are static instances which are allocated within the binary (static GameMain GameMainInstance) and some are static pointers to instances which are allocated on the heap at runtime (static Framework* FrameworkInstance).

Static Address Signatures

Since the instructions resolved from static address signatures are variable length, an offset argument is required to tell the resolver where to read the static address location from in the signature. This offset is usually to the first (0-indexed) ?? in your signature, but could be further away in some situations.

[VTableAddress]

public VTableAddressAttribute(string signature, int offset, bool isPointer = false)
[VTableAddress("48 8d 05 ?? ?? ?? ?? 48 89 03 48 8d 83 50 02 00 00 48 89 93 20 02 00 00", 3)]
public unsafe partial struct AddonRetainerTaskAsk

Used on structs for returning the static location of struct VTables in the binary.

This will generate the following wrapper:

public static partial class Addresses
{
    public static readonly Address VTable = new StaticAddress("AddonRetainerTaskAsk.VTable", "48 8d 05 ?? ?? ?? ?? 48 89 03 48 8d 83 50 02 00 00 48 89 93 20 02 00 00 ?? ?? ?? ?? ?? ?? ?? ??", new ulong[] {0x4800000000058d48, 0x000250838d480389, 0x0000022093894800, 0x0000000000000000}, new ulong[] {0xFF00000000FFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x0000000000000000}, 0, 3);
}

public unsafe static class StaticAddressPointers
{
    public static nuint VTable => AddonRetainerTaskAsk.Addresses.VTable.Value;
}

public static AddonRetainerTaskAskVTable StaticVTable => *(AddonRetainerTaskAskVTable*)StaticAddressPointers.VTable;

Static Virtual Function Pointers

If a struct is both annotated with [VTableAddress(...)] and has functions annotated with [VirtualFunction(...)], the StaticVTable can then be used to get static addresses for those functions which can be used for staticly hooking the function call. For example:

this.onSetupHook = Hook<OnSetupDelegate>.FromAddress((nint)AddonRetainerTaskAsk.StaticVTable.OnSetup, this.OnSetupDetour);

[GenerateCStrOverloads]

public GenerateCStrOverloadsAttribute(string? ignoreArgument = null)
[MemberFunction("E8 ?? ?? ?? ?? 48 8B F8 41 B0 01")]
[GenerateCStrOverloads]
public partial AtkUnitBase* GetAddonByName(byte* name, int index = 1);

Used to generate some useful overload methods for native functions that take C string arguments. C strings are null-terminated char (8-bit) arrays. Since the assembly has marshalling disabled, you cannot use string as an argument to function pointers, so all C string arguments must be declared as byte*, as mentioned earlier. This has two problems - it makes working with the methods annoying, and hides the fact that the argument is a character array. C# char type is 16-bit to match C#'s native UTF16 strings, so it can't be used instead.

This generator will generate the following overloads:

public global::FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase* GetAddonByName(string name, int index = 1)
{
    int utf8StringLengthname = global::System.Text.Encoding.UTF8.GetByteCount(name);
    Span<byte> nameBytes = utf8StringLengthname <= 512 ? stackalloc byte[utf8StringLengthname + 1] : new byte[utf8StringLengthname + 1];
    global::System.Text.Encoding.UTF8.GetBytes(name, nameBytes);
    nameBytes[utf8StringLengthname] = 0;

    fixed (byte* namePtr = nameBytes)
    {
        return GetAddonByName(namePtr, index);
    }
}

public global::FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase* GetAddonByName(ReadOnlySpan<byte> name, int index = 1)
{
    fixed (byte* namePtr = name)
    {
        return GetAddonByName(namePtr, index);
    }
}

The string argument wrapper will take care of converting the string to bytes for you. Obviously, this adds overhead, but the runtime's marshalling would be doing the same thing anyway. The ReadOnlySpan<byte> overload mainly exists to allow passing of UTF-8 string literals.

This attribute is not meant to be used for C string returns; those will always return as byte* so as not to make assumptions about the memory lifetime of returned pointers.

ffxivclientstructs's People

Contributors

aers avatar aireil avatar asgardxiv avatar awgil avatar caraxi avatar chalkos avatar daemitus avatar exter-n avatar github-actions[bot] avatar goaaats avatar haselnussbomber avatar illion20 avatar infiziert90 avatar itsbexy avatar jeffyw avatar juntalis avatar kazwolfe avatar koenari avatar lmcintyre avatar marimelon avatar midorikami avatar nukoooo avatar ottermandias avatar pohky avatar sheepgomeh avatar soreepeong avatar tischel avatar unknownx7 avatar wolfcomp avatar workingrobot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ffxivclientstructs's Issues

Support KR FFXIV

I want to create structures for the FFXIV Korean version.
Can you explain how to create a data.yml to use in IDA?

Help with a error I can't solve

Trying to find out if I'm inside or not, get a confusing error. Can't find any documentation so any help would be appreciated.

Code:
FFXIVClientStructs.Interop.Resolver rt = FFXIVClientStructs.Interop.Resolver.GetInstance;
rt.SetupSearchSpace();
rt.Resolve();
bool isInside = FFXIVClientStructs.FFXIV.Client.Game.Housing.HousingManager.Instance()->IsInside();

Error:
Function pointer for HousingManager.Instance is null. The resolver was either uninitialized or failed to resolve address with signature E8 ?? ?? ?? ?? 8B 56 7C ?? ?? ?? ?? ?? ?? ?? ??.'

RFC: Source generators

Using AddonHudLayoutScreen for example.

How are vfuncs accessed while still retaining access to the vtbl? Currently the vtbl is in AtkUnitBase.
AddonHudLayoutScreen should get its own vtbl for its own specific functions. Since we don't necessarily have knowledge of what is overridden like in IDA, it'll likely need to inherit all of AtkUnitBase's names too.
Should vfuncs be differentiated from funcs?
Should we get into the including delegate business?

[VTable(0x1418106A0)].   // This I could like
[Func("AddonOverlayMouseMovedEvent", 0x141023730)]    // not a fan of looking these up by string
public unsafe struct AddonHudLayoutScreen { <stuff> } 
public unsafe struct AddonHudLayoutScreen 
{
    ...
    public static class VTable
    {
        public static readonly IntPtr Address = new IntPtr(0xdeadbeef);
        public static IntPtr this[int index] => Address + 8*index;  // Although you cant have static indexers.
    }
    public static class Functions 
    {
        public static readonly IntPtr AddonOverlayMouseMovedEventAddress = new IntPtr(0x141023730);
    }
    public static class Delegates
    {  // How would these be stored, as plaintext in the data.yml?
        public delegate void AddonOverlayMouseMovedEventDelegate(stuff);
    }
} 

Request for information

Not sure if this is the right place, but I'd like to know if any of you FFXIV reversing experts would be willing to help me understand it's software architecture a bit more. Particularly, I'd love to have a better understanding the role of Agents and how they work, how the FFXIV UI system works, how the UI retrieves the data it displays from the server, and how to manipulate the controls on the UI. Even a basic interaction diagram of those components would be very helpful.

If this information already exists somewhere, then a link to where I can find it could be appreciated. Otherwise, if you don't want to have the discussion here, feel free to email me at [email protected].

Thanks!

Future Work

Generators

  • Static VTables
    Make vtables available as addresses without needing an instance of the object first. Also provide vtable size via attribute argument. Would be integrated with the virtual function generator and generate a properly-sized vtable struct.
  • Inheritance
    [Inherits] attribute that generates struct members from the parent into the child so all fields and methods show as available without having to do AtkTextNode->AtkResNode for example. This generator would need info from all other generators so first combine all generators into a single generator (relatively easy) beforehand.

IDA

  • Reformat data.yml
    There are some constructs we don't really support well. Might switch off yaml to something "simpler" since we don't need yaml features.
  • CExporter
    Will likely rewrite this using Roslyn syntax analysis rather than reflection. In addition to exporting types, export method signatures.
  • Rewrite import script
    Import types and use method signatures to set function argument types appropriately. Also want to pull in some other forms of smart renaming (rename EXD getters via the root, maybe rename unknown agents and addons automatically with their IDs and uld names, more ideas here???)

Other

Anything I'm forgetting. Feel like we've talked about other stuff before.

I feel like some way to indicate which structs have been 'validated' after a patch (anything that didnt change size is probably safe, and anything that changed size and has had its offsets verified) would be nice. There's no doubt numerous "broken" (outdated) offsets and having some way of tracking that would be useful.

Versioning

With 603b211 I added versioning to Client Structs, but I failed to realize GitVersion fails to work with detached heads which makes building anything that isn't fully updated with Client Structs fails to build.

I'd like to keep versioning as I believe it will be helpful, but I'm unsure of a better way to do it.

Any ideas?

RaycastHit offsets need adjustments

Was playing around with Raycasts a bit and it looks like some offsets have been changed:

  • Distance is at 0x48 now
  • I'm pretty sure Object is at 0x50
  • I think Flags is at 0x40

Opened this issue so someone with better knowledge of the struct can take a look cause I don't really know how the Flags or the Object should look like.

Consider switching from source generator to generated-and-committed code

imo the source generator is quite hard to debug and use, especially if you'd like to view what their output looks like on GitHub.

I think it would be better to convert it to a standalone application that produces files that can be committed into the repository.

Open to arguments otherwise, though.

CExporter issue: AddonContextMenu

namespace FFXIVClientStructs.FFXIV.Client.UI;
public struct AddonContextMenu
{
    [FieldOffset(0x0)] public AtkUnitBase AtkUnitBase;
    [FieldOffset(0x160)] public unsafe AtkValue* AtkValues; // Does this belong in base?
    [FieldOffset(0x1CA)] public ushort AtkValuesCount; // // Does this belong in base?
}

CExporter: Does not detect fields exceeding struct size

For structs with explicit set struct size, there is no error for fields that esceed the struct size

PS: I vaguely recall some discussion about this, but as I did not find any written info on this I'll open an issue for either fixing this or making a note in a readme

Remaining CExporter issues

Current offset exceeded the next field's offset (0x228 > 0x1E0): Client::Graphics::Render::RenderTargetManager.OffscreenRenderTarget_1
Current offset exceeded the next field's offset (0x18E8 > 0x18C8): Client::UI::AddonWeeklyBingo.SecondChanceButton
Current offset exceeded the next field's offset (0x8 > 0x1): Client::Game::Character::Character::ForayInfo.Element
Current offset exceeded the next field's offset (0x4280 > 0x3E90): Client::UI::Agent::AgentMap.MiniMapMarkerArray
Current offset exceeded the next field's offset (0x8F8 > 0x8F1): Client::Graphics::Scene::Human.Sex
Current offset exceeded the next field's offset (0x1A0 > 0x198): Client::Game::UI::Buddy.Pet
Unhandled type: FFXIVClientStructs.FFXIV.Client.System.Memory.ICreatable

I think the ForayInfo is an issue in how the program calculates offsets.
WeeklyBingo has buttons in the wrong struct i think? but the offsets need to be recalculated.
I'm not sure whats going on with BuddyPet.

Thinking in classes instead of vtbls?

What would a class-based approach look like?

Do we need to need to specify the size of a vtable at all? When I was calculating things, the only xref in a vtable is vf0. The next xref is generally the start of a new vtable. Is this the rule or just common? Do vtables continue past what look like xrefs to data (dwords, bytes, etc)?

@vtbl(0x14169AE50, size=3)  # Cycle through __dict__, basically treating this like an enum
class Component__GUI__AtkResNode(Component__GUI__AtkEventTarget):
    dtor = 1  # also lose the nice layout orientation of all the addresses in a line, unless we turn off formatting, aligning the = signs. 
    ctor = 0x1404CC6B0"

@vtbl(0x14169AEC8)  # More verbose, harder to maintain? 
class Component__Gui__AtkCollisionNode(Component__GUI__AtkResNode):
    @vfunc(1)
    def dtor(): ...
    @func(0x14053F820)
    def ctor(): ...

It looks like a class, but its still basically working the vtables. However the automatic sizing would open up some opportunities I think. Especially if we can identify the first vtbl object regularly. Then they could all be labled something dumb like vtbl_Unknown001.

CExporter stack trace

It looks like the c structs are a bit out of date with the csharp source, so I tried building/running your CExporter and got the following:

PS C:\Users\miked\Source\repos\FFXIVClientStructs\ida\CExporter\bin\Debug\net5.0> ./CExporter.exe Unhandled exception. System.ArgumentException: Field passed in is not a marshaled member of the type 'FFXIVClientStructs.FFXIV.Client.UI.AddonEnemyList'. (Parameter 'fieldName') at System.Runtime.InteropServices.Marshal.OffsetOf(Type t, String fieldName) at CExporter.FieldInfoExtensions.GetFieldOffset(FieldInfo finfo) in C:\Users\miked\Source\repos\FFXIVClientStructs\ida\CExporter\Program.cs:line 424 at CExporter.Exporter.<>c.<ProcessStruct>b__10_1(FieldInfo finfo) in C:\Users\miked\Source\repos\FFXIVClientStructs\ida\CExporter\Program.cs:line 145 at System.Linq.EnumerableSorter2.ComputeKeys(TElement[] elements, Int32 count)
at System.Linq.EnumerableSorter1.ComputeMap(TElement[] elements, Int32 count) at System.Linq.EnumerableSorter1.Sort(TElement[] elements, Int32 count)
at System.Linq.OrderedEnumerable1.GetEnumerator()+MoveNext() at System.Linq.Lookup2.Create(IEnumerable1 source, Func2 keySelector, IEqualityComparer1 comparer) at System.Linq.GroupedEnumerable2.GetEnumerator()
at CExporter.Exporter.ProcessStruct(Type type, StringBuilder header) in C:\Users\miked\Source\repos\FFXIVClientStructs\ida\CExporter\Program.cs:line 147
at CExporter.Exporter.ProcessType(Type type, StringBuilder header) in C:\Users\miked\Source\repos\FFXIVClientStructs\ida\CExporter\Program.cs:line 105
at CExporter.Exporter.Export(GapStrategy strategy) in C:\Users\miked\Source\repos\FFXIVClientStructs\ida\CExporter\Program.cs:line 84
at CExporter.Program.Main(String[] _) in C:\Users\miked\Source\repos\FFXIVClientStructs\ida\CExporter\Program.cs:line 19`

Problem attaching IDA pro 7.7 debugger to ffxiv 7.7

I realize this is a bit OT, but I am suddenly unable to attach ida to the running game after the 6.1 patch. I was wondering if you have experienced this issue and, if so, have you discovered what anti-debug method they are using.

Status fields StackCount and Param are actually one field

In FFXIVClientStructs.FFXIV.Client.Game.Status, the fields StackCount and Param are actually one combined field, at least in the case of food and potions.

The u16 starting at offset 2 contains the ItemFood row for consumed food and potion status effects (i.e. "Well Fed" and "Medicated"). I imagine for status effects with stacks, it's conceivable that it's actually just a u16.

FateManager doesn't work.

I joint the fate in game, but FateManager.Instance()->FateJoined is 0. And the FateManager.Instance()->CurrentFate is Zero.

CExporter issue: AgentMap

namespace FFXIVClientStructs.FFXIV.Client.UI.Agent;
public unsafe partial struct AgentMap
{
    ....
    [FieldOffset(0x3AA0)] public fixed byte UnkArray2[0xA8 * 12];  // <-- until 0x4280, exceeds MiniMapMarker
    [FieldOffset(0x3E90)] public fixed byte MiniMapMarkerArray[0x40 * 100]; // 100 * MiniMapMarker
    ....
}

CExporter issue: AtkComponentNumericInput

namespace FFXIVClientStructs.FFXIV.Component.GUI;
public unsafe partial struct AtkComponentNumericInput
{
    ....
    [FieldOffset(0x0)] public AtkComponentInputBase AtkComponentInputBase; // Size 0xF0
    [FieldOffset(0xC8)] public AtkTextNode* AtkTextNode; // Does  this belong inside the base?
    ....
}

ffxiv_idarename.py generating a lot of errors with latest FFXIV version

Hello,

I am getting quite a few errors when I run this macro. They are of the sort:

7FF67FB4E810: can't rename byte as 'vtbl_Client::UI::AddonTooltip' because this byte can't have a name (it is a tail byte).
7FF67FB675A8: can't rename byte as 'vtbl_Client::UI::AddonCharaSelectWorldServer' because this byte can't have a name (it is a tail byte).
7FF67FBB5F98: can't rename byte as 'vtbl_Client::UI::AddonWeeklyPuzzle' because this byte can't have a name (it is a tail byte).
7FF67FBBD2A0: can't rename byte as 'vtbl_Client::UI::AddonMJIRecipeNoteBook' because this byte can't have a name (it is a tail byte).

and

Error: Function at 0x7FF67EA5E730 had unexpected name "" during naming of Client::Game::UI::RecipeNote.CancelCrafting
Error: Function at 0x7FF67EA5F690 had unexpected name "" during naming of Client::Game::UI::RecipeNote.IsRecipeUnlocked
Error: Function at 0x7FF67EA5FC00 had unexpected name "" during naming of Client::Game::UI::RecipeNote.FirstRecipeIndex
Error: Function at 0x7FF67EA5FBC0 had unexpected name "" during naming of Client::Game::UI::RecipeNote.GetRecipeByIndex
Error: Function at 0x7FF67EA5FC40 had unexpected name "" during naming of Client::Game::UI::RecipeNote.GetSelectedRecipe
Error: Function at 0x7FF67EA607A0 had unexpected name "" during naming of Client::Game::UI::RecipeNote.Initialize

probably hundreds of them. I did put the ida.cfg file in place. Is there something else I must do to not get these errors? Or is this normal?

Thanks.

Clarity on Acceptable Contributions

I apologize for opening this but I don't see anything in the repo about the kind of contributions you accept and this has recently come up and I wanted to ask/clarify.

Concerns have been raised with me about some of the things I've recently contributed (and were accepted), in that they are potentially dangerous (or even exploitable).

From my point of view, this project is meant to be an as complete as possible reverse engineering of FFXIV and encapsulates the collective knowledge about the client. There are already things either implemented (or documented in data.yml) which are inherently dangerous and can be used by nefarious developers to create cheats etc (and actively are).

I'm generally of the opinion that knowledge is not harmful and that if people choose to misuse or abuse it, that's on them.

Do you have any official guidance on what is acceptable to document/implement in this project and not?
Should I continue to push things regardless of what they are?

Patch 6.5 - ConfigOption enum off by one

Hi, you're probably still working on updating FFXIVClientStructs but just wanted to let you know this enum seems to be off by one now.

My plugin code which is now hitting BGM instead of master.

        /// <summary>
        /// Mutes/Unmutes the sound
        /// </summary>
        /// <param name="enabled"></param>
        public static unsafe void SetMasterSoundEnable(bool enabled)
        {
            Framework.Instance()->SystemConfig.CommonSystemConfig.ConfigBase.ConfigEntry[(int)ConfigOption.IsSndMaster].SetValueUInt((uint)(enabled ? 0 : 1));
        }

        public static unsafe bool GetMasterSoundEnable()
        {
            if (Framework.Instance()->SystemConfig.CommonSystemConfig.ConfigBase.ConfigEntry[(int)ConfigOption.IsSndMaster].Value.UInt == 0)
                PluginLog.Debug("Enabled");
            return (Framework.Instance()->SystemConfig.CommonSystemConfig.ConfigBase.ConfigEntry[(int)ConfigOption.IsSndMaster].Value.UInt == 0);
        }

Removing data from py rename script

I know how much you love updating your diff scripts. This seems sane enough, although if you want it in json instead, i can make that happen. The idea is simple enough, take the actual data out of the py script into a yml file.

version: 2020.12.29.0000.0000

globals:
  0x14169A2A0: g_HUDScaleTable

functions:
  0x140059670: FFXIVString_ctor  # empty string ctor

classes:
  Client::Game::Control::TargetSystem::ListFeeder:
  
  GroupManager:
    funcs:
      0x140BB2600: Create
  Common::Configuration::ConfigBase:
    inherits_from: Client::System::Common::NonCopyable
    vtbl: 0x14164E260
    funcs:
      0x140068C30: ctor
  Common::Configuration::UIConfig:
    inherits_from: Common::Configuration::ConfigBase 
    vtbl: 0x14164E280
  Client::System::Framework::Framework:
    vtbl: 0x14164F4B8
    vfuncs:
      1: Setup
    funcs:
      0x14008EA40: ctor

ffxiv_idarename.py doesn't work with Ghidra

ffxiv_idarename.py> Running...
  File "W:\bullshit\ghidra\ffxiv\FFXIVClientStructs\ida\ffxiv_idarename.py", line 619
    def recurse_tree(current_node: Node, current_class: FfxivClass, all_bases: set[str]):
                                ^
SyntaxError: mismatched input ':' expecting RPAREN
ffxiv_idarename.py> Finished!

Seems to be this commit breaking it - type hinting isn't in py2, which Ghidra uses.

PartyMember Struct Field 0x1A0

FYI, the unknown long at 0x1A0 in FFXIVClientStructs.FFXIV.Group.Partymember is the players Content ID (errr I think that's what it's called anyway; your eight-byte identifier).

CExporter issue: BallonType

Is BalloonType uint or byte?
Current offset exceeded the next field's offset (0xEC > 0xE9): Client::UI::Agent::BalloonInfo.byte

namespace FFXIVClientStructs.FFXIV.Client.Game;
public enum BalloonType : uint
{
    Timer = 0, // runs on a simple timer and disappears when the timer ends
    Unknown = 1 // the non-timer mode, not sure what its called or where its used
}

namespace FFXIVClientStructs.FFXIV.Client.Game;
public struct Balloon
{
    ...
    [FieldOffset(0x8)] public BalloonType Type; // <- uint usage?
    [FieldOffset(0xC)] public BalloonState State;
    ...
}

namespace FFXIVClientStructs.FFXIV.Client.UI.Agent;
public unsafe struct BalloonInfo
{
    ...
    [FieldOffset(0xE4)] public int BalloonId;  // <- byte usage?
    [FieldOffset(0xE8)] public BalloonType Type;
    ...
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.