Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sonic Frontiers] Implemented basic code library support for PlayerVisuals #60

Merged
merged 6 commits into from
Nov 19, 2023
33 changes: 32 additions & 1 deletion Source/Sonic Frontiers/Libraries/GOComponents.hmm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Library "GOComponents" by "Hyper"
#lib "Memory"
#lib "Player"
#lib "PlayerEffect"
#lib "PlayerVisual"
#lib "StringMapOperation"

#import "Cameras"
Expand Down Expand Up @@ -472,7 +473,37 @@ Library "GOComponents" by "Hyper"
[StructLayout(LayoutKind.Explicit, Size = 0x180)]
public struct GOCPlayerVisual
{
[FieldOffset(0)] public GOComponent Base;
/* 0x1408BA540 */
private static long _sigInternalGetVisualAs = ScanSignature(
"\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x8B\xD9\x8B\xFA\x48\x8B\x89\x08",
"xxxxxxxxxxxxxxxxxxx"
);

[FieldOffset(0x000)] public GOComponent Base;
NM-20 marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// A pointer to an instance of `app::player::PlayerVisual`.
/// </summary>
[FieldOffset(0x108)] public PlayerVisual.Data *pPlayerVisual;

FUNCTION_PTR(PlayerVisual.Data *, fpInternalGetVisualAs, _sigInternalGetVisualAs, GOCPlayerVisual *_this, uint in_nameHash)
NM-20 marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Attempts to cast <see cref="pPlayerVisual"/> to the specified <see cref="Type"/>.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> to be used in the cast.</typeparam>
/// <returns>If successful, the casted <see cref="pPlayerVisual"/>; otherwise, null.</returns>
public T *GetVisualAs<T>() where T : unmanaged
NM-20 marked this conversation as resolved.
Show resolved Hide resolved
{
Type type = typeof(T);
uint hash = StringMapOperation.ComputeHash(type.Name);

fixed (GOCPlayerVisual *pThis = &this)
{
PlayerVisual.Data *result = GET_FUNCTION_PTR(fpInternalGetVisualAs)(pThis, hash);
return (T *)result;
}
}
}

/// <summary>
Expand Down
26 changes: 26 additions & 0 deletions Source/Sonic Frontiers/Libraries/PlayerVisual.hmm
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Library "PlayerVisual" by "NM"
{
#include "Helpers" noemit

using System.Runtime.InteropServices;

/// <summary>
/// A struct representation of `app::player::PlayerVisual`.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
public struct Data
{
VFUNCTION_PTR(Data, 1, uint, GetNameHash)
}

/// <summary>
/// A struct representation of `app::player::VisualSuperSonic`.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 0x11C /* ? */)]
NM-20 marked this conversation as resolved.
Show resolved Hide resolved
public struct VisualSuperSonic
{
[FieldOffset(0x000)] public PlayerVisual.Data Base;

[FieldOffset(0x118)] public bool IsSuperSonic2;
NM-20 marked this conversation as resolved.
Show resolved Hide resolved
}
}