Library "INI" by "Hyper" { using System.Collections.Generic; using System.IO; public Dictionary> Read(string path) { Dictionary> result = new(); if (!File.Exists(path)) return result; using (StreamReader reader = new StreamReader(path)) { string section = string.Empty; string line = string.Empty; // Add root section. result.Add(section, new Dictionary()); while ((line = reader.ReadLine()) != null) { if (line.StartsWith("[") && line.EndsWith("]")) { section = line.Substring(1, line.Length - 2); result.Add(section, new Dictionary()); continue; } if (line.StartsWith(";") || line.StartsWith("#")) continue; int delimiterIndex = line.IndexOf('='); if (delimiterIndex == -1) continue; string key = line.Substring(0, delimiterIndex); string value = line.Substring(delimiterIndex + 1); if (value.StartsWith("\"") && value.EndsWith("\"") && value.Length > 1) value = value.Substring(1, value.Length - 2); result[section].Add(key, value); } } return result; } public T Parse(string in_value, T in_defaultValue) { T result = in_defaultValue; if (typeof(T) == typeof(string)) { result = (T)(object)in_value; } else if (typeof(T) == typeof(bool)) { if (bool.TryParse(in_value, out bool out_boolValue)) { result = (T)(object)out_boolValue; } else { return (T)(object)(Parse(in_value, (bool)(object)in_defaultValue ? 1 : 0) > 0); } } else if (typeof(T) == typeof(int)) { if (int.TryParse(in_value, out int out_intValue)) result = (T)(object)out_intValue; } else if (typeof(T) == typeof(double)) { if (double.TryParse(in_value, out double out_doubleValue)) result = (T)(object)out_doubleValue; } else if (typeof(T) == typeof(float)) { if (float.TryParse(in_value, out float out_floatValue)) result = (T)(object)out_floatValue; } return result; } public T GetField(Dictionary> in_ini, string in_section, string in_key, T in_defaultValue) { if (!in_ini.ContainsKey(in_section)) return in_defaultValue; if (!in_ini[in_section].ContainsKey(in_key)) return in_defaultValue; return Parse(in_ini[in_section][in_key], in_defaultValue); } } Library "RTTI" by "Hyper" { #lib "Memory" #define RESOLVE_RELATIVE_PTR(in_offset) (IntPtr.Size == 4 ? in_offset : (0x140000000 + in_offset)) using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; [DllImport("imagehlp.dll", CallingConvention = CallingConvention.StdCall)] private static extern uint UnDecorateSymbolName([MarshalAs(UnmanagedType.LPStr)] string name, byte[] outputString, uint maxStringLength, uint flags); [StructLayout(LayoutKind.Sequential)] public struct CompleteObjectLocator { public int Signature; public int VftableOffset; public int CtorDisplacementOffset; public int pTypeDescriptor; public int pClassHierarchyDescriptor; public int pObjectBase; public TypeDescriptor* GetTypeDescriptor() { return (TypeDescriptor*)RESOLVE_RELATIVE_PTR(pTypeDescriptor); } public ClassHierarchyDescriptor* GetClassHierarchyDescriptor() { return (ClassHierarchyDescriptor*)RESOLVE_RELATIVE_PTR(pClassHierarchyDescriptor); } public override string ToString() => $"const {GetTypeDescriptor()->GetName()}::`RTTI Complete Object Locator'"; } [StructLayout(LayoutKind.Sequential)] public struct TypeDescriptor { public void* pTypeInfo; public void* pRuntimeRef; public string GetName(bool in_isDemangled = true, IEnumerable in_demanglerFlags = null) { fixed (TypeDescriptor* pThis = &this) { var result = Marshal.PtrToStringAnsi((nint)((long)pThis + (IntPtr.Size == 4 ? 0x08 : 0x10))); if (string.IsNullOrEmpty(result)) return string.Empty; result = result.TrimStart('.'); if (in_isDemangled) { if (in_demanglerFlags == null) in_demanglerFlags = new[] { RTTI.DemanglerFlags.NAME_ONLY }; return Demangle(result, in_demanglerFlags); } else { return result; } } } public string[] GetNamespaces() { return GetName().Split(new[] { "::" }, StringSplitOptions.RemoveEmptyEntries); } public override string ToString() => $"class {GetName()} `RTTI Type Descriptor'"; } [StructLayout(LayoutKind.Sequential)] public struct ClassHierarchyDescriptor { public int Signature; public int Attributes; public int BaseClassCount; public int pBaseClasses; public BaseClassDescriptor* GetBaseClass(int in_index) { if (in_index > BaseClassCount) return null; var ptr = *(int*)(RESOLVE_RELATIVE_PTR(pBaseClasses) + (in_index * 4)); return (BaseClassDescriptor*)(RESOLVE_RELATIVE_PTR(ptr)); } public override string ToString() => $"{GetBaseClass(0)->GetTypeDescriptor()->GetName()}::`RTTI Class Hierarchy Descriptor'"; } [StructLayout(LayoutKind.Sequential)] public struct BaseClassDescriptor { public int pTypeDescriptor; public int SubElementCount; public int MemberDisplacement; public int VftableDisplacement; public int DisplacementWithinVftable; public int BaseClassAttributes; public int pClassHierarchyDescriptor; public TypeDescriptor* GetTypeDescriptor() { return (TypeDescriptor*)RESOLVE_RELATIVE_PTR(pTypeDescriptor); } public ClassHierarchyDescriptor* GetClassHierarchyDescriptor() { return (ClassHierarchyDescriptor*)RESOLVE_RELATIVE_PTR(pClassHierarchyDescriptor); } public override string ToString() => $"{GetTypeDescriptor()->GetName()}::`RTTI Base Class Descriptor at ({MemberDisplacement}, {VftableDisplacement}, {DisplacementWithinVftable}, {BaseClassAttributes})'"; } public CompleteObjectLocator* GetRuntimeInfoFromVftable(void* in_pVftable) { if (in_pVftable == null) return null; var runtimeInfoOffset = *(long*)((long)in_pVftable - IntPtr.Size); if (!Memory.IsAccessible((nint)runtimeInfoOffset)) return null; return (CompleteObjectLocator*)runtimeInfoOffset; } public CompleteObjectLocator* GetRuntimeInfo(void* in_pClass) { return GetRuntimeInfoFromVftable((void*)*(long*)in_pClass); } public string GetClassName(void* in_pClass, bool in_isDemangled = true, IEnumerable in_demanglerFlags = null) { var pRuntimeInfo = RTTI.GetRuntimeInfo(in_pClass); if (pRuntimeInfo == null) return string.Empty; var pTypeDescriptor = pRuntimeInfo->GetTypeDescriptor(); if (pTypeDescriptor == null) return string.Empty; return pTypeDescriptor->GetName(in_isDemangled, in_demanglerFlags); } public string[] GetClassNamespaces(void* in_pClass) { return GetClassName(in_pClass).Split(new[] { "::" }, StringSplitOptions.RemoveEmptyEntries); } public string Demangle(string in_mangledName, IEnumerable in_flags) { var result = string.Empty; var flags = 0U; var demangledBytes = new byte[1024]; foreach (var flag in in_flags) flags |= (uint)flag; while (true) { var resultLength = UnDecorateSymbolName ( in_mangledName, demangledBytes, (uint)demangledBytes.Length, (uint)flags ); if (resultLength == (demangledBytes.Length - 2)) { demangledBytes = new byte[demangledBytes.Length * 2]; continue; } else { int count = Array.IndexOf(demangledBytes, 0, 0); if (count < 0) count = demangledBytes.Length; result = Encoding.ASCII.GetString(demangledBytes, 0, count); break; } } if (string.IsNullOrEmpty(result)) return result; var namespaces = result.Split(new[] { "::" }, StringSplitOptions.RemoveEmptyEntries); if (namespaces.Length > 0) { var last = namespaces[namespaces.Length - 1]; if (last.StartsWith("AV")) namespaces[namespaces.Length - 1] = last.Remove(0, 2); result = string.Join("::", namespaces); } return result; } public enum DemanglerFlags { /// /// Enable full undecoration. /// COMPLETE = 0x0000, /// /// Remove leading underscores from Microsoft keywords. /// NO_LEADING_UNDERSCORES = 0x0001, /// /// Disable expansion of Microsoft keywords. /// NO_MS_KEYWORDS = 0x0002, /// /// Disable expansion of return types for primary declarations. /// NO_FUNCTION_RETURNS = 0x0004, /// /// Disable expansion of the declaration model. /// NO_ALLOCATION_MODEL = 0x0008, /// /// Disable expansion of the declaration language specifier. /// NO_ALLOCATION_LANGUAGE = 0x0010, /// /// Disable expansion of Microsoft keywords on the this type for primary declaration. /// NO_MS_THISTYPE = 0x0020, /// /// Disable expansion of CodeView modifiers on the this type for primary declaration. /// NO_CV_THISTYPE = 0x0040, /// /// Disable all modifiers on the "this" type. /// NO_THISTYPE = 0x0060, /// /// Disable expansion of access specifiers for members. /// NO_ACCESS_SPECIFIERS = 0x0080, /// /// Disable expansion of throw-signatures for functions and pointers to functions. /// NO_THROW_SIGNATURES = 0x0100, /// /// Disable expansion of the static or virtual attribute of members. /// NO_MEMBER_TYPE = 0x0200, /// /// Disable expansion of the Microsoft model for user-defined type returns. /// NO_RETURN_UDT_MODEL = 0x0400, /// /// Undecorate 32-bit decorated names. /// P32_BIT_DECODE = 0x0800, /// /// Undecorate only the name for primary declaration. Returns [scope::]name. Does expand template parameters. /// NAME_ONLY = 0x1000, /// /// Do not undecorate function arguments. /// NO_ARGUMENTS = 0x2000, /// /// Do not undecorate special names, such as vtable, vcall, vector, metatype, and so on. /// NO_SPECIAL_SYMS = 0x4000 } } Library "Win32" by "Hyper" { using System.Diagnostics; using System.Runtime.InteropServices; private static IntPtr _windowHandle = IntPtr.Zero; [DllImport("kernel32.dll")] private static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); [LibraryUpdate] public void Update() { if (_windowHandle == IntPtr.Zero) { var hwnd = Process.GetCurrentProcess().MainWindowHandle; if (hwnd == GetConsoleWindow()) return; _windowHandle = hwnd; } } public static IntPtr GetGameWindowHandle() { return _windowHandle; } public static bool IsGameForegroundWindow() { return GetForegroundWindow() == _windowHandle; } } Library "Memory" by "Hyper & Sajid" { using System.Collections.Generic; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Text; [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr VirtualQuery(IntPtr lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, UIntPtr dwLength); [StructLayout(LayoutKind.Sequential)] public struct MEMORY_BASIC_INFORMATION { public IntPtr BaseAddress; public IntPtr AllocationBase; public uint AllocationProtect; public IntPtr RegionSize; public uint State; public uint Protect; public uint Type; } private static Dictionary> _preservedMemory = new(); public void Preserve(nint in_location, nint in_length, bool in_isPreservedOnce = true) { if (in_location == 0) return; if (in_isPreservedOnce) { if (_preservedMemory.ContainsKey(in_location)) return; } else { if (_preservedMemory.ContainsKey(in_location)) _preservedMemory.Remove(in_location); } List buffer = new(); for (nint i = 0; i < in_length; i++) buffer.Add(Read(in_location + i)); _preservedMemory.Add(in_location, buffer); } public void Preserve(long in_location, long in_length, bool in_isPreservedOnce = true) { Preserve((nint)in_location, (nint)in_length, in_isPreservedOnce); } public void Restore(nint in_location) { if (in_location == 0) return; if (!_preservedMemory.ContainsKey(in_location)) return; nint i = 0; foreach (byte b in _preservedMemory[in_location]) { WriteProtected(in_location + i, b); i++; } } public void Restore(long in_location) { Restore((nint)in_location); } public uint GetPageProtectFlags(nint in_location) { var memInfo = new MEMORY_BASIC_INFORMATION(); if (VirtualQuery(in_location, ref memInfo, (UIntPtr)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION))) == IntPtr.Zero) return 1; return memInfo.Protect; } public bool IsAccessible(nint in_location) { // PAGE_NOACCESS if ((GetPageProtectFlags(in_location) & 1) != 0) return false; return true; } public nint ReadCall(nint in_location) { if (in_location == 0) return 0; return in_location + Read(in_location + 0x01) + 0x05; } public long ReadCall(long in_location) { return (long)ReadCall((nint)in_location); } public nint ReadEffectiveAddress(nint in_location) { if (in_location == 0) return 0; return in_location + Read(in_location + 0x03) + 0x07; } public long ReadEffectiveAddress(long in_location) { return (long)ReadEffectiveAddress((nint)in_location); } public enum JumpType : sbyte { Unknown = -1, ShortCond, NearJmp, NearCond, LongJmp } public JumpType ReadJumpOpcode(nint in_location) { JumpType result = JumpType.Unknown; if (in_location == 0) return result; byte opcode = Read(in_location); if ((opcode & 0xF0) == 0x70) { result = JumpType.ShortCond; } else { switch (opcode) { case 0xE3: case 0xEB: result = JumpType.ShortCond; break; case 0xE9: result = JumpType.NearJmp; break; case 0x0F: result = JumpType.NearCond; break; case 0xFF: result = JumpType.LongJmp; break; } } return result; } public JumpType ReadJumpOpcode(long in_location) { return ReadJumpOpcode((nint)in_location); } public nint ReadJump(nint in_location) { if (in_location == 0) return 0; switch (ReadJumpOpcode(in_location)) { case JumpType.ShortCond: return in_location + Read(in_location + 0x01) + 0x02; case JumpType.NearJmp: return in_location + Read(in_location + 0x01) + 0x05; case JumpType.NearCond: return in_location + Read(in_location + 0x02) + 0x06; case JumpType.LongJmp: return (nint)Read(in_location + 0x06); } return 0; } public long ReadJump(long in_location) { return (long)ReadJump((nint)in_location); } public void WriteForceJump(nint in_location) { if (in_location == 0) return; switch (ReadJumpOpcode(in_location)) { case JumpType.ShortCond: WriteProtected(in_location, 0xEB); break; case JumpType.NearCond: WriteProtected(in_location, 0xE9); WriteProtected(in_location + 0x01, Read(in_location + 0x02) + 0x01); break; } } public void WriteForceJump(long in_location) { WriteForceJump((nint)in_location); } public nint ReadThunk(nint in_location, nint in_offset = 0) { return ReadJump(ReadCall(in_location) + in_offset); } public long ReadThunk(long in_location, long in_offset = 0) { return (long)ReadThunk((nint)in_location, (nint)in_offset); } public void WriteString(long in_location, string in_str, Encoding in_encoding) { WriteProtected(in_location, in_encoding.GetBytes(in_str)); } public void WriteString(long in_location, string in_str) { WriteString(in_location, in_str, Encoding.ASCII); } public void PrintMemory(IntPtr in_address, int in_rowCount) where T : unmanaged { for (int i = 0; i < in_rowCount * 16; i += 16) { Console.Write($"{(in_address + i).ToInt64():X16}: "); if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte)) { for (int j = 0; j < 16; j++) Console.Write($"{Read(in_address + i + j):X2} "); } else if (typeof(T) == typeof(short) || typeof(T) == typeof(ushort)) { for (int j = 0; j < 16; j += 2) Console.Write($"{Read(in_address + i + j):X4} "); } else if (typeof(T) == typeof(int) || typeof(T) == typeof(uint)) { for (int j = 0; j < 16; j += 4) Console.Write($"{Read(in_address + i + j):X8} "); } else if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong)) { for (int j = 0; j < 16; j += 8) Console.Write($"{Read(in_address + i + j):X16} "); } else if (typeof(T) == typeof(float)) { for (int j = 0; j < 16; j += 4) Console.Write($"{Read(in_address + i + j)} "); } else if (typeof(T) == typeof(double)) { for (int j = 0; j < 16; j += 8) Console.Write($"{Read(in_address + i + j)} "); } Console.WriteLine(); } } public void PrintMemory(IntPtr in_address, int in_rowCount) { PrintMemory(in_address, in_rowCount); } public static bool TryGetPointer(void* in_pData, out T* out_pData) where T : unmanaged { out_pData = (T*)in_pData; return in_pData != null; } public struct Pointer where T : unmanaged { public T* pData; public Pointer(ref T data) { fixed(T* dataPtr = &data) { pData = dataPtr; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Pointer(T* in_pData) { pData = in_pData; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsValid() { return pData != null; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T Ref() { return ref *pData; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public T* Get() { return pData; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator bool(Pointer self) => self.IsValid(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Pointer(T* data) => new(data); public override string ToString() => $"0x{((long)pData):X}"; } } Library "DeltaTime" by "Hyper" { using System.Diagnostics; private static Stopwatch _frameTimer = new Stopwatch(); private static float _deltaTime; private static int _deltaIndex; private static float _deltaSum; private static float[] _deltaSamples = new float[100]; [LibraryInitializer] public void Init() { _frameTimer = Stopwatch.StartNew(); } [LibraryUpdate] public void Update() { _deltaTime = (float)_frameTimer.Elapsed.TotalMilliseconds / 1000.0f; _frameTimer.Reset(); _frameTimer.Start(); } public float GetDeltaTime() { return _deltaTime; } public float GetDeltaTimeAverage() { _deltaSum -= _deltaSamples[_deltaIndex]; _deltaSum += _deltaTime; _deltaSamples[_deltaIndex] = _deltaTime; if (++_deltaIndex == _deltaSamples.Length) _deltaIndex = 0; return _deltaSum / _deltaSamples.Length; } public double GetDeltaTimeMilliseconds() { return _frameTimer.Elapsed.TotalMilliseconds; } public float GetFrameRate(bool in_isRounded = true) { var result = 1.0f / _deltaTime; if (in_isRounded) result = (float)Math.Round(result); return result; } public float GetFrameRateAverage(bool in_isRounded = true) { var result = 1.0f / GetDeltaTimeAverage(); if (in_isRounded) result = (float)Math.Round(result); return result; } } Library "HMM" by "Hyper" { #lib "INI" using Microsoft.Win32; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Threading; public string GetGameDirectory() { return Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); } public Dictionary> GetModsDatabase() { string cpkredirCfgPath = Path.Combine(GetGameDirectory(), "cpkredir.ini"); if (!File.Exists(cpkredirCfgPath)) return new(); var cpkredirCfg = INI.Read(cpkredirCfgPath); string modsDbPath = cpkredirCfg["CPKREDIR"]["ModsDbIni"]; if (!File.Exists(modsDbPath)) return new(); return INI.Read(modsDbPath); } public List GetMods() { List result = new(); var modsDb = GetModsDatabase(); if (modsDb.Count <= 0) return result; int activeModCount = INI.Parse(modsDb["Main"]["ActiveModCount"], 0); foreach (var entry in modsDb["Mods"].Keys) { for (int i = 0; i < activeModCount; i++) { if (modsDb["Main"][$"ActiveMod{i}"].Contains(entry)) { result.Add(new Mod(modsDb["Mods"][entry])); } } } return result; } public Mod GetModByID(string in_id) { foreach (var mod in GetMods()) { if (mod.ID == in_id) return mod; } return null; } public List FindModsByName(string name) { List result = new(); foreach (var mod in GetMods()) { if (mod.Name.Contains(name)) { result.Add(mod); } } return result; } public List GetCodes() { List result = new(); var modsDb = GetModsDatabase(); if (modsDb == null) return result; foreach (var value in modsDb["Codes"].Values) result.Add(value); return result; } public class Mod { public string Name { get; set; } public string Version { get; set; } public string Author { get; set; } public string Description { get; set; } public string Date { get; set; } public string AuthorURL { get; set; } public string UpdateServer { get; set; } public string SaveFile { get; set; } public string ID { get; set; } public List IncludeDirs { get; set; } = new(); public List Dependencies { get; set; } = new(); public string DLLFile { get; set; } public string CodeFile { get; set; } public string ConfigSchemaFile { get; set; } public string Path { get; set; } public Dictionary> Ini { get; set; } = new(); public Mod(string modIniPath) { var ini = INI.Read(modIniPath); if (ini == null) return; Name = INI.GetField(ini, "Desc", "Title", Name); Version = INI.GetField(ini, "Desc", "Version", Version); Author = INI.GetField(ini, "Desc", "Author", Author); Description = INI.GetField(ini, "Desc", "Description", Description); Date = INI.GetField(ini, "Desc", "Date", Date); AuthorURL = INI.GetField(ini, "Desc", "AuthorURL", AuthorURL); UpdateServer = INI.GetField(ini, "Main", "UpdateServer", UpdateServer); SaveFile = INI.GetField(ini, "Main", "SaveFile", SaveFile); ID = INI.GetField(ini, "Main", "ID", ID); DLLFile = INI.GetField(ini, "Main", "DLLFile", DLLFile); CodeFile = INI.GetField(ini, "Main", "CodeFile", CodeFile); ConfigSchemaFile = INI.GetField(ini, "Main", "ConfigSchemaFile", ConfigSchemaFile); Path = System.IO.Path.GetDirectoryName(modIniPath); Ini = ini; int includeDirCount = INI.GetField(ini, "Main", "IncludeDirCount", 1); for (int i = 0; i < includeDirCount; i++) IncludeDirs.Add(INI.GetField(ini, "Main", $"IncludeDir{i}", ".")); int dependencyCount = INI.GetField(ini, "Main", "DependsCount", 0); for (int i = 0; i < dependencyCount; i++) Dependencies.Add(new ModDependency(INI.GetField(ini, "Main", $"Depends{i}", ""))); } } public class ModDependency { public string ID { get; set; } public string Name { get; set; } public string Link { get; set; } public string Version { get; set; } public ModDependency(string in_id, string in_name, string in_link, string in_version) { ID = in_id; Name = in_name; Link = in_link; Version = in_version; } public ModDependency(string in_csv) { var fields = in_csv.Split('|'); for (int i = 0; i < fields.Length; i++) { switch (i) { case 0: ID = fields[i]; break; case 1: Name = fields[i]; break; case 2: { if (fields.Length > 2) { Link = fields[i]; } else { Version = fields[i]; } break; } case 3: Version = fields[i]; break; } } } } public static class RegistryConfig { public static string ConfigPath { get; } = @"SOFTWARE\HEDGEMM"; public static bool CheckLoaderUpdates { get; set; } = true; public static bool CheckManagerUpdates { get; set; } = true; public static bool CheckModUpdates { get; set; } = true; public static int CodesSortingColumnIndex { get; set; } = 1; public static bool CodesUseTreeView { get; set; } = true; public static string ExecutablePath { get; set; } public static string ExtraGameDirectories { get; set; } public static bool KeepOpen { get; set; } = true; public static string LastGameDirectory { get; set; } public static string UILanguage { get; set; } public static string UITheme { get; set; } public static bool UpdateCodesOnLaunch { get; set; } = true; static RegistryConfig() { Load(); } public static void Load() { var personalizeKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize"); bool isLightTheme = false; if (personalizeKey != null) { var useLightThemeStr = personalizeKey.GetValue("AppsUseLightTheme", 0)?.ToString(); if (int.TryParse(useLightThemeStr, out int out_isLightTheme)) isLightTheme = out_isLightTheme != 0; personalizeKey.Close(); } var key = Registry.CurrentUser.CreateSubKey(ConfigPath); LastGameDirectory = (string)key.GetValue("LastGame", string.Empty); ExtraGameDirectories = (string)key.GetValue(nameof(ExtraGameDirectories), string.Empty); UILanguage = (string)key.GetValue(nameof(UILanguage), Thread.CurrentThread.CurrentCulture.Name); UITheme = (string)key.GetValue(nameof(UITheme), isLightTheme ? "LightTheme" : "DarkerTheme"); CodesSortingColumnIndex = (int)key.GetValue(nameof(CodesSortingColumnIndex), 1); CodesUseTreeView = (int)key.GetValue(nameof(CodesUseTreeView), 1) != 0; UpdateCodesOnLaunch = (int)key.GetValue(nameof(UpdateCodesOnLaunch), 1) != 0; CheckManagerUpdates = (int)key.GetValue(nameof(CheckManagerUpdates), 1) != 0; CheckLoaderUpdates = (int)key.GetValue(nameof(CheckLoaderUpdates), 1) != 0; CheckModUpdates = (int)key.GetValue(nameof(CheckModUpdates), 1) != 0; KeepOpen = (int)key.GetValue(nameof(KeepOpen), 1) != 0; key.Close(); } public static void Save() { var key = Registry.CurrentUser.CreateSubKey(ConfigPath); key.SetValue("ExecutablePath", Assembly.GetExecutingAssembly().Location); key.SetValue("LastGame", LastGameDirectory); key.SetValue(nameof(ExtraGameDirectories), ExtraGameDirectories); key.SetValue(nameof(UILanguage), UILanguage); key.SetValue(nameof(UITheme), UITheme); key.SetValue(nameof(CodesSortingColumnIndex), CodesSortingColumnIndex); key.SetValue(nameof(CodesUseTreeView), CodesUseTreeView ? 1 : 0); key.SetValue(nameof(UpdateCodesOnLaunch), UpdateCodesOnLaunch ? 1 : 0); key.SetValue(nameof(CheckManagerUpdates), CheckManagerUpdates ? 1 : 0); key.SetValue(nameof(CheckLoaderUpdates), CheckLoaderUpdates ? 1 : 0); key.SetValue(nameof(CheckModUpdates), CheckModUpdates ? 1 : 0); key.SetValue(nameof(KeepOpen), KeepOpen ? 1 : 0); key.Close(); } } } Library "StringMapOperation" by "ĐeäTh" { /// /// Computes a hash based on the input string. /// /// The string to hash. /// A string hash. public uint ComputeHash(string in_key) { uint hash = in_key[0]; for (int i = 1; i < in_key.Length; i++) hash = in_key[i] + 31 * hash; return hash & 0x7FFFFFFF; } } Library "MathHelpers" by "Hyper" { using System.Collections.Generic; public T Clamp(T in_value, T in_minValue, T in_maxValue) where T : IComparable { if (in_value.CompareTo(in_minValue) < 0) { return in_minValue; } else if (in_value.CompareTo(in_maxValue) > 0) { return in_maxValue; } else { return in_value; } } public T Clamp01(T value) where T : IComparable { if (value.CompareTo(default(T)) < 0) { return default(T); } else if (value.CompareTo((T)Convert.ChangeType(1, typeof(T))) > 0) { return (T)Convert.ChangeType(1, typeof(T)); } else { return value; } } public T FloatPercentToRange(float in_value) { if (typeof(T) == typeof(sbyte)) { return (T)(object)(byte)(in_value * (sbyte.MaxValue * 1.0f)); } else if (typeof(T) == typeof(byte)) { return (T)(object)(byte)(in_value * (byte.MaxValue * 1.0f)); } else if (typeof(T) == typeof(short)) { return (T)(object)(short)(in_value * (short.MaxValue * 1.0f)); } else if (typeof(T) == typeof(ushort)) { return (T)(object)(ushort)(in_value * (ushort.MaxValue * 1.0f)); } else if (typeof(T) == typeof(int)) { return (T)(object)(int)(in_value * (int.MaxValue * 1.0f)); } else if (typeof(T) == typeof(uint)) { return (T)(object)(uint)(in_value * (uint.MaxValue * 1.0f)); } else if (typeof(T) == typeof(long)) { return (T)(object)(long)(in_value * (long.MaxValue * 1.0f)); } else if (typeof(T) == typeof(ulong)) { return (T)(object)(ulong)(in_value * (ulong.MaxValue * 1.0f)); } return default; } public float Lerp(float in_start, float in_end, float in_time) { return in_start + (in_end - in_start) * in_time; } public static float InverseLerp(float a, float b, float value) { if (a == b) return 0.0f; return Clamp01((value - a) / (b - a)); } public static float Remap(float in_value, float in_sourceFrom, float in_sourceTo, float in_destinationFrom, float in_destinationTo) { return (in_value - in_sourceFrom) / (in_sourceTo - in_sourceFrom) * (in_destinationTo - in_destinationFrom) + in_destinationFrom; } public static float ToDegrees(float in_radians) { return in_radians * (180.0f / (float)Math.PI); } public static float ToRadians(float in_degrees) { return in_degrees * ((float)Math.PI / 180.0f); } public static float WrapToRadians(float in_value) { float sign = in_value > 0.0f ? 1.0f : -1.0f; float mod = (float)Math.Abs(in_value) % 6.28319f; return mod * sign; } } Library "XInput" by "Hyper" { #lib "MathHelpers" #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; [DllImport("xinput1_4.dll", EntryPoint = "XInputGetState")] public extern int XInputGetState(int in_dwUserIndex, ref State in_pState); [DllImport("xinput1_4.dll", EntryPoint = "XInputSetState")] public extern int XInputSetState(int in_dwUserIndex, ref Vibration in_pVibration); public const short XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE = 7849; public const short XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE = 8689; private static float _leftMotorSpeed = 0.0f; private static float _rightMotorSpeed = 0.0f; [Flags] public enum Buttons : ushort { DPAD_UP = 0x0001, DPAD_DOWN = 0x0002, DPAD_LEFT = 0x0004, DPAD_RIGHT = 0x0008, START = 0x0010, BACK = 0x0020, LEFT_THUMB = 0x0040, RIGHT_THUMB = 0x0080, LEFT_SHOULDER = 0x0100, RIGHT_SHOULDER = 0x0200, A = 0x1000, B = 0x2000, X = 0x4000, Y = 0x8000 } [StructLayout(LayoutKind.Sequential)] public struct State { public int dwPacketNumber; public Gamepad Gamepad; } [StructLayout(LayoutKind.Sequential)] public struct Gamepad { public Buttons wButtons; public byte bLeftTrigger; public byte bRightTrigger; public short sThumbLX; public short sThumbLY; public short sThumbRX; public short sThumbRY; } [StructLayout(LayoutKind.Sequential)] public struct Vibration { public ushort wLeftMotorSpeed; public ushort wRightMotorSpeed; public Vibration(ushort in_leftMotorSpeed, ushort in_rightMotorSpeed) { wLeftMotorSpeed = in_leftMotorSpeed; wRightMotorSpeed = in_rightMotorSpeed; _leftMotorSpeed = in_leftMotorSpeed / 65535.0f; _rightMotorSpeed = in_rightMotorSpeed / 65535.0f; } public Vibration(float in_leftMotorSpeed, float in_rightMotorSpeed) { wLeftMotorSpeed = MathHelpers.FloatPercentToRange(in_leftMotorSpeed); wRightMotorSpeed = MathHelpers.FloatPercentToRange(in_rightMotorSpeed); _leftMotorSpeed = in_leftMotorSpeed; _rightMotorSpeed = in_rightMotorSpeed; } public Vibration(ushort in_motorSpeed) { wLeftMotorSpeed = wRightMotorSpeed = in_motorSpeed; _leftMotorSpeed = _rightMotorSpeed = in_motorSpeed / 65535.0f; } public Vibration(float in_motorSpeed) { wLeftMotorSpeed = wRightMotorSpeed = MathHelpers.FloatPercentToRange(in_motorSpeed); _leftMotorSpeed = _rightMotorSpeed = in_motorSpeed; } } public State? GetState() { var pState = new State(); if (XInputGetState(0, ref pState) != 0) return null; return pState; } public void SetState(Vibration in_vibration) { XInputSetState(0, ref in_vibration); } public Vector2 GetAnalog(int in_analogIndex, bool in_isTestDeadzone = true) { var pState = GetState(); if (pState == null) return Vector2.Zero; Vector2 v = Vector2.Zero; switch (in_analogIndex) { case 0: v = new Vector2(pState.Value.Gamepad.sThumbLX / 32767.0f, pState.Value.Gamepad.sThumbLY / 32767.0f); break; case 1: v = new Vector2(pState.Value.Gamepad.sThumbRX / 32767.0f, pState.Value.Gamepad.sThumbRY / 32767.0f); break; } if (in_isTestDeadzone) { v = IsAnalogNeutral(in_analogIndex) ? Vector2.Zero : v; } return v; } // Use Player.Input for keyboard parity! public bool IsButtonDown(Buttons in_buttons) { var pState = GetState(); if (pState == null) return false; return (pState.Value.Gamepad.wButtons & in_buttons) != 0; } public float GetTrigger(int in_triggerIndex) { var pState = GetState(); if (pState == null) return 0; switch (in_triggerIndex) { case 0: return pState.Value.Gamepad.bLeftTrigger / 255.0f; case 1: return pState.Value.Gamepad.bRightTrigger / 255.0f; } return 0; } public bool IsAnalogNeutral(int in_analogIndex) { var pState = GetState(); if (pState == null) return true; switch (in_analogIndex) { case 0: { short x = pState.Value.Gamepad.sThumbLX; short y = pState.Value.Gamepad.sThumbLY; return x < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && x > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && y < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && y > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; } case 1: { short x = pState.Value.Gamepad.sThumbRX; short y = pState.Value.Gamepad.sThumbRY; return x < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && x > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && y < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && y > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; } } return true; } public Vibration GetVibration() { return new Vibration(_leftMotorSpeed, _rightMotorSpeed); } public void SetVibration(float in_value) { SetState(new Vibration(in_value)); } public void SetVibration(int in_motorIndex, float in_value) { switch (in_motorIndex) { case 0: { SetState(new Vibration(in_value, _rightMotorSpeed)); break; } case 1: { SetState(new Vibration(_leftMotorSpeed, in_value)); break; } } } } Library "Bitwise" by "Hyper" { public long Set(long in_base, int in_offset, bool in_isOffsetBitIndex = true) { return in_base | (in_isOffsetBitIndex ? (1L << in_offset) : in_offset); } public long Reset(long in_base, int in_offset, bool in_isOffsetBitIndex = true) { return in_base & (in_isOffsetBitIndex ? ~(1L << in_offset) : in_offset); } public bool Test(long in_base, int in_offset, bool in_isOffsetBitIndex = true) { return (in_base & (in_isOffsetBitIndex ? (1L << in_offset) : in_offset)) != 0; } } Library "Globals" by "Hyper" { using System.Collections.Generic; private Dictionary _globals = new(); public void Add(string in_name, object in_obj) { if (_globals.ContainsKey(in_name)) return; _globals.Add(in_name, in_obj); } public void Remove(string in_name) { _globals.Remove(in_name); } public object Get(string in_name) { if (!_globals.ContainsKey(in_name)) return null; return _globals[in_name]; } public T Get(string in_name, T in_defaultValue = default) { var result = Get(in_name); if (result == null) return in_defaultValue; return (T)result; } public bool GetFlag(string in_name) { return Get(in_name); } public void Set(string in_name, object in_obj) { if (!_globals.ContainsKey(in_name)) return; _globals[in_name] = in_obj; } } Library "Logger" by "Hyper" { #define PRINT_OBJECT(obj, format, caller) Logger.Utility(#obj + " = " + obj.ToString(format), caller); #define PRINT_OBJECT(obj, format) Logger.Utility(#obj + " = " + obj.ToString(format)); public enum LogLevel { None, Utility, Warning, Error } public void Log(object message, LogLevel level = LogLevel.None, string caller = "") { var oldColour = Console.ForegroundColor; switch (level) { case LogLevel.Warning: Console.ForegroundColor = ConsoleColor.Yellow; break; case LogLevel.Error: Console.ForegroundColor = ConsoleColor.Red; break; case LogLevel.Utility: Console.ForegroundColor = ConsoleColor.Green; break; } Console.WriteLine(string.IsNullOrEmpty(caller) ? message.ToString() : $"[{caller}] {message}"); Console.ForegroundColor = oldColour; } public void Utility(object message, string caller = "") { Log(message, LogLevel.Utility, caller); } public void Warning(object message, string caller = "") { Log(message, LogLevel.Warning, caller); } public void Error(object message, string caller = "") { Log(message, LogLevel.Error, caller); } } Library "VectorHelpers" by "Hyper" { #lib "MathHelpers" #load "System.Numerics.dll" using System.Numerics; public static float Angle(Quaternion in_first, Quaternion in_second) { var dot = MathHelpers.Clamp(Quaternion.Dot(in_first, in_second), -1.0f, 1.0f); return MathHelpers.ToDegrees((float)Math.Acos(2.0f * dot * dot - 1.0f)); } public static float SignedAngle(Vector3 in_first, Vector3 in_second, Vector3 in_axis) { var angle = (float)Math.Acos(MathHelpers.Clamp(Vector3.Dot(Vector3.Normalize(in_first), Vector3.Normalize(in_second)), -1.0f, 1.0f)); var cross = Vector3.Cross(in_first, in_second); var sign = Vector3.Dot(cross, in_axis) >= 0 ? 1.0f : -1.0f; return angle * sign; } public static Vector3 ClampMagnitude(Vector3 in_vector, float in_maxMagnitude) { if (in_vector.Length() > in_maxMagnitude * in_maxMagnitude) return Vector3.Normalize(in_vector) * in_maxMagnitude; return in_vector; } public static Vector3 GetRight(Quaternion in_rotation) { return Vector3.Transform(Vector3.UnitX, Quaternion.Normalize(in_rotation)); } public static Vector3 GetUp(Quaternion in_rotation) { return Vector3.Transform(Vector3.UnitY, Quaternion.Normalize(in_rotation)); } public static Vector3 GetForward(Quaternion in_rotation) { return Vector3.Transform(Vector3.UnitZ, Quaternion.Normalize(in_rotation)); } public static float GetMagnitude(Vector3 in_velocity) { return in_velocity.Length(); } public static float GetHorizontalMagnitude(Vector3 in_velocity) { return (float)Math.Sqrt(in_velocity.X * in_velocity.X + in_velocity.Z * in_velocity.Z); } public static float GetPitch(Quaternion in_rotation, bool in_isConvertToDegrees = false) { var result = (float)Math.Atan2(2.0f * (in_rotation.W * in_rotation.Y + in_rotation.Z * in_rotation.X), 1.0f - 2.0f * (in_rotation.Y * in_rotation.Y + in_rotation.Z * in_rotation.Z)); return in_isConvertToDegrees ? MathHelpers.ToDegrees(result) : result; } public static float GetRoll(Quaternion in_rotation, bool in_isConvertToDegrees = false) { var result = (float)Math.Asin(2.0f * (in_rotation.W * in_rotation.Z - in_rotation.X * in_rotation.Y)); return in_isConvertToDegrees ? MathHelpers.ToDegrees(result) : result; } public static float GetVerticalMagnitude(Vector3 in_velocity) { return in_velocity.Y; } public static float GetYaw(Quaternion in_rotation, bool in_isConvertToDegrees = false) { var result = (float)Math.Atan2(2.0 * (in_rotation.Y * in_rotation.Z + in_rotation.W * in_rotation.X), in_rotation.W * in_rotation.W - in_rotation.X * in_rotation.X - in_rotation.Y * in_rotation.Y + in_rotation.Z * in_rotation.Z); return in_isConvertToDegrees ? MathHelpers.ToDegrees(result) : result; } public static Vector3 GetYawPitchRoll(Quaternion in_rotation, bool in_isConvertToDegrees = false) { return new Vector3 ( GetYaw(in_rotation, in_isConvertToDegrees), GetPitch(in_rotation, in_isConvertToDegrees), GetRoll(in_rotation, in_isConvertToDegrees) ); } public static Vector3 Lerp(Vector3 in_start, Vector3 in_end, float in_time) { in_time = MathHelpers.Clamp(in_time, 0.0f, 1.0f); return new Vector3 ( in_start.X + (in_end.X - in_start.X) * in_time, in_start.Y + (in_end.Y - in_start.Y) * in_time, in_start.Z + (in_end.Z - in_start.Z) * in_time ); } public static Quaternion LookRotation(Vector3 in_forward, Vector3 in_upward) { in_forward = Vector3.Normalize(in_forward); in_upward = Vector3.Normalize(in_upward); var right = Vector3.Cross(in_upward, in_forward); in_upward = Vector3.Cross(in_forward, right); var m = new Matrix4x4 ( right.X, right.Y, right.Z, 0.0f, in_upward.X, in_upward.Y, in_upward.Z, 0.0f, in_forward.X, in_forward.Y, in_forward.Z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); return Quaternion.CreateFromRotationMatrix(m); } public static Quaternion RotateTowards(Quaternion in_from, Quaternion in_to, float in_maxRadiansDelta) { float angle = Angle(in_from, in_to); if (angle <= in_maxRadiansDelta || angle == 0.0f) return in_to; return Quaternion.Slerp(in_from, in_to, in_maxRadiansDelta / angle); } public static Quaternion LookRotation(Vector3 in_forward) { return LookRotation(in_forward, Vector3.UnitY); } public static Vector3 ProjectOnPlane(Vector3 in_vector, Vector3 in_normal) { in_normal = Vector3.Normalize(in_normal); return in_vector - Vector3.Dot(in_vector, in_normal) * in_normal; } } Library "Helpers" by "Hyper & Sajid" { #lib "StringMapOperation" using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; /// /// Creates an `__stdcall` delegate with an unmanaged function pointer based on the provided function signature. /// /// /// /// /// The return type of the unmanaged function. /// The name of the unmanaged function. /// The arguments of the unmanaged function. #define UNMANAGED_FUNCTION(in_returnType, in_functionName, ...) \ [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] \ public delegate in_returnType T##in_functionName(__VA_ARGS__); \ public static T##in_functionName _del##in_functionName = new T##in_functionName(in_functionName); \ public static long _fp##in_functionName = (long)System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_del##in_functionName); \ public static in_returnType in_functionName(__VA_ARGS__) /// /// Creates an `__stdcall` delegate based on the provided function signature. /// /// /// /// /// The return type of the unmanaged function. /// The name of the unmanaged function. /// The arguments of the unmanaged function. #define UNMANAGED_FUNCTION_DELEGATE(in_returnType, in_functionName, ...) \ [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] \ public delegate in_returnType in_functionName(__VA_ARGS__); /// /// Gets a pointer created by `UNMANAGED_FUNCTION` by name. /// /// The name of the unmanaged function. /// A pointer to the unmanaged function. #define GET_UNMANAGED_FUNCTION_PTR(in_functionName) _fp##in_functionName /// /// Creates a delegate using the signature created by `UNMANAGED_FUNCTION_DELEGATE`. /// /// The name of the unmanaged function. /// The location of the function. /// A delegate for the unmanaged function. #define CREATE_UNMANAGED_FUNCTION_PTR(in_functionName, in_location) System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer((IntPtr)(in_location)) /// /// Creates a function pointer to native code at the specified location. /// /// /// /// /// The return type of the unmanaged function. /// The name of the unmanaged function. /// The location of the function. /// The arguments of the unmanaged function. #define FUNCTION_PTR(in_returnType, in_functionName, in_location, ...) \ [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] \ public delegate in_returnType T##in_functionName(__VA_ARGS__); \ public static long _addr##in_functionName = in_location; /// /// Creates a function pointer to a virtual function at an instance of a struct. /// /// /// GetNameHash()(); /// } /// ]]> /// /// The struct type this is nested inside. /// The index of this function in the virtual function table. /// The return type of the unmanaged function. /// The name of the unmanaged function. /// The location of the function. /// The arguments of the unmanaged function. #define VFUNCTION_PTR(in_thisType, in_functionIndex, in_returnType, in_functionName, ...) \ [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] \ public delegate in_returnType T##in_functionName(__VA_ARGS__); \ public T##in_functionName in_functionName() \ { \ fixed (in_thisType* pThis = &this) \ return System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer((IntPtr)(*(long*)((*(long*)pThis) + (1 * sizeof(nint)) * in_functionIndex))); \ } /// /// Gets a pointer created by `FUNCTION_PTR` by name. /// /// The name of the function pointer. /// A delegate to the native function. #define GET_FUNCTION_PTR(in_functionName) System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer((IntPtr)_addr##in_functionName) /// /// Creates a fixed byte array with a special accessor for the real type. /// /// The real type of this array. /// The name of this array. /// The size of this array. #define UNMANAGED_FIXED_ARRAY(in_type, in_name, in_size) \ public fixed byte _##in_name[in_size]; \ public in_type* in_name \ { \ get \ { \ fixed (byte* p_##in_name = _##in_name) \ return (in_type*)p_##in_name; \ } \ } #define MAKE_GENERIC_API(in_functionName) \ public T* in_functionName() where T : unmanaged \ { \ var name = Helpers.GetInternalName(typeof(T)); \ \ return (T*)in_functionName(string.IsNullOrEmpty(name) ? typeof(T).Name : name); \ } \ #define MAKE_STATIC_GENERIC_API(in_functionName) \ public static T* in_functionName() where T : unmanaged \ { \ var name = Helpers.GetInternalName(typeof(T)); \ \ return (T*)in_functionName(string.IsNullOrEmpty(name) ? typeof(T).Name : name); \ } \ /// /// Gets a pointer to an ANSI string. /// /// The ANSI string to get a pointer to. /// A pointer to the input ANSI string. #define TO_STRING_PTR(in_str) (long)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi((##in_str##)) /// /// Gets a pointer to a Unicode string. /// /// The Unicode string to get a pointer to. /// A pointer to the input Unicode string. #define TO_WSTRING_PTR(in_str) (long)System.Runtime.InteropServices.Marshal.StringToHGlobalUni((##in_str##)) /// /// Gets a pointer to a UTF-8 string. /// /// The UTF-8 string to get a pointer to. /// A pointer to the input UTF-8 string. #define TO_U8STRING_PTR(in_str) (long)Helpers.StringToCoTaskMemUTF8((##in_str##)) /// /// Gets an ANSI string from a pointer. /// /// The pointer to read an ANSI string from. /// An ANSI string. #define FROM_STRING_PTR(in_ptr) System.Runtime.InteropServices.Marshal.PtrToStringAnsi((nint)(in_ptr)) /// /// Gets a Unicode string from a pointer. /// /// The pointer to read a Unicode string from. /// A Unicode string. #define FROM_WSTRING_PTR(in_ptr) System.Runtime.InteropServices.Marshal.PtrToStringUni((nint)(in_ptr)) /// /// Gets a UTF-8 string from a pointer. /// /// The pointer to read a UTF-8 string from. /// A UTF-8 string. #define FROM_U8STRING_PTR(in_ptr) Helpers.PtrToStringUTF8((nint)(in_ptr)) /// /// Exposes a base field on the super class as a property /// /// The field type. /// The field name. #define DEFINE_BASE_PROPERTY(TYPE, NAME) public TYPE NAME { get => Base.NAME; set => Base.NAME = value; } #define DEFINE_INTERFACE_PROPERTY(INTERFACE, TYPE, NAME) TYPE INTERFACE.NAME { get => NAME; set => NAME = value; } /// /// A struct representation of a `const char*`. /// [StructLayout(LayoutKind.Explicit, Size = 8)] public struct UnmanagedString { [FieldOffset(0)] public long pValue; public string Value { get { if (pValue == 0) return string.Empty; return FROM_STRING_PTR(pValue); } set => pValue = TO_STRING_PTR(value); } public UnmanagedString(string in_value) { Value = in_value; } public static implicit operator UnmanagedString(string in_value) { return new UnmanagedString(in_value); } public static bool operator ==(UnmanagedString in_left, string in_right) { return in_left.Value == in_right; } public static bool operator !=(UnmanagedString in_left, string in_right) { return !(in_left == in_right); } public override bool Equals(object in_obj) { if (in_obj is string str) return Value == str; return base.Equals(in_obj); } public override int GetHashCode() { return (int)StringMapOperation.ComputeHash(Value); } public override string ToString() { return Value; } } [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] public sealed class InternalNameAttribute : Attribute { public string InternalName { get; } public InternalNameAttribute(string in_internalName) { InternalName = in_internalName; } } /// /// Gets a list of indices where the input substring is found in a given string. /// /// /// /// /// The string to find substrings in. /// The substring to search for. /// A list of indices where a substring appears in the given string. public List GetSubstringIndices(string in_str, string in_substr) { var indices = new List(); int i = 0; while ((i = in_str.IndexOf(in_substr, i)) != -1) { indices.Add(i); i += in_substr.Length; } return indices; } /// /// Gets a name from a InternalNameAttribute attached to a type. /// /// The type to get the attribute from. /// A string representing the internal name of the input type. public static string GetInternalName(Type in_type) { var attr = (InternalNameAttribute)Attribute.GetCustomAttribute(in_type, typeof(InternalNameAttribute)); return attr == null ? string.Empty : attr.InternalName; } // https://github.com/scripthookvdotnet/scripthookvdotnet/blob/main/source/core/StringMarshal.cs /* Copyright (C) 2015 crosire, kagikn This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Changes; - 29/08/2023 - (Hyper) renamed buffer - (Hyper) renamed functions to use uppercase "UTF8" - (Hyper) removed braces to compact code - (Hyper) removed unsafe clauses (HMM always uses unsafe code) - (Hyper) removed static modifiers - 20/09/2023 - (Hyper) changed argument naming conventions - (Hyper) changed IntPtr to nint - (Hyper) changed string null check in StringToCoTaskMemUTF8 to use string.IsNullOrEmpty */ ///////////////////////////////////////////////////////////////////////////////////////////////////////// private static byte[] _bufferStringToCoTaskMemUTF8 = new byte[100]; /// /// Gets a UTF-8 string from a memory location. /// /// The memory location where the UTF-8 string is. /// A UTF-8 string. public string PtrToStringUTF8(nint in_ptr) { if (in_ptr == 0) return string.Empty; byte* data = (byte*)in_ptr; int len = 0; while (data[len] != 0) ++len; return PtrToStringUTF8(in_ptr, len); } /// /// Gets a fixed-length UTF-8 string from a memory location. /// /// The memory location where the UTF-8 string is. /// The length of the UTF-8 string in memory. /// A UTF-8 string. public string PtrToStringUTF8(nint in_ptr, int in_length) { if (in_length < 0) throw new ArgumentException(null, nameof(in_length)); if (in_ptr == 0) return null; if (in_length == 0) return string.Empty; return Encoding.UTF8.GetString((byte*)in_ptr, in_length); } /// /// Creates a pointer to a UTF-8 string. /// /// The UTF-8 string to get a pointer for. /// A pointer to the input UTF-8 string. public nint StringToCoTaskMemUTF8(string in_str) { if (string.IsNullOrEmpty(in_str)) return 0; int byteCountUtf8 = Encoding.UTF8.GetByteCount(in_str); if (byteCountUtf8 > _bufferStringToCoTaskMemUTF8.Length) _bufferStringToCoTaskMemUTF8 = new byte[byteCountUtf8 * 2]; Encoding.UTF8.GetBytes(in_str, 0, in_str.Length, _bufferStringToCoTaskMemUTF8, 0); nint dest = Marshal.AllocCoTaskMem(byteCountUtf8 + 1); if (dest == 0) throw new OutOfMemoryException(); Marshal.Copy(_bufferStringToCoTaskMemUTF8, 0, dest, byteCountUtf8); ((byte*)dest)[byteCountUtf8] = 0; return dest; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// } Patch "Show Frame Rate on Title Bar" in "System" by "Hyper & Sajid" // #lib "DeltaTime" #lib "Win32" using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; using System.Threading; [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern bool SetWindowText(IntPtr hWnd, String lpString); static bool _isOriginalTitleCaptured = false; static string _originalTitle; // { new Thread ( delegate() { while (true) { var windowHandle = Win32.GetGameWindowHandle(); if (windowHandle == IntPtr.Zero) continue; if (!_isOriginalTitleCaptured) { if (string.IsNullOrEmpty(_originalTitle)) { var title = new StringBuilder(GetWindowTextLength(windowHandle) + 1); GetWindowText(windowHandle, title, title.Capacity); _originalTitle = title.ToString(); } else { _isOriginalTitleCaptured = true; } } else { SetWindowText(windowHandle, $"{_originalTitle} - {DeltaTime.GetFrameRateAverage()} FPS ({DeltaTime.GetDeltaTimeAverage()} ms)"); } Thread.Sleep((int)DeltaTime.GetDeltaTimeMilliseconds()); } } ) .Start(); } Code "Always Hide Mouse Cursor" in "System" by "Hyper" does /* Keeps the mouse cursor hidden at all times when the game window is focused. This prevents the mouse cursor appearing under certain conditions, even if the primary input method is a controller. */ // #lib "Win32" [System.Runtime.InteropServices.DllImport("user32.dll")] static extern nint SetCursor(nint hCursor); // { if (!Win32.IsGameForegroundWindow()) return; SetCursor(0); } Patch "Restore Unused Supreme QTE" in "Enemy" by "Gordon Ramsay" does /* Restores an unused quick time event for the final blow to Supreme. This replaces the basic X button QTE to dodge the rifle projectile in the final game. */ { WriteProtected ( /* 0x14125C830 */ ScanSignature ( "zev_rfl_shoot02", "xxxxxxxxxxxxxxx" ), System.Text.Encoding.UTF8.GetBytes("zev_rfl_shoot01") ); } Patch "Disable Soldier Eggs" in "Enemy" by "Hyper" does "Disables the egg spawners for the Soldier enemy, allowing them to spawn instantly." { WriteNop ( /* 0x14057714D */ ScanSignature ( "\x75\x07\x40\x88\xB5\x60\x04\x00\x00", "xxxxxxxxx" ), 2 ); } Patch "Always Respawn Enemies" in "Enemy" by "Hyper" does "Always respawns enemies and guardians when loading back into islands." // #lib "Memory" // { Memory.WriteForceJump ( /* v1.42: 0x149410FC4 */ ScanSignature ( "\x0F\x88\x60\x01\x00\x00", "xxxxxx" ) ); } Patch "Disable Ring Magnetism" in "Gameplay" by "Hyper" does "Disables rings spinning around and magnetising to the player upon collecting them." { WriteNop ( /* v1.41: 0x140478FD0 */ ScanSignature ( "\x48\x85\xC0\x74\x42\xBA\x05\x00\x00\x00", "xxxxxxxxxx" ), 23 ); } Code "Disable Super Sonic Damage Wait" in "Gameplay" by "Hyper" does /* Disables Super Sonic remaining uncontrollable for a short period after taking heavy damage from the titans. Notes; - This does not affect Wyvern, as the knock back damage doesn't cause any major inconvenience there, and disabling it only makes the camera look bad. */ // #lib "Player" #import "Postures" #import "Services" // { if (LevelInfo.GetCurrentStageID().StartsWith("w2")) return; var pPostureDamageBlowOffHeavy = Player.Posture.GetPosture(); if (pPostureDamageBlowOffHeavy == null) return; if (pPostureDamageBlowOffHeavy->Phase == PostureDamageBlowOffHeavy.PhaseType.Damage) pPostureDamageBlowOffHeavy->Phase = PostureDamageBlowOffHeavy.PhaseType.Release; } Code "Disable Lava Instant Death" in "Gameplay" by "Hyper" does "Disables Sonic instantly drowning in lava and makes him jump up from the heat until running out of rings." // #include "BlackboardStatus" noemit #lib "BlackboardItem" #lib "Memory" #lib "Player" static bool _isInitialised = false; static bool _isDamageAnimQueued = false; static bool _isLandAnimQueued = false; static int _ringCount = 0; // { if (!_isInitialised) { fixed (int* p_ringCount = &_ringCount) fixed (bool* p_isDamageAnimQueued = &_isDamageAnimQueued) { /* 0x14099D457 */ long sig = ScanSignature ( "\xF6\x43\x54\x40\x0F\x84\xD0\x00\x00\x00", "xxxxxxxxxx" ); WriteAsmHook ( $@" mov rcx, {(long)p_ringCount} cmp dword ptr [rcx], 0 jnz exit mov rdx, {Memory.ReadJump(sig + 0x04)} jmp rdx exit: mov rcx, {(long)p_isDamageAnimQueued} mov byte ptr [rcx], 1 lea edx, dword ptr [rax - 0x03] mov r8d, 0x400000 ", sig, HookBehavior.Replace ); } _isInitialised = true; } var pBlackboardItem = BlackboardItem.Get(); if (pBlackboardItem == null) return; _ringCount = pBlackboardItem->RingCount; // Don't apply animation fixes to Sonic. if (Player.GetPlayerType() == Player.PlayerType.Sonic) { _isDamageAnimQueued = false; _isLandAnimQueued = false; return; } if (_isDamageAnimQueued) { Player.Animation.SetAnimation("BUMP_JUMP_START"); _isDamageAnimQueued = false; _isLandAnimQueued = true; } if (_isLandAnimQueued && Player.Status.IsGrounded()) { if (IS_STATE_FLAG(IsIdle)) Player.Animation.SetAnimation("LANDING"); _isLandAnimQueued = false; } } Code "Rebind Quick Restart to Back" in "Gameplay" by "Hyper" does "Rebinds the quick restart command from LT + RT + Back to just pressing the Back button." // #lib "Memory" #lib "PhotoMode" static bool _isInitialised = false; static long _sigGameModeBattleRushInputHandler = 0; static long _sigGameModeCyberStageInputHandler = 0; static long _sigGameModeCyberStageChallengeInputHandler = 0; // { if (!_isInitialised) { /* 0x1401A8EDB */ _sigGameModeBattleRushInputHandler = ScanSignature ( "\xF6\x40\x17\x01\x74\x26\xF6\x40\x1F\x01\x74\x20\xF6\x40\x0F\x01\x74\x1A\xBA\x0E\x00\x00\x00\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x32\xC0", "xxxxxxxxxxxxxxxxxxxxxxxxxxx????xx" ); /* 0x1401B8CF4 */ _sigGameModeCyberStageInputHandler = ScanSignature ( "\xF6\x40\x17\x01\x74\x26\xF6\x40\x1F\x01\x74\x20\xF6\x40\x0F\x01\x74\x1A\xBA\x0E\x00\x00\x00\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\xB0\x01", "xxxxxxxxxxxxxxxxxxxxxxxxxxx????xx" ); /* 0x1401BDBC0 */ _sigGameModeCyberStageChallengeInputHandler = ScanSignature ( "\xF6\x40\x17\x01\x74\x21", "xxxxxx" ); Memory.Preserve(_sigGameModeBattleRushInputHandler, 4); Memory.Preserve(_sigGameModeCyberStageInputHandler, 4); Memory.Preserve(_sigGameModeCyberStageChallengeInputHandler, 4); _isInitialised = true; } if (PhotoMode.IsEnabled()) { Memory.Restore(_sigGameModeBattleRushInputHandler); Memory.Restore(_sigGameModeCyberStageInputHandler); Memory.Restore(_sigGameModeCyberStageChallengeInputHandler); } else { WriteProtected(_sigGameModeBattleRushInputHandler, 0xEB, 0x0A); WriteProtected(_sigGameModeCyberStageInputHandler, 0xEB, 0x0A); WriteProtected(_sigGameModeCyberStageChallengeInputHandler, 0xEB, 0x0A); } } Patch "Disable Bullet Time" in "Gameplay" by "Hyper" does /* Disables the slow-mo sequences when performing certain actions. Notes; - This only applies to sequences that apply the bullet time filter, other actions like QTEs will remain unchanged. */ { // Disable bullet time for bosses and parry. WriteProtected ( /* 0x1402193E0 */ ScanSignature ( "\x40\x53\x48\x83\xEC\x50\x0F\x29\x74\x24\x40\x48\x8B\xD9\x0F\x29\x7C\x24\x30\x0F\x28\xF1", "xxxxxxxxxxxxxxxxxxxxxx" ) + 0x06, 0xEB, 0x40 ); // Disable bullet time audio for parry. WriteProtected ( /* 0x140990BE8 */ ScanSignature ( "\x75\x53\x41\x8B\x0E\x89\x4C\x24\x20", "xxxxxxxxx" ), 0xE9, 0x1F, 0x01, 0x00, 0x00 ); // Disable bullet time for Giganto dash rings. WriteProtected ( /* 0x1402C918F */ ScanSignature ( "\x48\x8D\x4D\x97\x0F\x28\xF9", "xxxxxxx" ), 0xE9, 0xAC, 0x00, 0x00, 0x00 ); // Disable bullet time for Ninja. WriteProtected ( /* 0x1405A7E7B */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8D\x4E\x3C\xE8\xCC\xCC\xCC\xCC\x84\xC0\x75\x37", "x????xxxxx????xxxx" ), 0xEB, 0x77 ); } Patch "Disable Hit Stop" in "Gameplay" by "Hyper" does "Disables the slow motion effect after performing attacks." { WriteAsmHook ( $@" xorps xmm3, xmm3 movaps xmm7, xmm3 mov r8, [rcx + 0xB0] mov esi, edx add rax, r8 ", /* 0x147689E7F */ ScanSignature ( "\x0F\x28\xFB\x4C\x8B\x81\xB0\x00\x00\x00", "xxxxxxxxxx" ), HookBehavior.Replace ); } Code "Fix Player Deceleration" in "Fixes" by "chico88959 & Hyper" does /* Fixes the player not decelerating correctly when the deceleration rate is set to anything below 100% in the game settings. Affected characters; - Amy - Knuckles - Tails */ // #include "Reflection" noemit #lib "Reflection" #lib "AmyParameters" #lib "KnucklesParameters" #lib "TailsParameters" // { var AmyParametersInfo = Reflection.GetDataInfo("amy_common"); if (AmyParametersInfo.pData != null) { RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.speed.deceleNeutralMin.force, 500.0f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.speed.deceleNeutralMin.jerkMin, 20.0f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.speed.deceleNeutralMax.force, 2000.0f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.speed.deceleNeutralMax.jerkMin, 700.0f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.speed.deceleNeutralMax.jerkMax, 800.0f); } var KnucklesParametersInfo = Reflection.GetDataInfo("knuckles_common"); if (KnucklesParametersInfo.pData != null) { RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.speed.deceleNeutralMin.force, 500.0f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.speed.deceleNeutralMin.jerkMin, 20.0f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.speed.deceleNeutralMax.force, 2000.0f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.speed.deceleNeutralMax.jerkMin, 700.0f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.speed.deceleNeutralMax.jerkMax, 800.0f); } var TailsParametersInfo = Reflection.GetDataInfo("tails_common"); if (TailsParametersInfo.pData != null) { RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.speed.deceleNeutralMin.force, 500.0f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.speed.deceleNeutralMin.jerkMin, 20.0f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.speed.deceleNeutralMax.force, 2000.0f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.speed.deceleNeutralMax.jerkMin, 700.0f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.speed.deceleNeutralMax.jerkMax, 800.0f); } } Patch "Fix Photo Mode Camera Collision" in "Fixes" by "Hyper" does "Allows the camera in Photo Mode to slide against collision, rather than freezing in place." { WriteNop ( /* 0x1400A6D0F */ ScanSignature ( "\x73\x3B\x0F\x28\x64\x24\x40", "xxxxxxx" ), 2 ); } Patch "Show Missions in Arcade Mode" in "UI" by "Hyper" does "Shows the missions in the results screen when completing Cyber Space in Arcade Mode." { /* 0x14093798D */ long addr = ScanSignature ( "\x44\x38\xBB\x6C\x02\x00\x00", "xxxxxxx" ); if (addr == 0) return; WriteProtected(addr, Assemble("mov byte ptr [rbx + 0x26C], 0")); WriteProtected(addr + 7, 0xEB); } Patch "Disable Menu Restrictions" in "UI" by "Hyper" does /* Removes restrictions from accessing certain menu screens and options. Notes; - This grants you the full pause menu, including the Skills and Save Data menus, within reasonable areas (e.g. the tutorial). - This grants you permission to save and load anywhere, including during combat. - This will allow you to open the map screen during combat. - This will allow you to place map markers before having completed any challenges. - This will allow you to enter Photo Mode during inaccessible parts of the game where Photo Mode is usually accessible. */ // #lib "Memory" // { // Disable save/load deny. Memory.WriteForceJump ( /* v1.41: 0x14D0848F1 */ ScanSignature ( "\x74\x0E\x83\xFE\x01", "xxxxx" ) ); // Disable "SetHUDEnabled" callback function. Memory.WriteForceJump ( /* v1.41: 0x14BFC27A5 */ ScanSignature ( "\x0F\x84\xD6\x00\x00\x00\x44\x0F\xBE\xC0", "xxxxxxxxxx" ) ); // Disable map screen restriction during combat. WriteProtected ( /* 0x1409AE37D */ ScanSignature ( "\x0F\x94\x44\x24\x48\x89\x5C\x24\x44", "xxxxxxxxx" ), Assemble("mov byte ptr [rsp + 0x58 + 0xFFFFFFFFFFFFFFF0], 1") ); // Disable "Unlock Cyloop" tutorial to prevent softlock. WriteNop ( /* 0x1409F3376 */ ScanSignature ( "\x0F\x44\xD9\xBA\x7E\x23\x00\x00", "xxxxxxxx" ), 3 ); // Disable Photo Mode check. Memory.WriteForceJump ( /* 0x140AA17A2 */ ScanSignature ( "\x0F\x84\xED\x00\x00\x00\x48\x8B\x5F\x18\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x33\xD2", "xxxxxxxxxxx????xxxxxxx????xx" ) ); } Code "Show Another Story Stages in Arcade Mode" in "UI" by "Hyper & Weezley" does "Shows the extra Cyber Space stages from Another Story in Arcade Mode below 4-9." // #lib "GameManager" #lib "Lua" #import "Services" using System.Collections.Generic; static List _extraStages = new(); // { // Load extra sound resources. if (_extraStages.Contains(LevelInfo.GetCurrentStageID()) && Lua.Call("IsLoadingLevel") != 0) Lua.Call("LoadLevel", "extra_cyber_sound"); var pStageInfo = GameManager.GetService(); if (pStageInfo == null) return; foreach (var pStageData in pStageInfo->Stages) { if (pStageData.pData->CyberStageIndex == -1) continue; if ((pStageData.pData->AttributeFlags & (1L << (int)StageInfo.Attributes.Extra)) != 0) _extraStages.Add(pStageData.pData->Name.ToString()); pStageData.pData->AttributeFlags &= ~(1L << (int)StageInfo.Attributes.Extra); } } Patch "Disable Running Fall" in "Animation" by "Hyper" does "Disables the animation where Sonic continues running when falling off a platform, forcing him into the proper falling animation." { WriteNop ( /* v1.42: 0x14B66EA60 */ ScanSignature ( "\xF3\x0F\x10\x40\x30\xF3\x0F\x59\x05\xCC\xCC\xCC\xCC\x0F\x2F\xF0\x0F\x28\x74\x24\x40\x73\x16", "xxxxxxxxx????xxxxxxxxxx" ), 5 ); } Code "Bouncy Jump Ball" in "Animation" by "Hyper" does /* Uses bouncy jump ball animations when jumping and double jumping, similar to Sonic Forces. Notes; - Tails uses his normal jump ball animation, as he doesn't have a bouncy alternative. */ // #include "Helpers" noemit #lib "Memory" #lib "Player" static bool _isInitialised = false; static sbyte _playerType = 0; // { if (!_isInitialised) { /* 0x1409D4A30 */ long sigPlayAnimationEffectAddr = Memory.ReadCall ( /* 0x14095EC8E */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\x46\x38\x48\x8B\x88\x08\x01\x00\x00\x48\x85\xC9\x74\x0C\xBA\x8E\xB4\x47\x3B\xE8\xCC\xCC\xCC\xCC\xEB\x03\x48\x8B\xC5", "x????xxxxxxxxxxxxxxxxxxxxxx????xxxxx" ) ); /* 0x14095EC7C */ long sigSetAnimationCallerAddr = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x41\xB0\x01\x48\x8D\x15\xCC\xCC\xCC\xCC\x48\x8B\xCE\xE8\xCC\xCC\xCC\xCC\x48\x8B\x46\x38", "x????xxxxxx????xxxx????xxxx" ); /* 0x1408B9F20 */ long sigSetAnimationAddr = Memory.ReadCall(sigSetAnimationCallerAddr); fixed (sbyte* p_playerType = &_playerType) { // StateJump { WriteAsmHook ( $@" test dil, dil jz playUpdatePhase1Anim playUpdatePhase2Anim: mov r8b, 0xFE mov rdx, {TO_STRING_PTR("JUMP_BALL")} mov rcx, rax mov rax, {sigSetAnimationAddr} call rax mov r8b, 1 mov rdx, {TO_STRING_PTR("SPINJUMP")} mov rcx, rsi mov rax, {sigPlayAnimationEffectAddr} call rax jmp exit playUpdatePhase1Anim: mov rdx, {(long)p_playerType} cmp byte ptr [rdx], 1 jne playUpdatePhase2Anim mov r8b, 0xFE mov rdx, {TO_STRING_PTR("JUMP_START")} mov rcx, rax mov rax, {sigSetAnimationAddr} call rax exit: ", /* 0x14095EC6A */ ScanSignature ( "\x41\xB0\xFE\x48\x8B\xC8\x40\x84\xFF\x74\x59", "xxxxxxxxxxx" ), HookBehavior.Replace ); WriteNop(sigSetAnimationCallerAddr, 23); } // StateDoubleJump WriteAsmHook ( $@" mov rdx, {TO_STRING_PTR("SPINJUMP")} lea rdx, [rdx] mov rcx, rbx mov rax, {sigPlayAnimationEffectAddr} call rax ", /* 0x14B9FC903 */ ScanSignature ( "\x48\x8D\x15\xCC\xCC\xCC\xCC\x48\x89\xD9\xE8\xCC\xCC\xCC\xCC\x48\x8B\x43\x38", "xxx????xxxx????xxxx" ), HookBehavior.Replace ); } _isInitialised = true; } _playerType = (sbyte)Player.GetPlayerType(); } Code "Somersault Landing at High Velocity" in "Animation" by "Hyper" does /* Enters Sonic into a somersault state when landing from a moderate height at a high velocity whilst retaining your momentum. This state lasts a fraction of a second, but keep in mind that within that time, you will be unable to perform certain actions until the animation is complete. */ // #include "BlackboardStatus" noemit #lib "HMM" #lib "Player" #load "System.Numerics.dll" #import "States" using System.Numerics; using System.Collections.Generic; static bool _isInitialised = false; static bool _isRecoveryJumpCharging = false; static bool _isSpinDashAutoRunAllowed = false; static Vector3 _lastGroundedPosition; static List _exitStates = new() { Sonic.StateID.StateJump, Sonic.StateID.StateRecoveryJump, Sonic.StateID.StateFall, Sonic.StateID.StateBumpJump, Sonic.StateID.StateRecovery }; static float _heightFallen = 0.0f; // { if (!_isInitialised) { if (HMM.GetCodes().Contains("Gameplay/Skills/Allow Spin Dash During Auto Run")) _isSpinDashAutoRunAllowed = true; Sonic.StateID NotifyStateSpringJumpHeadLandDamageCollision(Sonic.StateID in_stateId, Sonic.StateID[] in_stateStackTrace) { bool isStateSpringJumpHeadLand = in_stateId == Sonic.StateID.StateSpringJumpHeadLand; if (isStateSpringJumpHeadLand) { Player.Collision.SetEntityCollision(false); } else if (Player.State.GetPreviousStateID() == Sonic.StateID.StateSpringJumpHeadLand) { Player.Collision.SetEntityCollision(true); } return in_stateId; } Player.State.AddStateNotifyAction(NotifyStateSpringJumpHeadLandDamageCollision); _isInitialised = true; } var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; var pStateRecoveryJump = Player.State.GetState(); if (pStateRecoveryJump != null) _isRecoveryJumpCharging = pStateRecoveryJump->IsDropDashCharge; if (Player.State.GetCurrentStateID() == Sonic.StateID.StateSpringJumpHeadLand) { if (Player.Input.IsPressed(Player.InputActionType.PlayerJump) || Player.Input.IsPressed(Player.InputActionType.PlayerAttack)) { Player.State.SetState(Sonic.StateID.StateRun); } if (Player.Input.IsPressed(Player.InputActionType.PlayerSonicboom)) { if (!_isSpinDashAutoRunAllowed && IS_WORLD_FLAG(IsAutoRun)) goto CheckGrounded; Player.State.SetState(Sonic.StateID.StateSpinBoost); } } CheckGrounded: if (Player.Status.IsGrounded()) { _lastGroundedPosition = kinematics->Position; if (!_exitStates.Contains(Player.State.GetPreviousStateID())) goto Reset; if (Player.Kinematics.GetHorizontalMagnitude() > 15.0f && _heightFallen >= 5.0f) { if (IS_STATE_FLAG(IsBoost)) { // Allow StateJump to continue running if we're boosting. if (Player.State.GetPreviousStateID() == Sonic.StateID.StateJump) goto Reset; } // Prevent somersault landing on walls. if (IS_STATE_FLAG(IsWallClimb)) goto Reset; // Allow StateRecoveryJump to enter StateDropDash. if (Player.State.GetPreviousStateID() == Sonic.StateID.StateRecoveryJump && _isRecoveryJumpCharging) goto Reset; Player.State.SetState(Sonic.StateID.StateSpringJumpHeadLand); } Reset: _heightFallen = 0.0f; } else { /* Reset position if the player has reached apex height and has begun falling again. */ if ((_lastGroundedPosition.Y - kinematics->Position.Y) < _heightFallen) { _lastGroundedPosition = kinematics->Position; } _heightFallen = _lastGroundedPosition.Y - kinematics->Position.Y; } } Library "Postures" by "Hyper" { #include "Helpers" noemit #lib "BlackboardStatus" #lib "Memory" #lib "Player" #lib "StringMapOperation" #import "Collections" #import "GOComponents" using System.Runtime.InteropServices; /// /// A struct representation of `app::game::PostureImpl`. /// [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PostureImpl { } /// /// A struct representation of `app::player::PostureListener`. /// [StructLayout(LayoutKind.Explicit)] public struct PostureListener { } /// /// A struct representation of `app::player::PlayerPosture`. /// [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct PlayerPosture { [FieldOffset(0)] public PostureImpl Base; VFUNCTION_PTR(PlayerPosture, 1, uint, GetNameHash) } /// /// A struct representation of `app::player::PlayerPostureContext`. /// [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerPostureContext { /// /// A pointer to an instance of `app::player::Player`. /// [FieldOffset(0x10)] public Player.Data* pPlayer; /// /// A pointer to an instance of `app::player::GOCPlayerKinematicParams`. /// [FieldOffset(0x18)] public GOCPlayerKinematicParams* pGOCPlayerKinematicParams; /// /// A pointer to an instance of `app::player::GOCPlayerBlackboard`. /// [FieldOffset(0x20)] public GOCPlayerBlackboard* pGOCPlayerBlackboard; /// /// A pointer to an instance of `app::player::BlackboardStatus`. /// [FieldOffset(0x28)] public BlackboardStatus.Data* pBlackboardStatus; /// /// A pointer to an instance of `app::player::PlayerSpeedParam`. /// [FieldOffset(0x30)] public PlayerSpeedParam* pPlayerSpeedParam; /// /// A pointer to an instance of `app::player::PlayerExtraParam`. /// [FieldOffset(0x38)] public PlayerExtraParam* pPlayerExtraParam; /// /// A pointer to an instance of `app::player::PlayerGrindSpeedParam`. /// [FieldOffset(0x40)] public PlayerGrindSpeedParam* pPlayerGrindSpeedParam; /// /// A struct representation of `app::player::PlayerSpeedParam`. /// [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct PlayerSpeedParam { } /// /// A struct representation of `app::player::PlayerExtraParam`. /// [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerExtraParam { } /// /// A struct representation of `app::player::PlayerGrindSpeedParam`. /// [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerGrindSpeedParam { } } /// /// A struct representation of `app::player::PostureMoveManager`. /// [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct PostureMoveManager { /// /// An array of pointers to `app::player::PostureListener` instances. /// [FieldOffset(0x10)] public ObjectMoveArray> PostureListeners; /// /// A pointer to an instance of `app::player::PlayerPosture`. /// [FieldOffset(0x50)] public PlayerPosture* pPlayerPosture; /// /// Gets an instance of `app::player::PlayerPosture` by name and type. /// /// /// /// public PlayerPosture* GetPlayerPosture(string in_postureName) { if (pPlayerPosture->GetNameHash()() == StringMapOperation.ComputeHash(in_postureName)) return pPlayerPosture; return null; } MAKE_GENERIC_API(GetPlayerPosture) } /// /// A struct representation of `app::player::PostureDamageBlowOffHeavy`. /// [StructLayout(LayoutKind.Explicit)] public struct PostureDamageBlowOffHeavy { /// /// The current phase of this posture. /// [FieldOffset(0x12C)] public PhaseType Phase; public enum PhaseType : byte { /// /// The player has taken damage. /// Damage, /// /// The player has recovered from the damage. /// Recover, /// /// The player is waiting to return to the arena. /// Wait, /// /// The player is returning to the arena. /// Release } } } Library "Resources" by "Hyper" { #include "Helpers" noemit #lib "Memory" using System.Collections.Generic; using System.Runtime.InteropServices; private static bool _isInitialised = false; private static string _currentResourceName = string.Empty; private static string _currentResourceType = string.Empty; public delegate string TResourceNotifyAction(string in_resourceName, string in_resourceType); private static List _resourceNotifyActions = new(); public delegate long TResourceDataAction(string in_resourceName, string in_resourceType, long in_pResource); private static List _resourceDataActions = new(); UNMANAGED_FUNCTION(long, GetResourceInfo, long in_pResourceName, long in_pResourceType) { _currentResourceName = FROM_STRING_PTR(in_pResourceName); _currentResourceType = FROM_STRING_PTR(in_pResourceType); foreach (TResourceNotifyAction action in _resourceNotifyActions) in_pResourceName = TO_STRING_PTR(action(_currentResourceName, _currentResourceType)); return in_pResourceName; } UNMANAGED_FUNCTION(long, GetResourceData, long in_pResource) { foreach (TResourceDataAction action in _resourceDataActions) in_pResource = action(_currentResourceName, _currentResourceType, in_pResource); return in_pResource; } /// /// A struct representation of resource data. /// [StructLayout(LayoutKind.Explicit)] public struct Data { /// /// A pointer to the data for this resource. /// [FieldOffset(0x60)] public long pData; /// /// The size of the data for this resource. /// [FieldOffset(0x68)] public long Size; } [LibraryInitializer] public void Init() { if (_isInitialised) return; /* 0x140D599A3 */ long sigLoadResourceCaller = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x85\xC0\x74\x22\x80\x78\x10\x00", "x????xxxxxxxxx" ); if (sigLoadResourceCaller == 0) return; WriteAsmHook ( $@" sub rsp, 0xD0 mov rdi, r8 mov rbx, rdx mov rsi, rcx mov rcx, rdx mov rdx, [rdi] mov rax, {GET_UNMANAGED_FUNCTION_PTR(GetResourceInfo)} call rax mov rdx, [rcx] mov rbx, rdx ", /* 0x140EE897B */ ScanSignature ( "\x48\x81\xEC\xD0\x00\x00\x00\x49\x8B\xF8\x48\x8B\xDA", "xxxxxxxxxxxxx" ), HookBehavior.Replace ); WriteAsmHook ( $@" mov rcx, rax mov rax, {GET_UNMANAGED_FUNCTION_PTR(GetResourceData)} call rax lea r11, qword ptr [rsp + 0xD8 + 0xFFFFFFFFFFFFFFF8] mov rbx, qword ptr [r11 + 0x10] mov rsi, qword ptr [r11 + 0x18] mov rsp, r11 ", /* 0x140EE8A56 */ Memory.ReadCall(sigLoadResourceCaller) + 0xE6, HookBehavior.Replace ); // Allow loading open zone asset archive. WriteNop ( /* 0x1401E88DC */ ScanSignature ( "\x0F\x84\x41\x01\x00\x00\x48\x8D\x15", "xxxxxxxxx" ), 6 ); // Allow loading Cyber Space asset archive. WriteNop ( /* 0x1401E88C7 */ ScanSignature ( "\x74\x0F\x48\x8D\x15\xCC\xCC\xCC\xCC\x48\x8B\xCF\xE8\xCC\xCC\xCC\xCC\x40\x38\x75\x68", "xxxxx????xxxx????xxxx" ), 2 ); _isInitialised = true; } /// /// Registers a function of the `TResourceNotifyAction` type into the event handler for when a resource is loaded. /// /// Use notify actions for redirecting resources. /// Redirected resources must already have their data present in memory loaded from their respective Packfiles. /// /// /// /// /// The delegate to add. public void AddResourceNotifyAction(TResourceNotifyAction in_action) { if (_resourceNotifyActions.Contains(in_action)) return; _resourceNotifyActions.Add(in_action); } /// /// Removes a function of the `TResourceNotifyAction` type. /// /// The delegate to remove. public void RemoveResourceNotifyAction(TResourceNotifyAction in_action) { if (!_resourceNotifyActions.Contains(in_action)) return; _resourceNotifyActions.Remove(in_action); } /// /// Registers a function of the `TResourceDataAction` type into the event handler for when a resource is loaded. /// /// Use data actions for reading and writing resource data. /// /// /// pData; /// /// return in_pResource; /// } /// /// Resources.AddResourceDataAction(GetSonicParametersPointer); /// } /// ]]> /// /// The delegate to add. public void AddResourceDataAction(TResourceDataAction in_action) { if (_resourceDataActions.Contains(in_action)) return; _resourceDataActions.Add(in_action); } /// /// Removes a function of the `TResourceDataAction` type. /// /// The delegate to remove. public void RemoveResourceDataAction(TResourceDataAction in_action) { if (!_resourceDataActions.Contains(in_action)) return; _resourceDataActions.Remove(in_action); } } Library "Blackboard" by "Hyper, ĐeäTh & Sajid" does "Provides access to `app::player::Blackboard` from Sonic Frontiers." { #include "Helpers" noemit #import "Collections" #import "GOComponents" #lib "Helpers" #lib "Memory" #lib "Player" #lib "StringMapOperation" using System.Runtime.InteropServices; /// /// A struct representation of `app::player::Blackboard`. /// [StructLayout(LayoutKind.Explicit, Size = 0x38)] public struct Data { /// /// An array of pointers to `app::player::BlackboardContent` instances. /// [FieldOffset(0x18)] public ObjectMoveArray> BlackboardContents; } /// /// A struct representation of `app::player::BlackboardContent`. /// [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct BlackboardContent { /// /// Gets the string hash pertaining to the name of this `app::player::BlackboardContent` type. /// /// /// (pBlackboard); /// /// // Prints the name hash to the console. /// Console.WriteLine(((uint)pBlackboardStatus->GetNameHash()()).ToString("X")); /// } /// ]]> /// /// The string hash pertaining to the name of this `app::player::BlackboardContent` type. VFUNCTION_PTR(BlackboardContent, 1, uint, GetNameHash) } /// /// Gets an instance of `app::player::BlackboardContent` obtained by the input `app::player::Blackboard` instance by name. /// /// /// /// /// An instance of `app::player::Blackboard`. /// The name of the instance of `app::player::BlackboardContent` to find. /// A pointer to an instance of `app::player::BlackboardContent`. public long GetBlackboardContent(Data* in_pBlackboard, string in_name) { if (in_pBlackboard == null) return 0; var blackboardContents = in_pBlackboard->BlackboardContents; for (int i = 0; i < blackboardContents.Length; i++) { var pBlackboardContent = blackboardContents[i].pData; if ((uint)pBlackboardContent->GetNameHash()() == StringMapOperation.ComputeHash(in_name)) return (long)pBlackboardContent; } return 0; } /// /// Gets an instance of `app::player::BlackboardContent` obtained by the input `app::player::Blackboard` instance. /// /// /// (pBlackboard); /// } /// ]]> /// /// An instance of `app::player::Blackboard`. /// A pointer to an instance of `app::player::BlackboardContent`. public T* GetBlackboardContent(Data* in_pBlackboard) where T : unmanaged { var name = Helpers.GetInternalName(typeof(T)); return (T*)GetBlackboardContent(in_pBlackboard, string.IsNullOrEmpty(name) ? typeof(T).Name : name); } /// /// Gets an instance of `app::player::Blackboard` obtained by the current player. /// /// /// /// /// A pointer to an instance of `app::player::Blackboard`. public Data* GetPlayerBlackboard() { var pPlayer = Player.GetPlayerData(); if (pPlayer == null) return null; var pGOCPlayerBlackboard = GameObject.GetGOC(&pPlayer->GameObject); if (pGOCPlayerBlackboard == null) return null; return pGOCPlayerBlackboard->pBlackboard; } /// /// Gets an instance of `app::player::BlackboardContent` obtained by the current player by name. /// /// /// /// /// The name of the instance of `app::player::BlackboardContent` to find. /// A pointer to an instance of `app::player::BlackboardContent`. public long GetPlayerBlackboardContent(string in_name) { var pBlackboard = GetPlayerBlackboard(); if (pBlackboard == null) return 0; return Blackboard.GetBlackboardContent(pBlackboard, in_name); } /// /// Gets an instance of `app::player::BlackboardContent` obtained by the current player. /// /// /// (); /// } /// ]]> /// /// A pointer to an instance of `app::player::BlackboardContent`. public T* GetPlayerBlackboardContent() where T : unmanaged { var name = Helpers.GetInternalName(typeof(T)); return (T*)GetPlayerBlackboardContent(string.IsNullOrEmpty(name) ? typeof(T).Name : name); } } Library "Tails" by "Hyper" { /// /// An enum containing all of Tails' state IDs. /// public enum StateID : int { Default = -1, StateAcceleCombo1 = 149, // StateAttackRoot StateAcceleCombo2 = 150, // StateAttackRoot StateAquaBallJump = 121, StateAquaBallStand = 120, StateAquaBallStomping = 122, StateAttackRoot = 134, StateAuraTrain = 191, StateAvoid = 140, StateAvoidLocal = 143, StateAvoidToTarget = 142, StateAvoidUpper = 141, StateAwakening = 27, StateBallMove = 172, StateBaseJump = 102, StateBatterBox = 203, StateBattleStart = 158, StateBoarding = 183, StateBossCounter = 159, StateBrake = 6, StateBrakeNeutral = 7, StateBreathe = 44, StateBumpJump = 16, StateCaught = 167, StateChargeAttack = 151, // StateAttackRoot StateClimbing = 100, StateClimbingEdge = 99, StateCloudJump = 192, StateHomingFinish = 136, // StateAttackRoot StateComboMove = 131, StateComboStep = 132, StateComboWarp = 133, StateCrasher = 153, // StateAttackRoot StateCrossSlash = 155, // StateAttackRoot StateDamage = 29, // StateDamageRoot StateDamageBlowOff = 31, // StateDamageRoot StateDamageBlowOffHeavy = 32, // StateDamageRoot StateDamageLava = 38, StateDamageQuake = 33, // StateDamageRoot StateDamageRoot = 28, StateDamageRunning = 34, // StateDamageRoot StateDamageTurnBack = 30, // StateDamageRoot StateDead = 39, StateDebuff = 180, StateDestination = 188, StateDiving = 79, // StateDivingRoot StateDivingDamage = 81, // StateDivingRoot StateDivingFall = 80, // StateDivingRoot StateDivingRoot = 78, StateDivingSpecial = 84, // StateDivingSpecialRoot StateDivingSpecialDamage = 87, // StateDivingSpecialRoot StateDivingSpecialDashRing = 85, // StateDivingSpecialRoot StateDivingSpecialFall = 86, // StateDivingSpecialRoot StateDivingSpecialPush = 88, // StateDivingSpecialRoot StateDivingSpecialRoot = 83, StateDivingSpring = 82, // StateDivingRoot StateDrift = 111, StateDriftDash = 112, StateDriftAir = 113, StateDropDash = 114, StateFall = 15, StateFallWithKodama = 198, StateFallWithCannonball = 201, StateFallFlip = 21, StateFallingDead = 40, StateFallSlope = 20, StateFan = 171, StateFixedGoal = 128, StateFloat = 108, StateFly = 103, StateFlyLocal = 106, StateFlyLocal2D = 107, StateFlyOnPath = 105, StateFlyTurn = 104, StateGoal = 126, StateGoal2 = 127, StateGrind = 47, // StateGrindRoot StateGrindDamage = 50, // StateGrindRoot StateGrindDamageAir = 51, // StateGrindRoot StateGrindJump = 48, // StateGrindRoot StateGrindDoubleJump = 49, // StateGrindRoot StateGrindRoot = 46, StateGrindStep = 52, StateGuard = 148, StateGuardedFlipBack = 35, // StateDamageRoot StateHangPole = 173, StateHangPoleJump = 174, StateHoldStand = 162, StateHomingAttack = 63, // StateAttackRoot StateHomingAttackRoot = 62, // StateAttackRoot StateHomingAttackInStorm = 64, // StateAttackRoot StateHomingFinished = 65, // StateAttackRoot StateHomingRepelled = 66, StateHomingShot = 156, // StateAttackRoot StateImpactGimmick = 185, StateJump = 8, StateJumpWithKodama = 197, StateJumpBoardLaunch = 170, StateBounceJump = 11, StateRecoveryJump = 12, StateSpringJump = 165, StateSpringJumpHeadLand = 166, StateKickBox = 176, StateLavaDead = 45, StateLeftStep = 72, StateLeftStepRun = 74, PlayerStateLevitation = 215, StateLightDash = 26, StateLoopKick = 152, // StateAttackRoot StateMoveInWarningArea = 189, StateMoveToBatterBox = 204, StateMoveToBossArea = 190, StateMoveToReflexesPanel = 206, StateNoisyGoal = 129, StateOperateConsole = 184, StateParalysis = 37, StateParriedFlipBack = 36, StateParry = 144, StateParryStand = 145, // StateParry StatePipeMove = 168, StatePipeOut = 169, StatePressDead = 43, StatePursuitKick = 135, // StateAttackRoot StatePushBox = 175, StateQuickCyloop = 137, // StateAttackRoot StateQuickStep = 68, // StateQuickStepRoot StateQuickStepCrash = 71, // StateQuickStepRoot StateQuickStepJump = 76, StateQuickStepDoubleJump = 77, StateQuickStepLeft = 69, // StateQuickStepRoot StateQuickStepRight = 70, // StateQuickStepRoot StateQuickStepRoot = 67, StateRecoil = 19, StateRecovery = 164, StateReflexesPanel = 205, StateReflexesPanelLeftStep = 207, StateReflexesPanelRightStep = 208, StateRightStep = 73, StateRightStepRun = 75, StateRun = 4, StateRunWithKodama = 196, StateRunWithCannonball = 199, StateRunawayBee = 194, StateRunningStart = 125, StateSandSki = 177, StateSandSkiBlow = 178, StateSendSignal = 186, StateSleep = 0, StateSliding = 60, // StateSquatRoot StateSlidingToStand = 61, StateSlingshot = 179, StateSmash = 138, // StateAttackRoot StateSmashSS = 139, // StateAttackRoot StateSonicBoomKick = 154, // StateAttackRoot StateSpin = 115, StateSpinAttack = 14, StateSpinBoost = 118, StateSpinBoostCharge = 117, StateSpinMove = 119, StateSpinDash = 116, // StateAttackRoot StateSpinSlash = 157, // StateAttackRoot StateSquat = 18, // StateSquatRoot StateSquatRoot = 17, StateStandRoot = 1, StateStandWithKodama = 195, StateStand = 2, // StateStandRoot StateStandWithCannonball = 200, StateStolenEmerald = 182, StateStorm = 181, StateSuffocatingDead = 42, StateTakeBehind = 146, StateTakeBehindSS = 147, StateTalkMode = 163, StateThrowCannonball = 202, StateTimeUpDead = 130, StateTreadmill = 193, StateTreeJump = 276, StateTurn = 5, StateUpDead = 41, StateUpDownPole = 123, StateUpDownPoleDamage = 124, StateWakeUp = 3, StateWarpEnd = 161, StateWarpStart = 160, StateWaterFall = 187, StateAirBoost = 22, StateAirBoostCyclone = 25, // StateCycloneBoostRoot StateTailsFly = 10, StateDoubleJump = 9, StateCyBlasterLift = 262, StateCyBlasterLiftUp = 263, // StateCyBlasterLift StateCyBlasterLiftStand = 264, // StateCyBlasterLift StateCyBlasterLiftRun = 265, // StateCyBlasterLift StateCyBlasterLiftJump = 266, // StateCyBlasterLift StateCyBlasterLiftFall = 267, // StateCyBlasterLift StateCyBlasterLiftRelease = 268, // StateCyBlasterLift TailsStateStomping = 53, // StateAttackRoot TailsStateStompingBounce = 59, // StateAttackRoot TailsStateStompingDown = 55, // StateAttackRoot TailsStateStompingLand = 58, // StateAttackRoot StateSpannerThrow = 269, StateCycloneAppear = 270, StateCycloneBoostRoot = 271, StateCycloneBoost = 272, // StateCycloneBoostRoot StateLeftStepCyclone = 273, StateRightStepCyclone = 274, StateWaveCannon = 275, } } Library "HandleManagerBase" by "Sajid" { #import "Collections" #import "GameTypes" using System.Runtime.InteropServices; using HandleBase = HandleManagerBase.Handle; [StructLayout(LayoutKind.Explicit, Size = 0x70)] public struct Data { [FieldOffset(0x18)] public ObjectMoveArray HandleTable; public RefByHandleObject* GetObject(int id) { if (!IsHandleValid(id)) return default; id &= 0xFFFF; return (RefByHandleObject*)HandleTable[(nint)id].Object; } public HandleBase GetHandle(int id) { if (!IsHandleValid(id)) return default; id &= 0xFFFF; return new HandleBase(ref HandleTable[(nint)id]); } public Handle GetHandle(int id) where T : unmanaged { if (!IsHandleValid(id)) return default; id &= 0xFFFF; return new Handle(ref HandleTable[(nint)id]); } public Handle GetHandle(in T obj) where T : unmanaged, IRefByHandleObject { if (!IsHandleValid(obj.Handle)) return default; var id = obj.Handle & 0xFFFF; return new Handle(ref HandleTable[(nint)id]); } public static bool IsHandleValid(int id) { unchecked { return (0xFFFF0000 & id) != 0; } } } public struct HandleTableEntry { public long Handle; public void* Object; } public struct Handle where T : unmanaged { public long Value; public HandleTableEntry* TableEntry; public Handle(ref HandleTableEntry entry) { Value = entry.Handle; fixed(HandleTableEntry* pEntry = &entry) { TableEntry = pEntry; } } public bool IsValid() { return TableEntry != null && (TableEntry->Handle == Value && TableEntry->Object != null); } public T* Get() { return IsValid() ? (T*)TableEntry->Object : null; } } } Library "Plugins" by "Hyper" { #include "Helpers" noemit #include "SaveData" noemit #lib "Helpers" #lib "Memory" #lib "Player" #lib "StringMapOperation" #import "Collections" using System.Runtime.InteropServices; /// /// A struct representation of `app::player::StatePluginBase`. /// [StructLayout(LayoutKind.Sequential, Size = 0x28)] public struct StatePluginBase { VFUNCTION_PTR(StatePluginBase, 1, uint, GetNameHash) } /// /// A struct representation of `app::player::StatePlugin`. /// [StructLayout(LayoutKind.Sequential, Size = 0x28)] public struct StatePlugin { public StatePluginBase Base; } /// /// A struct representation of `app::player::PlayerStatePlugin`. /// [StructLayout(LayoutKind.Sequential, Size = 0x28)] public struct PlayerStatePlugin { public StatePlugin Base; } /// /// A struct representation of `app::player::StatePluginManager`. /// [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct StatePluginManager { /// /// An array of pointers to `app::player::StatePluginBase` instances. /// [FieldOffset(0x18)] public ObjectMoveArray> Plugins; /// /// Gets an instance of `app::player::StatePluginBase` by name. /// /// The name of the state plugin. /// An instance of `app::player::StatePluginBase` requested by name. public StatePluginBase* GetStatePlugin(string in_pluginName) { foreach (var pPlugin in Plugins) { if (pPlugin.pData == null) continue; if (pPlugin.pData->GetNameHash()() == StringMapOperation.ComputeHash(in_pluginName)) return pPlugin.pData; } return null; } MAKE_GENERIC_API(GetStatePlugin) } /// /// A struct representation of `app::player::StatePluginAirTrick`. /// [StructLayout(LayoutKind.Explicit)] public struct StatePluginAirTrick { /// /// Determines whether air tricks are enabled. /// [FieldOffset(0x3D)] public bool IsEnabled; } /// /// A struct representation of `app::player::StatePluginBattle`. /// [StructLayout(LayoutKind.Explicit)] public struct StatePluginBattle { /// /// Bit flags for the state of this battle. /// [FieldOffset(0x7C)] public BattleFlags Flags; /// /// An enum containing known flags for `app::player::StatePluginBattle`. /// [Flags] public enum BattleFlags : short { /// /// The player has Phantom Rush. /// IsPhantomRush = 0x200 } } /// /// A struct representation of `app::player::StatePluginBoost`. /// [StructLayout(LayoutKind.Explicit)] public struct StatePluginBoost { /// /// The maximum amount of boost the player can hold. /// [FieldOffset(0x3C)] public float BoostCapacity; /// /// The current amount of boost for the player. /// [FieldOffset(0x40)] public float BoostAmount; /// /// The current time remaining for infinite boost. /// [FieldOffset(0x54)] public float InfiniteBoostTimer; /// /// Bit flags for the boost gauge. /// [FieldOffset(0xD0)] public BoostFlags Flags; /// /// Gets the boost gauge level from the current boost capacity. /// /// The current boost gauge level guessed from the boost capacity. public ushort GetBoostLevelFromCapacity() { return (ushort)((BoostCapacity - 100.0f) / 12.5f); } /// /// Gets the boost capacity from the current boost gauge level. /// /// The boost gauge level. /// The current boost capacity guessed from the boost gauge level. public float GetBoostCapacityFromLevel() { ushort? boostGaugeLevel = SAVE_GET_PARAM(character.boostGaugeLevel); if (boostGaugeLevel == null) return 100.0f; return 100.0f + (boostGaugeLevel.Value * 12.5f); } /// /// An enum containing known flags for `app::player::StatePluginBoost`. /// [Flags] public enum BoostFlags : uint { /// /// The gauge is currently recharging. /// IsGaugeRecharging = 1, /// /// The player is air boosting. /// IsAirBoost = 2, /// /// The gauge is empty and unusable by the player (in the red zone). /// IsGaugeEmpty = 8, /// /// The gauge is currently being displayed. /// IsGaugeVisible = 0x10, /// /// The player is Cylooping whilst boosting. /// IsCyloopBoost = 0x20, /// /// The player is boosting. /// IsBoosting = 0x20000 } } /// /// A struct representation of `app::player::StatePluginQuickStep`. /// [StructLayout(LayoutKind.Explicit)] public struct StatePluginQuickStep { /// /// The type of the current quick step spline. /// [FieldOffset(0x29)] public QuickStepLineType LineType; /// /// The index of the current quick step lane. /// [FieldOffset(0x2A)] public byte LineIndex; /// /// An enum representing the quick step line types. /// public enum QuickStepLineType : byte { Line2_Left, Line2_Right, Line3, Line5, Line1 } /// /// Gets whether the player is allowed to quick step in the specified direction. /// /// Determines if the player is quick stepping to the right. /// A boolean representing whether the player can quick step in the specified direction. public static bool IsQuickStepLegal(bool in_quickStepRight = false) { var pStatePluginQuickStep = Player.State.GetStatePlugin(); if (pStatePluginQuickStep == null) return false; if (in_quickStepRight) { switch (pStatePluginQuickStep->LineType) { case QuickStepLineType.Line2_Left: return pStatePluginQuickStep->LineIndex == 0; case QuickStepLineType.Line3: return pStatePluginQuickStep->LineIndex != 2; // TODO: verify this. case QuickStepLineType.Line5: return pStatePluginQuickStep->LineIndex != 3; default: return false; } } else { switch (pStatePluginQuickStep->LineType) { case QuickStepLineType.Line2_Right: return pStatePluginQuickStep->LineIndex == 2; case QuickStepLineType.Line3: case QuickStepLineType.Line5: // TODO: verify this. return pStatePluginQuickStep->LineIndex != 1; default: return false; } } } } } Library "PhotoMode" by "Hyper" { #include "Helpers" noemit #lib "GameManager" #lib "GameMode" #lib "GameObject" #lib "GameService" #lib "Logger" #lib "Lua" #lib "Memory" #lib "Player" #import "Cameras" #import "GOComponents" #import "Services" #import "Messages" #import "Services" #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; private static bool _isInitialised = false; private static bool _isNewLevel = false; private static bool _isPackfileLoaded = false; private static string _lastLevel = string.Empty; private static long _sigPhotoModeServiceStaticClassCtor = 0; /* 0x140208C80 */ private static long _sigInvokePhotoMode = ScanSignature("\x40\x55\x53\x56\x41\x54\x41\x56\x48\x8D\x6C\x24\xC9", "xxxxxxxxxxxxx"); FUNCTION_PTR(char, fpInvokePhotoMode, _sigInvokePhotoMode, void* in_pPhotoModeService, bool in_isEnabled) [LibraryInitializer] public void Init() { if (_isInitialised) return; if (_sigPhotoModeServiceStaticClassCtor == 0) { /* 0x140205929 */ _sigPhotoModeServiceStaticClassCtor = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x48\x85\xC0\x74\x0C\x44\x0F\xB6\xB0\x98\x00\x00\x00", "x????xxxxxxx????xxxxxxxxxxxxx" ); if (_sigPhotoModeServiceStaticClassCtor == 0) { Logger.Error("[Camera] Failed to register app::game::PhotoModeService!"); return; } /* 0x143DAD260 */ GameService.AddUserService(Memory.ReadEffectiveAddress(Memory.ReadCall(_sigPhotoModeServiceStaticClassCtor))); } _isInitialised = true; } [LibraryUpdate] public void Update() { var stageId = LevelInfo.GetCurrentStageID(); if (_lastLevel != stageId) { _lastLevel = stageId; _isNewLevel = true; _isPackfileLoaded = false; } if (Lua.GetState() != 0) { if (_isNewLevel) { Lua.Call("LoadLevel", "photomode_misc"); _isNewLevel = false; _isPackfileLoaded = true; } } else { _isPackfileLoaded = false; } } /// /// Determines whether Photo Mode is enabled. /// /// A boolean representing whether Photo Mode is enabled. public bool IsEnabled() { var pPhotoModeService = GameManager.GetService(); if (pPhotoModeService == null) return false; return pPhotoModeService->IsEnabled; } /// /// Sets whether Photo Mode is enabled. /// /// The enabled state of Photo Mode. public void SetEnabled(bool in_isEnabled) { if (!_isPackfileLoaded) return; var pPhotoModeService = GameManager.GetService(); if (pPhotoModeService == null) return; void SendMessage(bool in_isEnabled) { Messages.SendMessageToGameService ( &pPhotoModeService->GameService, new MsgUISetGameCockpitEnabled("PhotoMode", 0xFFFFFFFFFFFFFFFF, in_isEnabled) ); } SendMessage(!in_isEnabled); GET_FUNCTION_PTR(fpInvokePhotoMode)(pPhotoModeService, in_isEnabled); /* The reason this is being sent twice is because of the Red Ring display in Cyber Space. If we don't restore the "game cockpit" at least once, the Red Ring display will persist. This does also mean the Red Ring display will never return until completely exiting out of the stage, but that's a small price to pay for having no HUD at all. */ SendMessage(in_isEnabled); SendMessage(!in_isEnabled); } /// /// Toggles Photo Mode. /// public void Toggle() { SetEnabled(!IsEnabled()); } /// /// Gets an instance of `app::camera::PhotoModeCamera` from `app::game::ObjPhotoModeCamera`. /// /// A pointer to an instance of `app::camera::PhotoModeCamera`. public PhotoModeCamera* GetCamera() { var pObjPhotoModeCamera = GameManager.GetGameObject(); if (pObjPhotoModeCamera == null) return null; return pObjPhotoModeCamera->pPhotoModeCamera; } } Library "Lua" by "Hyper & ĐeäTh" { #include "Helpers" noemit #lib "GameManager" #lib "GameMode" #lib "GameService" #lib "Helpers" #lib "Logger" #lib "Memory" #lib "Resources" #lib "StringMapOperation" #import "Allocators" #import "Services" // Basic types #define LUA_TNONE (-1) #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8 #define LUA_NUMTYPES 9 // Thread status #define LUA_OK 0 #define LUA_YIELD 1 #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 #define LUA_ERRMEM 4 #define LUA_ERRERR 5 using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; private static bool _isInitialised = false; private static bool _isPrintPreviousError = true; private static long _sigScriptSequenceManagerStaticClassCtor = 0; private static List _deniedGameModes = new() { "GameModeBattleRush", "GameModeBossRush", "GameModeFishing", "GameModeHacking", "GameModeMasterTrial", "GameModeStage", "GameModeTitle", "GameModeUnknown" }; private static string _lastGameModeName = "GameModeUnknown"; private static List _userScriptHandles = new(); private static (string ScriptName, long pResourceData) _currentResLuaData = new(); private static Dictionary _scriptData = new(); public abstract class Hook { public string ScriptName { get; } public HookBehavior Behaviour { get; } public uint Hash { get; set; } public Hook(string in_scriptName, HookBehavior in_behaviour) { ScriptName = in_scriptName; Behaviour = in_behaviour; } public abstract string WriteHook(string code); public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) return false; return Hash == ((Hook)obj).Hash; } public override int GetHashCode() { return Hash.ToString("X").GetHashCode(); } } public class LineHook : Hook { public string Code { get; } public string Pattern { get; } public bool IsRegex { get; } = false; public RegexOptions RegexOptions { get; } public LineHook(string in_code, string in_scriptName, string in_pattern, HookBehavior in_behaviour, bool in_isRegex = false, RegexOptions in_regexOptions = default) : base(in_scriptName, in_behaviour) { Code = in_code; Pattern = in_pattern; IsRegex = in_isRegex; RegexOptions = in_regexOptions; Hash = StringMapOperation.ComputeHash(ToString()); } public override string WriteHook(string in_code) { string result = in_code; var regexOptions = RegexOptions.Compiled | RegexOptions; bool isLineFound = IsRegex ? Regex.Match(result, Pattern, regexOptions).Success : result.Contains(Pattern); if (!isLineFound) return result; var insertions = new List<(int Index, string Text)>(); void AddInsertion(int index, int length) { switch (Behaviour) { case HookBehavior.Before: insertions.Add((index, $"{Code}\n")); break; case HookBehavior.Replace: { result = IsRegex ? new Regex(Pattern, regexOptions).Replace(result, Code) : result.Replace(Pattern, Code); break; } case HookBehavior.After: insertions.Add((index + length, $"\n{Code}")); break; } } if (IsRegex) { foreach (Match match in Regex.Matches(result, Pattern, regexOptions)) AddInsertion(match.Index, match.Length); } else { foreach (int index in Helpers.GetSubstringIndices(result, Pattern)) AddInsertion(index, Pattern.Length); } foreach (var insertion in insertions.OrderByDescending(i => i.Index)) result = result.Insert(insertion.Index, insertion.Text); return result; } public override string ToString() { return $"[Lua] Line Hook - [{ScriptName}]::[\"{Pattern}\"] (Behaviour: {Behaviour}, Regex: {IsRegex});\n{Code}"; } } public class FunctionHook : Hook { public string Code { get; } public string FunctionName { get; } public FunctionHook(string in_code, string in_scriptName, string in_functionName, HookBehavior in_behaviour) : base(in_scriptName, in_behaviour) { Code = in_code; FunctionName = in_functionName; Hash = StringMapOperation.ComputeHash(ToString()); } public override string WriteHook(string in_code) { var result = new StringBuilder(); var nestedKeywords = new List() { "function", "if", "elseif", "for", "while", "repeat" }; string funcPattern = $@"(^function\s+{FunctionName}\s*\(.*?\))"; bool isInsideFunction = false; int scopeDepth = 0; foreach (string line in in_code.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None)) { if (line.Contains($"function {FunctionName}")) { if (line.Contains("end")) { Match inlineFuncSig = Regex.Match(line, funcPattern, RegexOptions.Compiled); if (!inlineFuncSig.Success) continue; string funcSig = inlineFuncSig.Groups[0].Value; int funcSigIndex = inlineFuncSig.Index + inlineFuncSig.Length; switch (Behaviour) { case HookBehavior.Before: result.Append($"{funcSig} {Code} "); result.Append(line.Substring(funcSigIndex, line.LastIndexOf("end") - funcSigIndex)); result.Append(" end"); break; case HookBehavior.Replace: result.Append($"{funcSig} {Code} end"); break; case HookBehavior.After: result.Append($"{funcSig} "); result.Append(line.Substring(funcSigIndex, line.LastIndexOf("end") - funcSigIndex)); result.Append($" {Code} end"); break; } isInsideFunction = false; scopeDepth = 0; continue; } // Write function signature. result.AppendLine(line); if (Behaviour == HookBehavior.Before) result.AppendLine(Code); isInsideFunction = true; scopeDepth++; continue; } else if (isInsideFunction) { if (line.Contains("end")) { scopeDepth--; if (scopeDepth == 0) { if (Behaviour != HookBehavior.Before) result.AppendLine(Code); result.AppendLine("end"); isInsideFunction = false; break; } } else if (nestedKeywords.Any(x => line.Trim().StartsWith(x))) { scopeDepth++; } if (Behaviour != HookBehavior.Replace) result.AppendLine(line); continue; } result.AppendLine(line); } return result.ToString(); } public override string ToString() { return $"[Lua] Function Hook - [{ScriptName}]::[{FunctionName}] (Behaviour: {Behaviour});\n{Code}"; } } private static List _hooks = new(); /* 0x153DC50F0 */ private static long _sig_luaL_loadbufferx = ScanSignature("\x48\x83\xEC\x48\x48\x8B\x44\x24\x70\x48", "xxxxxxxxxx"); FUNCTION_PTR(long, luaL_loadbufferx, _sig_luaL_loadbufferx, long L, long buff, long size, long name, long mode) /* 0x140F56850 */ private static long _sig_lua_getglobal = Memory.ReadCall(ScanSignature("\xE8\xCC\xCC\xCC\xCC\x48\x8B\x0F\x48\x8B\xD3\xE8", "x????xxxxxxx")); FUNCTION_PTR(long, lua_getglobal, _sig_lua_getglobal, long L, long name) /* 0x153D1EE30 */ private static long _sig_lua_pcallk = ScanSignature("\x48\x89\x74\x24\x18\x57\x48\x83\xEC\x40\x31\xF6", "xxxxxxxxxxxx"); FUNCTION_PTR(long, lua_pcallk, _sig_lua_pcallk, long L, int nargs, int nresults, int errfunc, long ctx, long k) /* 0x140F55DC0 */ private static long _sig_lua_pop = ScanSignature("\x40\x53\x48\x83\xEC\x20\x45\x8B\xD0", "xxxxxxxxx"); FUNCTION_PTR(long, lua_pop, _sig_lua_pop, long L, int idx) /* 0x140F56590 */ private static long _sig_lua_pushlstring = ScanSignature("\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x8B\xD9\x4D", "xxxxxxxxxxxxxx"); FUNCTION_PTR(long, lua_pushlstring, _sig_lua_pushlstring, long L, long s, long len) /* 0x140F56570 */ private static long _sig_lua_pushinteger = ScanSignature("\x48\x8B\x41\x10\x48\x89\x10\xC6\x40\x08\x03", "xxxxxxxxxxx"); FUNCTION_PTR(long, lua_pushinteger, _sig_lua_pushinteger, long L, int n) /* 0x153CF8870 */ private static long _sig_lua_pushnumber = ScanSignature("\x48\x8B\x41\x10\xC5\xFA", "xxxxxx"); FUNCTION_PTR(long, lua_pushnumber, _sig_lua_pushnumber, long L, float n) /* 0x140F567D0 */ private static long _sig_lua_pushboolean = ScanSignature("\x48\x8B\x41\x10\x85", "xxxxx"); FUNCTION_PTR(long, lua_pushboolean, _sig_lua_pushboolean, long L, int b) /* 0x153CE29A0 */ private static long _sig_lua_type = ScanSignature("\x48\x83\xEC\x28\xE8\xCC\xCC\xCC\xCC\x0F\xB6\x50\x08\xF6", "xxxxx????xxxxx"); FUNCTION_PTR(long, lua_type, _sig_lua_type, long L, int idx) /* 0x15391B810 */ private static long _sig_lua_tolstring = ScanSignature("\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x57\x48\x83\xEC\x20\x4C\x89\xC3\x89", "xxxxxxxxxxxxxxxxxxx"); FUNCTION_PTR(long, lua_tolstring, _sig_lua_tolstring, long L, int idx, long len) /* 0x153CEFC70 */ private static long _sig_lua_tointegerx = ScanSignature("\x40\x53\x48\x83\xEC\x20\x49\x8B\xD8\x48\xC7", "xxxxxxxxxxx"); FUNCTION_PTR(long, lua_tointegerx, _sig_lua_tointegerx, long L, int idx, long pisnum) /* 0x140F55F30 */ private static long _sig_lua_tonumberx = ScanSignature("\x48\x83\xEC\x28\xE8\xCC\xCC\xCC\xCC\x80\x78\x08\x13", "xxxxx????xxxx"); FUNCTION_PTR(long, lua_tonumberx, _sig_lua_tonumberx, long L, int idx, long pisnum) /* 0x153CE8FE0 */ private static long _sig_lua_toboolean = ScanSignature("\x48\x83\xEC\x28\xE8\xCC\xCC\xCC\xCC\x0F\xB6\x48\x08\x80\xF9\x01", "xxxxx????xxxxxxx"); FUNCTION_PTR(bool, lua_toboolean, _sig_lua_toboolean, long L, int idx) /* 0x14C25D880 */ private static long _sigInitScriptSequenceManager = ScanSignature("\x48\x89\x5C\x24\x10\x48\x89\x6C\x24\x18\x56\x57\x41\x54\x41\x56\x41\x57\x48\x81\xEC\x30\x01\x00\x00\x48\x89", "xxxxxxxxxxxxxxxxxxxxxxxxxxx"); FUNCTION_PTR(int*, InitScriptSequenceManager, _sigInitScriptSequenceManager, ScriptSequenceManager* in_pScriptSequenceManager, uint* in_pStringHash, char a3) /* 0x14C245AC0 */ private static long _sigRegisterScriptSequenceManager = ScanSignature("\x40\x56\x48\x81\xEC\xC0\x00\x00\x00\x48\x89\xCE\x45", "xxxxxxxxxxxxx"); FUNCTION_PTR(long, RegisterScriptSequenceManager, _sigRegisterScriptSequenceManager, ScriptSequenceManager* in_pScriptSequenceManager) [LibraryInitializer] public void Init() { if (_isInitialised) return; if (_sigScriptSequenceManagerStaticClassCtor == 0) { /* 0x140178E1E */ _sigScriptSequenceManagerStaticClassCtor = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCF\xE8\xCC\xCC\xCC\xCC\x0F\xB7\x97\x58\x01\x00\x00", "x????xxxxxxx????xxxxxxx" ); if (_sigScriptSequenceManagerStaticClassCtor == 0) { Logger.Error("[Lua] Failed to register app::ScriptSequence!"); return; } /* 0x143DBE440 */ GameService.AddUserService(Memory.ReadEffectiveAddress(Memory.ReadCall(_sigScriptSequenceManagerStaticClassCtor))); } long HookService(string in_resourceName, string in_resourceType, long in_pResource) { if (in_resourceType != "ResLuaData" || in_pResource == 0) return in_pResource; var pResource = (Resources.Data*)in_pResource; _currentResLuaData = (in_resourceName, (long)in_pResource); bool isHooked = false; string script = _scriptData.ContainsKey(in_resourceName) ? _scriptData[in_resourceName] : Helpers.PtrToStringUTF8((nint)pResource->pData, (int)pResource->Size); // Always allow committing backed up Lua data. if (_hooks.Count == 0 && _scriptData.ContainsKey(in_resourceName)) isHooked = true; foreach (var hook in _hooks) { if (hook.ScriptName == in_resourceName || string.IsNullOrEmpty(hook.ScriptName)) { // Back up current script since the game caches our changes. if (!_scriptData.ContainsKey(in_resourceName)) _scriptData.Add(in_resourceName, script); } else if (!string.IsNullOrEmpty(hook.ScriptName)) { continue; } string result = hook.WriteHook(script); if (script == result) continue; script = result; isHooked = true; } if (isHooked) { pResource->pData = TO_U8STRING_PTR(script); pResource->Size = Encoding.UTF8.GetBytes(script).Length; } return (long)pResource; } Resources.AddResourceDataAction(HookService); _isInitialised = true; } [LibraryUpdate] public void Update() { if (_lastGameModeName != GameMode.GetName()) { _lastGameModeName = GameMode.GetName(); if (_deniedGameModes.Contains(GameMode.GetName()) || GameMode.GetTutorialDestination() == GameMode.DestinationMode.GameModeStage) { return; } var pScriptSequenceManager = GameManager.GetService(); if (pScriptSequenceManager == null) return; if (pScriptSequenceManager->ScriptSequences.Length <= 0) { // BuildLevel uint hash = 0x59B595D6; GET_FUNCTION_PTR(InitScriptSequenceManager)(pScriptSequenceManager, &hash, (char)0); GET_FUNCTION_PTR(RegisterScriptSequenceManager)(pScriptSequenceManager); Logger.Utility($"[Lua] Initialised app::ScriptSequenceManager at 0x{((long)pScriptSequenceManager):X}!"); } } } public ScriptSequenceManager.ScriptSequence* GetScriptSequence() { var pScriptSequenceManager = GameManager.GetService(); if (pScriptSequenceManager == null) return null; var scriptSequences = pScriptSequenceManager->ScriptSequences; if (scriptSequences.Length <= 0) return null; return scriptSequences[0].pData; } public long GetState() { var pScriptSequence = GetScriptSequence(); if (pScriptSequence == null) return 0; return pScriptSequence->pScripts[0]->pLuaState; } public (string ScriptName, long pResourceData) GetCurrentScriptResource() { return (_currentResLuaData.ScriptName, _currentResLuaData.pResourceData); } public string Peek(bool in_isOutput = true) { long pResourceData = _currentResLuaData.pResourceData; if (pResourceData == 0) return string.Empty; var pResource = (Resources.Data*)pResourceData; string result = Helpers.PtrToStringUTF8((nint)pResource->pData, (int)pResource->Size); if (in_isOutput) { Logger.Utility($"[Lua] Peeking \"{_currentResLuaData.ScriptName}\" at 0x{pResourceData:X}..."); Logger.Warning("[Lua] WARNING: console output may look mangled due to unsupported characters"); Logger.Utility("[Lua] ///////////////////////////// PEEK START /////////////////////////////"); Console.Write($"\n{result}\n"); Logger.Utility("[Lua] ////////////////////////////// PEEK END //////////////////////////////"); } return result; } public LineHook CreateLineHook(string in_code, string in_scriptName, string in_pattern, HookBehavior in_behaviour, bool in_isRegex = false, RegexOptions in_regexOptions = default) { var hook = new LineHook(in_code, in_scriptName, in_pattern, in_behaviour, in_isRegex, in_regexOptions); if (_hooks.Contains(hook)) return hook; _hooks.Add(hook); return hook; } public LineHook CreateLineHook(string in_code, string in_pattern, HookBehavior in_behaviour, bool in_isRegex = false) { // Hook all Lua scripts. return CreateLineHook(in_code, null, in_pattern, in_behaviour, in_isRegex); } public FunctionHook CreateFunctionHook(string in_code, string in_scriptName, string in_functionName, HookBehavior in_behaviour) { var hook = new FunctionHook(in_code, in_scriptName, in_functionName, in_behaviour); if (_hooks.Contains(hook)) return hook; _hooks.Add(hook); return hook; } public FunctionHook CreateFunctionHook(string in_code, string in_functionName, HookBehavior in_behaviour) { // Hook all Lua scripts. return CreateFunctionHook(in_code, null, in_functionName, in_behaviour); } public void UninstallHook(Hook in_hook) { if (in_hook == null) return; if (!_hooks.Contains(in_hook)) return; _hooks.Remove(in_hook); } public string CreateFunctionSignature(string in_functionName, params object[] in_args) { var code = new StringBuilder(); { code.Append($"{in_functionName}("); int i = 0; foreach (var arg in in_args) { if (arg.GetType() == typeof(string)) { code.Append($"\"{arg}\""); } else { code.Append($"{arg}"); } if (i != in_args.Length - 1) { code.Append(", "); } i++; } code.Append(")"); } return code.ToString(); } public void SetPrintPreviousError(bool in_isEnabled) { _isPrintPreviousError = in_isEnabled; } public string GetPreviousError(long in_pLuaState) { var pError = (IntPtr)GET_FUNCTION_PTR(lua_tolstring)(in_pLuaState, -1, 0); GET_FUNCTION_PTR(lua_pop)(in_pLuaState, 1); return FROM_STRING_PTR(pError); } private void CallHandled(long in_pLuaState, int in_args, int in_results) { if (in_pLuaState == 0) return; if (GET_FUNCTION_PTR(lua_pcallk)(in_pLuaState, in_args, in_results, 0, 0, 0) != LUA_OK) { if (_isPrintPreviousError) Logger.Error($"[Lua] Error: {GetPreviousError(in_pLuaState)}"); } } public void Script(string in_code, bool in_isRunOnce = false) { long pLuaState = GetState(); if (pLuaState == 0) return; if (in_isRunOnce) { uint codeHash = StringMapOperation.ComputeHash(in_code); if (_userScriptHandles.Contains(codeHash)) { return; } else { _userScriptHandles.Add(codeHash); } } long str = TO_STRING_PTR(in_code); GET_FUNCTION_PTR(luaL_loadbufferx)(pLuaState, str, in_code.Length, str, 0); CallHandled(pLuaState, 0, -1); } public void LoadScript(string in_path, bool in_isRunOnce = false) { if (!File.Exists(in_path)) return; string code = string.Empty; try { code = File.ReadAllText(in_path); } catch (IOException) { Logger.Error($"[Lua] Error: \"{in_path}\" is being used by another process."); } if (string.IsNullOrEmpty(code)) return; Script(code, in_isRunOnce); } private void Call(string in_functionName, int in_resultCount, params object[] in_args) { long pLuaState = GetState(); if (pLuaState == 0) return; GET_FUNCTION_PTR(lua_getglobal)(pLuaState, TO_STRING_PTR(in_functionName)); foreach (var arg in in_args) { var type = arg.GetType(); if (type == typeof(string)) { string str = (string)arg; GET_FUNCTION_PTR(lua_pushlstring)(pLuaState, TO_STRING_PTR(str), str.Length); } else if (type == typeof(int)) { GET_FUNCTION_PTR(lua_pushinteger)(pLuaState, (int)arg); } else if (type == typeof(float) || type == typeof(double)) { GET_FUNCTION_PTR(lua_pushnumber)(pLuaState, (float)arg); } else if (type == typeof(bool)) { GET_FUNCTION_PTR(lua_pushboolean)(pLuaState, (bool)arg ? 1 : 0); } else { Logger.Error($"[Lua] Type {type} is not supported..."); return; } } CallHandled(pLuaState, in_args.Length, in_resultCount); } public void Call(string in_functionName, params object[] in_args) { Call(in_functionName, 0, in_args); } public T Call(string in_functionName, params object[] in_args) { long pLuaState = GetState(); if (pLuaState == 0) return default; Call(in_functionName, 1, in_args); var type = typeof(T); var luaType = GET_FUNCTION_PTR(lua_type)(pLuaState, -1); if (type == typeof(string) && luaType == LUA_TSTRING) { long ptr = (long)GET_FUNCTION_PTR(lua_tolstring)(pLuaState, -1, 0); return (T)(object)FROM_STRING_PTR(ptr); } else if (type == typeof(int) && luaType == LUA_TNUMBER) { return (T)(object)(int)GET_FUNCTION_PTR(lua_tointegerx)(pLuaState, -1, 0); } else if ((type == typeof(float) || type == typeof(double)) && luaType == LUA_TNUMBER) { return (T)(object)(float)GET_FUNCTION_PTR(lua_tonumberx)(pLuaState, -1, 0); } else if (type == typeof(bool) && luaType == LUA_TBOOLEAN) { return (T)(object)(bool)GET_FUNCTION_PTR(lua_toboolean)(pLuaState, -1); } else { Logger.Error($"[Lua] Type {type} is not supported..."); } return default; } } Library "Messages" by "Hyper, Sajid & ĐeäTh" { #include "Helpers" noemit #lib "GameManager" #lib "GameService" #lib "Memory" #lib "Player" #lib "StringMapOperation" #import "Allocators" using System.Runtime.InteropServices; using System.Text; /* 0x15306BF10 */ private static long _sigEnqueueMessage = ScanSignature("\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x63\x41\x38", "xxxxxxxxxxxxxx"); FUNCTION_PTR(long, fpEnqueueMessage, _sigEnqueueMessage, MessageQueue* in_pMessageQueue, void* in_pMessage) /* v1.42: 0x150517C80 */ private static long _sigSendMessageToGameManager = ScanSignature("\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x57\x48\x83\xEC\x20\x31\xFF\x48\x89\xD6\x48\x89\xCB\x48\x39\xB9\xB8\x01\x00\x00\x76\x28\x48\x8B\x83\xB0\x01\x00\x00\x48\x8B\x0C\xF8\x48\x85\xC9\x74\x0C\x48\x8B\x01\x49\x89\xF0\x48\x89\xDA\xFF\x50\xCC\x48\xFF\xC7\x48\x3B\xBB\xB8\x01\x00\x00\x72\xD8\x8B\x35", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx?xxxxxxxxxxxxxx"); FUNCTION_PTR(void, fpSendMessageToGameManager, _sigSendMessageToGameManager, GameManager.Data* in_pGameManager, void* in_pMessage) /* 0x146E60CB0 */ private static long _sigSendMessageToGameService = ScanSignature("\x48\x89\x5C\x24\x10\x55\x57\x41\x56\x48\x83\xEC\x20\x4C", "xxxxxxxxxxxxxx"); FUNCTION_PTR(long, fpSendMessageToGameService, _sigSendMessageToGameService, GameService.Data* in_pGameService, void* in_pGameManager, void* in_pMessage) /* 0x150128D20 */ private static long _sigSendMessageToLayer = ScanSignature("\x48\x89\x5C\x24\x18\x55\x48\x83\xEC\x20\x48\x63", "xxxxxxxxxxxx"); FUNCTION_PTR(long, fpSendMessageToLayer, _sigSendMessageToLayer, GameManager.Data* in_pGameManager, int in_layerIndex, void* in_pMessage) /* 0x146E56F10 */ private static long _sigSendMessageToMessenger = ScanSignature("\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x10\x48\x89\x74\x24\x18\x57\x48\x83\xEC\x30\x4C\x89\xCF\x41", "xxxxxxxxxxxxxxxxxxxxxxxx"); FUNCTION_PTR(byte, fpSendMessageToMessenger, _sigSendMessageToMessenger, void* in_pGameObject, void* in_pGameManager, byte a3, void* in_pMessage) /* 0x146E5A6A0 */ private static long _sigSendMessageToPlayer = ScanSignature("\x48\x89\x5C\x24\x18\x56\x57\x41\x56\x48\x83\xEC\x20\x48\x8B\x59", "xxxxxxxxxxxxxxxx"); FUNCTION_PTR(long, fpSendMessageToPlayer, _sigSendMessageToPlayer, Player.Data* in_pPlayer, void* in_pMessage) /// /// A struct representation of `hh::fnd::Message`. /// [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct Message { [FieldOffset(0)] public long pVftable; [FieldOffset(0x08)] public int ID; [FieldOffset(0x0C)] public int Sender; [FieldOffset(0x10)] public int Receiver; [FieldOffset(0x14)] public bool IsBroadcasted; [FieldOffset(0x18)] public uint Mask = 0xFFFFFFFF; public Message(int in_id) { ID = in_id; } VFUNCTION_PTR(Message, 0, Message*, Clone, Message* in_pMessage, IAllocator* in_pAllocator) VFUNCTION_PTR(Message, 1, Message*, Dtor, Message* in_pMessage, byte a2) } /// /// A struct representation of `hh::fnd::MessageQueue`. /// [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct MessageQueue { } /// /// A struct representation of `app::game::MsgChangePlayerCharacter`. /// [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct MsgChangePlayerCharacter { [FieldOffset(0)] public Message Base = new Message(0x20C8); [FieldOffset(0x20)] public Player.PlayerType PlayerType; public MsgChangePlayerCharacter() { } public MsgChangePlayerCharacter(Player.PlayerType in_playerType) : this() { PlayerType = in_playerType; } } /// /// A struct representation of `app::player::MsgHoldOn`. /// [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct MsgHoldOn { [FieldOffset(0)] public Message Base = new Message(0x21DA); [FieldOffset(0x24)] public byte UnkByte1; [FieldOffset(0x28)] public int UnkInt1; public MsgHoldOn() { UnkByte1 = 0; UnkInt1 = 144; } } /// /// A struct representation of `app::player::MsgHoldRelease`. /// [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct MsgHoldRelease { [FieldOffset(0)] public Message Base = new Message(0x21DB); [FieldOffset(0x20)] public int UnkInt1; [FieldOffset(0x50)] public byte UnkByte1; public MsgHoldRelease() { UnkInt1 = 0; UnkByte1 = 0; } } /// /// A struct representation of `app::game::MsgResumeWorld`. /// [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct MsgResumeWorld { [FieldOffset(0)] public Message Base = new Message(0x22CF); [FieldOffset(0x20)] public fixed byte Name[16]; [FieldOffset(0x30)] public bool UnkBool1; public MsgResumeWorld() { /* 0x1414150E0 */ Base.pVftable = Memory.ReadEffectiveAddress ( /* 0x1402090C0 */ ScanSignature ( "\x48\x8D\x05\xCC\xCC\xCC\xCC\x41\xB8\x10\x00\x00\x00\x48\x8D\x15\xCC\xCC\xCC\xCC\x48\x89\x45\xB7\x48\x8D\x4D\xD7\xE8\xCC\xCC\xCC\xCC\x48\x8B\x4E\x30", "xxx????xxxxxxxxx????xxxxxxxxx????xxxx" ) ); } public MsgResumeWorld(string in_name) : this() { fixed (byte* pName = Name) { var nameArr = Encoding.UTF8.GetBytes(in_name.Length <= 16 ? in_name : in_name.Substring(0, 16)); for (int i = 0; i < nameArr.Length; i++) pName[i] = nameArr[i]; } // Set common defaults for unknown values. UnkBool1 = true; } } /// /// A struct representation of `app::MsgSpringRoute`. /// [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct MsgSpringRoute { [FieldOffset(0)] public Message Base = new Message(0x231E); [FieldOffset(0x20)] public int Handle; [FieldOffset(0x24)] public float Velocity; public MsgSpringRoute() { } public MsgSpringRoute(GameObject.Data* in_sender, float in_velocity) { Handle = in_sender->Handle; Velocity = in_velocity; } } /// /// A struct representation of `app::camera::MsgStartFreeCamera`. /// [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct MsgStartFreeCamera { [FieldOffset(0)] public Message Base = new Message(0x2329); [FieldOffset(0x20)] public float UnkFloat1; public MsgStartFreeCamera() { UnkFloat1 = 0.4f; } } /// /// A struct representation of `app::game::MsgSuspendWorld`. /// [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct MsgSuspendWorld { [FieldOffset(0)] public Message Base = new Message(0x2352); [FieldOffset(0x20)] public fixed byte Name[16]; [FieldOffset(0x30)] public uint Flags; [FieldOffset(0x34)] public float UnkFloat1; [FieldOffset(0x38)] public bool UnkBool1; public MsgSuspendWorld() { /* 0x1414150B0 */ Base.pVftable = Memory.ReadEffectiveAddress ( /* 0x140208D70 */ ScanSignature ( "\x48\x8D\x05\xCC\xCC\xCC\xCC\x41\xB8\x10\x00\x00\x00\xF3\x0F\x11\x45\xEB\x48\x8D\x15\xCC\xCC\xCC\xCC\x48\x89\x45\xB7\x48\x8D\x4D\xD7\x44\x88\x75\xD7", "xxx????xxxxxxxxxxxxxx????xxxxxxxxxxxx" ) ); } public MsgSuspendWorld(string in_name, uint in_flags) : this() { fixed (byte* pName = Name) { var nameArr = Encoding.UTF8.GetBytes(in_name.Length <= 16 ? in_name : in_name.Substring(0, 16)); for (int i = 0; i < nameArr.Length; i++) pName[i] = nameArr[i]; } Flags = in_flags; // Set common defaults for unknown values. UnkFloat1 = -1.0f; UnkBool1 = true; } } /// /// A struct representation of `app::ui::MsgUISetGameCockpitEnabled`. /// [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct MsgUISetGameCockpitEnabled { [FieldOffset(0)] public Message Base = new Message(0x2406); [FieldOffset(0x20)] public ulong Flags; [FieldOffset(0x28)] public bool IsEnabled; [FieldOffset(0x2C)] public uint Hash; public MsgUISetGameCockpitEnabled(string in_name, ulong in_flags, bool in_isEnabled) { Base.Mask = 0x4000000; Flags = in_flags; IsEnabled = in_isEnabled; Hash = StringMapOperation.ComputeHash(in_name); } } public void EnqueueMessage(T in_message) where T : unmanaged { var pGameManager = GameManager.Get(); if (pGameManager == null) return; GET_FUNCTION_PTR(fpEnqueueMessage)(&pGameManager->MessageQueue, &in_message); } public void SendMessageToGameManager(T in_message) where T : unmanaged { var pGameManager = GameManager.Get(); if (pGameManager == null) return; GET_FUNCTION_PTR(fpSendMessageToGameManager)(pGameManager, &in_message); } public void SendMessageToGameService(GameService.Data* in_pGameService, T in_message) where T : unmanaged { if (in_pGameService == null) return; GET_FUNCTION_PTR(fpSendMessageToGameService)(in_pGameService, in_pGameService->pGameManager, &in_message); } public void SendMessageToLayer(int in_layerIndex, T in_message) where T : unmanaged { var pGameManager = GameManager.Get(); if (pGameManager == null) return; GET_FUNCTION_PTR(fpSendMessageToLayer)(pGameManager, in_layerIndex, &in_message); } public void SendMessageToMessenger(void* in_pMessenger, T in_message) where T : unmanaged { var pGameManager = GameManager.Get(); if (pGameManager == null) return; GET_FUNCTION_PTR(fpSendMessageToMessenger)(in_pMessenger, pGameManager, 0, &in_message); } public void SendMessageToPlayer(T in_message) where T : unmanaged { var pPlayer = Player.GetPlayerData(); if (pPlayer == null) return; GET_FUNCTION_PTR(fpSendMessageToPlayer)(pPlayer, &in_message); } } Library "Knuckles" by "Hyper" { /// /// An enum containing all of Knuckles' state IDs. /// public enum StateID : int { Default = -1, StateAcceleCombo1 = 149, // StateAttackRoot StateAcceleCombo2 = 150, // StateAttackRoot StateAquaBallJump = 121, StateAquaBallStand = 120, StateAquaBallStomping = 122, StateAttackRoot = 134, StateAuraTrain = 191, StateAvoid = 140, StateAvoidLocal = 143, StateAvoidToTarget = 142, StateAvoidUpper = 141, StateAwakening = 27, StateBallMove = 172, StateBaseJump = 102, StateBatterBox = 203, StateBattleStart = 158, StateBoarding = 183, StateBossCounter = 159, StateBrake = 6, StateBrakeNeutral = 7, StateBreathe = 44, StateBumpJump = 16, StateCaught = 167, StateChargeAttack = 151, // StateAttackRoot StateClimbing = 100, // StateWallActionRoot StateClimbingEdge = 99, // StateWallActionRoot StateCloudJump = 192, StateHomingFinish = 136, // StateAttackRoot StateComboMove = 131, StateComboStep = 132, StateComboWarp = 133, StateCrasher = 153, // StateAttackRoot StateCrossSlash = 155, // StateAttackRoot StateDamage = 29, // StateDamageRoot StateDamageBlowOff = 31, // StateDamageRoot StateDamageBlowOffHeavy = 32, // StateDamageRoot StateDamageLava = 38, StateDamageQuake = 33, // StateDamageRoot StateDamageRoot = 28, StateDamageRunning = 34, // StateDamageRoot StateDamageTurnBack = 30, // StateDamageRoot StateDead = 39, StateDebuff = 180, StateDestination = 188, StateDiving = 79, // StateDivingRoot StateDivingDamage = 81, // StateDivingRoot StateDivingFall = 80, // StateDivingRoot StateDivingRoot = 78, StateDivingSpecial = 84, // StateDivingSpecialRoot StateDivingSpecialDamage = 87, // StateDivingSpecialRoot StateDivingSpecialDashRing = 85, // StateDivingSpecialRoot StateDivingSpecialFall = 86, // StateDivingSpecialRoot StateDivingSpecialPush = 88, // StateDivingSpecialRoot StateDivingSpecialRoot = 83, StateDivingSpring = 82, // StateDivingRoot StateDrift = 111, StateDriftDash = 112, StateDriftAir = 113, StateDropDash = 114, StateFall = 15, StateFallWithKodama = 198, StateFallWithCannonball = 201, StateFallFlip = 21, StateFallingDead = 40, StateFallSlope = 20, StateFan = 171, StateFixedGoal = 128, StateFloat = 108, StateFly = 103, StateFlyLocal = 106, StateFlyLocal2D = 107, StateFlyOnPath = 105, StateFlyTurn = 104, StateGoal = 126, StateGoal2 = 127, StateGrind = 47, // StateGrindRoot StateGrindDamage = 50, // StateGrindRoot StateGrindDamageAir = 51, // StateGrindRoot StateGrindJump = 48, // StateGrindRoot StateGrindDoubleJump = 49, // StateGrindRoot StateGrindRoot = 46, StateGrindStep = 52, StateGuard = 148, StateGuardedFlipBack = 35, // StateDamageRoot StateHangPole = 173, StateHangPoleJump = 174, StateHoldStand = 162, StateHomingAttack = 63, // StateAttackRoot StateHomingAttackRoot = 62, // StateAttackRoot StateHomingAttackInStorm = 64, // StateAttackRoot StateHomingFinished = 65, // StateAttackRoot StateHomingRepelled = 66, StateHomingShot = 156, // StateAttackRoot StateImpactGimmick = 185, StateJump = 8, StateJumpWithKodama = 197, StateJumpBoardLaunch = 170, StateBounceJump = 11, StateRecoveryJump = 12, StateSpringJump = 165, StateSpringJumpHeadLand = 166, StateKickBox = 176, StateLavaDead = 45, StateLeftStep = 72, StateLeftStepRun = 74, PlayerStateLevitation = 215, StateLightDash = 26, StateLoopKick = 152, // StateAttackRoot StateMoveInWarningArea = 189, StateMoveToBatterBox = 204, StateMoveToBossArea = 190, StateMoveToReflexesPanel = 206, StateNoisyGoal = 129, StateOperateConsole = 184, StateParalysis = 37, StateParriedFlipBack = 36, StateParry = 144, StateParryStand = 145, // StateParry StatePipeMove = 168, StatePipeOut = 169, StatePressDead = 43, StatePursuitKick = 135, // StateAttackRoot StatePushBox = 175, StateQuickCyloop = 137, // StateAttackRoot StateQuickStep = 68, // StateQuickStepRoot StateQuickStepCrash = 71, // StateQuickStepRoot StateQuickStepJump = 76, StateQuickStepDoubleJump = 77, StateQuickStepLeft = 69, // StateQuickStepRoot StateQuickStepRight = 70, // StateQuickStepRoot StateQuickStepRoot = 67, StateRecoil = 19, StateRecovery = 164, StateReflexesPanel = 205, StateReflexesPanelLeftStep = 207, StateReflexesPanelRightStep = 208, StateRightStep = 73, StateRightStepRun = 75, StateRun = 4, StateRunWithKodama = 196, StateRunWithCannonball = 199, StateRunawayBee = 194, StateRunningStart = 125, StateSandSki = 177, StateSandSkiBlow = 178, StateSendSignal = 186, StateSleep = 0, StateSliding = 60, // StateSquatRoot StateSlidingToStand = 61, StateSlingshot = 179, StateSmash = 138, // StateAttackRoot StateSmashSS = 139, // StateAttackRoot StateSonicBoomKick = 154, // StateAttackRoot StateSpin = 115, StateSpinAttack = 14, StateSpinBoost = 118, StateSpinBoostCharge = 117, StateSpinMove = 119, StateSpinDash = 116, // StateAttackRoot StateSpinSlash = 157, // StateAttackRoot StateSquat = 18, // StateSquatRoot StateSquatRoot = 17, StateStandRoot = 1, StateStandWithKodama = 195, StateStand = 2, // StateStandRoot StateStandWithCannonball = 200, StateStolenEmerald = 182, StateStorm = 181, StateSuffocatingDead = 42, StateTakeBehind = 146, StateTakeBehindSS = 147, StateTalkMode = 163, StateThrowCannonball = 202, StateTimeUpDead = 130, StateTreadmill = 193, StateTreeJump = 276, StateTurn = 5, StateUpDead = 41, StateUpDownPole = 123, StateUpDownPoleDamage = 124, StateWakeUp = 3, StateWarpEnd = 161, StateWarpStart = 160, StateWaterFall = 187, StateCyKnuckle = 217, // StateAttackRoot StateCyKnuckleWall = 219, // StateWallActionRoot StateCyKnucklePreFall = 218, StateCyKnuckleHideHole = 222, StateCyKnuckleInHole = 220, StateCyKnuckleOutHole = 221, StateCyKnucklePopupItem = 224, StateCyKnuckleWarp = 223, StateGliding = 10, StateDoubleJump = 9, KnucklesStatePunch1 = 231, // StateAttackRoot KnucklesStatePunch2 = 232, // StateAttackRoot KnucklesStateUppercut = 233, // StateAttackRoot StateMaximumHeatKnuckle = 234, // StateAttackRoot StateMaximumHeatKnuckleFollow = 235, StateMaximumHeatKnuckleBounce = 236, // StateAttackRoot KnucklesStateStomping = 53, // StateAttackRoot KnucklesStateStompingBounce = 59, // StateAttackRoot KnucklesStateStompingDown = 55, // StateAttackRoot KnucklesStateStompingLand = 58, // StateAttackRoot KnucklesStateDrillBoostRoot = 225, KnucklesStateDrillBoost = 226, // KnucklesStateDrillBoostRoot KnucklesStateDrillBoostJump = 228, // KnucklesStateDrillBoostRoot KnucklesStateDrillBoostFall = 229, // KnucklesStateDrillBoostRoot KnucklesStateDrillBoostStep = 230, // KnucklesStateDrillBoostRoot StateAirBoost = 22, KnucklesStateDrillBoostAir = 23, // KnucklesStateDrillBoostRoot KnucklesStateWallMove = 90, // StateWallActionRoot StateWallHoming = 93, StateWallLeave = 101, StateWallSlideDown = 95, // StateWallActionRoot StateWallActionRoot = 89, } } Library "GameModes" by "Hyper" { #include "Helpers" noemit #lib "Helpers" using System.Runtime.InteropServices; /// /// A struct representation of `app::game::GameModeCyberStageChallenge`. /// [StructLayout(LayoutKind.Explicit, Size = 0x170)] public struct GameModeCyberStageChallenge { /// /// The directory location of the current stage. /// [FieldOffset(0xE0)] public Helpers.UnmanagedString Location; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// /// Extensions /// ///////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// A struct representation of `app::game::GameModeExtension`. /// [StructLayout(LayoutKind.Explicit)] public struct GameModeExtension { /// /// A pointer to an instance of `app::game::GameMode` acting as the parent of this extension. /// [FieldOffset(0x10)] public GameMode.Data* pGameMode; /// /// A pointer to an instance of `hh::game::GameManagerListener`. /// [FieldOffset(0x18)] public void* pGameManagerListener; VFUNCTION_PTR(GameModeExtension, 1, uint, GetNameHash) } /// /// A struct representation of `app::game::GameModeStageTimeExtension`. /// [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct GameModeStageTimeExtension { [FieldOffset(0)] public GameModeExtension Base; /// /// The current elapsed time. /// [FieldOffset(0x30)] public float Time; } } Library "BlackboardBattle" by "Hyper, ĐeäTh & NM" does "Provides access to `app::player::BlackboardBattle` from Sonic Frontiers." { #import "Blackboard" using System.Runtime.InteropServices; /// /// A struct representation of `app::player::BlackboardBattle`. /// [StructLayout(LayoutKind.Explicit, Size = 0x100, Pack = 0x10)] public struct Data { /// /// An instance of `app::player::BlackboardContent`, the base class for `app::player::BlackboardBattle`. /// [FieldOffset(0x00)] public BlackboardContent BlackboardContent; /// /// The player's current power (attack) level. /// [FieldOffset(0x20)] public byte PowerLevel; /// /// The player's current defense level. /// [FieldOffset(0x21)] public byte DefenseLevel; /// /// The value of the Phantom Rush gauge. /// [FieldOffset(0xAC)] public float PhantomRushAmount; /// /// The number of attack combos performed by the player. /// [FieldOffset(0xA8)] public int ComboCount; /// /// The value of the Quick Cyloop gauge. /// [FieldOffset(0xB8)] public float QuickCyloopAmount; } /// /// Gets an instance of `app::player::BlackboardBattle`. /// /// /// /// /// A pointer to an instance of `app::player::BlackboardBattle`. public Data* Get() { return (Data*)Blackboard.GetPlayerBlackboardContent("BlackboardBattle"); } } Library "PlayerEffect" by "Hyper" { #include "Helpers" noemit #import "Collections" #import "GOComponents" #lib "GameObject" #lib "Helpers" #lib "Memory" #lib "Player" #lib "StringMapOperation" using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct Data { [FieldOffset(0x18)] public Player.Data* pPlayer; [FieldOffset(0x20)] public long pVisualHuman; [FieldOffset(0x28)] public GOCPlayerVisual* pGOCPlayerVisual; [FieldOffset(0x30)] public GOCPlayerKinematicParams* pGOCPlayerKinematicParams; [FieldOffset(0x38)] public GOCPlayerBlackboard* pGOCPlayerBlackboard; VFUNCTION_PTR(Data, 1, uint, GetNameHash) } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct EffectList { [FieldOffset(0x28)] public ObjectMoveArray> PlayerEffects; } public Data* Get(string in_name) { var pPlayer = Player.GetPlayerData(); if (pPlayer == null) return null; var pGOCPlayerEffect = GameObject.GetGOC(&pPlayer->GameObject); if (pGOCPlayerEffect == null) return null; var playerEffects = pGOCPlayerEffect->pEffectList->PlayerEffects; for (int i = 0; i < playerEffects.Length; i++) { var pPlayerEffect = playerEffects[i].pData; if ((uint)pPlayerEffect->GetNameHash()() == StringMapOperation.ComputeHash(in_name)) return pPlayerEffect; } return null; } public T* Get() where T : unmanaged { var name = Helpers.GetInternalName(typeof(T)); return (T*)(long)Get(string.IsNullOrEmpty(name) ? typeof(T).Name : name); } } Library "GameTypes" by "Sajid" { #include "Helpers" noemit #lib "MessageManager" public struct BaseObject { public nint VFTable; } public struct ReferencedObject { public BaseObject Base; public void* Allocator; public int Unk1; public int RefCount; } public interface IRefByHandleObject { int Handle { get; set; } } public struct RefByHandleObject : IRefByHandleObject { public ReferencedObject Base; public int Handle; DEFINE_INTERFACE_PROPERTY(IRefByHandleObject, int, Handle) DEFINE_BASE_PROPERTY(void*, Allocator) DEFINE_BASE_PROPERTY(int, RefCount) } public interface IMessenger : IRefByHandleObject { MessageManager.Data* MessageManager { get; set; } } public struct Messenger : IMessenger { public RefByHandleObject Base; public MessageManager.Data* MessageManager; public uint AllowedMessageMask; DEFINE_BASE_PROPERTY(void*, Allocator) DEFINE_BASE_PROPERTY(int, RefCount) DEFINE_BASE_PROPERTY(int, Handle) DEFINE_INTERFACE_PROPERTY(IMessenger, MessageManager.Data*, MessageManager) DEFINE_INTERFACE_PROPERTY(IRefByHandleObject, int, Handle) } } Library "BlackboardStatus" by "Hyper, ĐeäTh, NM & Sora" does "Provides access to `app::player::BlackboardStatus` from Sonic Frontiers." { #include "Helpers" noemit #import "Blackboard" #import "Collections" #lib "Player" /// /// Determines whether a state flag is set. /// /// /// /// /// The name of an enum member from the `StateFlags` enum. /// A boolean value representing whether the state flag is set. #define IS_STATE_FLAG(in_name) (BlackboardStatus.Get() != null && BlackboardStatus.Get()->StateFlags.Test((ulong)BlackboardStatus.StateFlags.in_name)) /// /// Sets a state flag. /// /// /// /// /// The name of an enum member from the `StateFlags` enum. /// The enabled state of the specified flag. #define SET_STATE_FLAG(in_name, in_isEnabled) if (BlackboardStatus.Get() != null) BlackboardStatus.Get()->StateFlags.Set((ulong)BlackboardStatus.StateFlags.in_name, in_isEnabled) /// /// Determines whether a combat flag is set. /// /// /// /// /// The name of an enum member from the `CombatFlags` enum. /// A boolean value representing whether the combat flag is set. #define IS_COMBAT_FLAG(in_name) (BlackboardStatus.Get() != null && BlackboardStatus.Get()->CombatFlags[(int)BlackboardStatus.CombatFlags.in_name >> 6].Test((ulong)BlackboardStatus.CombatFlags.in_name & 0x3F)) /// /// Sets a combat flag. /// /// /// /// /// The name of an enum member from the `CombatFlags` enum. /// The enabled state of the specified flag. #define SET_COMBAT_FLAG(in_name, in_isEnabled) if (BlackboardStatus.Get() != null) BlackboardStatus.Get()->CombatFlags[(int)BlackboardStatus.CombatFlags.in_name >> 6].Set((ulong)BlackboardStatus.CombatFlags.in_name & 0x3F, in_isEnabled) /// /// Determines whether a world flag is set. /// /// /// /// /// The name of an enum member from the `WorldFlags` enum. /// A boolean value representing whether the world flag is set. #define IS_WORLD_FLAG(in_name) (BlackboardStatus.Get() != null && BlackboardStatus.Get()->WorldFlags[(int)BlackboardStatus.WorldFlags.in_name >> 6].Test((ulong)BlackboardStatus.WorldFlags.in_name & 0x3F)) /// /// Sets a world flag. /// /// /// /// /// The name of an enum member from the `WorldFlags` enum. /// The enabled state of the specified flag. #define SET_WORLD_FLAG(in_name, in_isEnabled) if (BlackboardStatus.Get() != null) BlackboardStatus.Get()->WorldFlags[(int)BlackboardStatus.WorldFlags.in_name >> 6].Set((ulong)BlackboardStatus.WorldFlags.in_name & 0x3F, in_isEnabled) using System.Runtime.InteropServices; /// /// An enum containing each of the game's difficulty settings. /// public enum DifficultySetting : byte { Easy = 0x00, Normal = 0x01, Hard = 0x02, Extreme = 0x03 } /// /// A struct representation of `app::player::BlackboardStatus`. /// [StructLayout(LayoutKind.Explicit, Size = 0x180, Pack = 0x10)] public struct Data { /// /// An instance of `app::player::BlackboardContent`, the base class for `app::player::BlackboardStatus`. /// [FieldOffset(0x000)] public BlackboardContent BlackboardContent; /// /// Determines if the current player is in their Super form. /// [FieldOffset(0x024)] public bool IsSuper; /// /// Bit flags representing combat statuses. /// [FieldOffset(0x028)] UNMANAGED_FIXED_ARRAY(BitSet64, CombatFlags, 2) /// /// Bit flags representing state statuses. /// [FieldOffset(0x038)] public BitSet64 StateFlags; /// /// Bit flags representing world statuses. /// [FieldOffset(0x040)] UNMANAGED_FIXED_ARRAY(BitSet64, WorldFlags, 2) /// /// The player's chosen difficulty setting in the game's options. /// [FieldOffset(0x180)] public DifficultySetting Difficulty; } /// /// Gets an instance of `app::player::BlackboardStatus`. /// /// /// /// /// A pointer to an instance of `app::player::BlackboardStatus`. public Data* Get() { return (Data*)Blackboard.GetPlayerBlackboardContent("BlackboardStatus"); } /// /// Determines if the current player is in their Super form. /// /// A boolean value representing whether the current player is in their Super form. public bool IsSuper() { if (Player.GetPlayerType() != Player.PlayerType.Sonic) return false; var pBlackboardStatus = Get(); if (pBlackboardStatus == null) return false; return pBlackboardStatus->IsSuper; } /// /// An enum containing known state flags. /// public enum StateFlags : uint { /// /// The player is boosting. /// IsBoost = 0x00, /// /// The player is air boosting. /// IsAirBoost = 0x04, /// /// The player has jumped on a rail. /// IsGrindJump = 0x06, /// /// The player is grinding on a rail. /// IsGrind = 0x07, /// /// The player is jumping. /// IsJump = 0x08, /// /// The player has double jumped. /// IsDoubleJump = 0x09, /// /// The player has stomp bounced. /// IsBounceJump = 0x0A, /// /// The player is falling. /// IsFall = 0x0B, /// /// The player is stomping. /// IsStomp = 0x0C, /// /// The player is diving. /// IsDiving = 0x0D, /// /// The player is boosting whilst diving. /// IsDivingBoost = 0x0E, /// /// The player is using Cyloop. /// IsCyloop = 0x11, /// /// The player finished a Cyloop. /// IsCyloopEnd = 0x12, /// /// The player is drifting. /// IsDrift = 0x13, /// /// The player is performing a homing attack. /// IsHoming = 0x17, /// /// The player is parrying. /// IsParry = 0x18, /// /// The player is climbing a wall. /// IsWallClimb = 0x19, /// /// The player is idle. /// IsIdle = 0x1A, /// /// The player is idle on a climbable wall. /// IsWallClimbIdle = 0x1C, /// /// The player is using the skateboard. /// IsBoarding = 0x1E, /// /// The player has used a spring. /// IsSpringJump = 0x21, /// /// The player is performing a Spin Dash. /// IsSpinDash = 0x22 } /// /// An enum containing known combat flags. /// public enum CombatFlags : uint { /// /// The player side steps, rather than dodging. /// IsSideStep = 0x05, /// /// The player has Parry. /// IsParry = 0x0F, /// /// The player has Perfect Parry. /// IsPerfectParry = 0x10, /// /// The player has Air Trick unlocked. /// IsAirTrick = 0x1A, /// /// The player has Grand Slam unlocked. /// IsGrandSlam = 0x22, /// /// The player has Quick Cyloop unlocked. /// IsQuickCyloop = 0x28, /// /// The player has Phantom Rush unlocked. /// IsPhantomRush = 0x2A, /// /// The player has Cyclone Kick unlocked. /// IsCycloneKick = 0x2B, /// /// The player has Recovery Smash unlocked. /// IsRecoverySmash = 0x2C, /// /// The player has Sonic Boom unlocked. /// IsSonicBoom = 0x2E, /// /// The player has Wild Rush unlocked. /// IsWildRush = 0x2F, /// /// The player has Loop Kick unlocked. /// IsLoopKick = 0x30, /// /// The player has Spin Slash unlocked. /// IsSpinSlash = 0x31, /// /// The player has Stomp Attack unlocked. /// IsStompAttack = 0x32, /// /// The player has Homing Shot unlocked. /// IsHomingShot = 0x34, /// /// The player has Cross Slash unlocked. /// IsCrossSlash = 0x35, /// /// The player has Auto Combo unlocked. /// IsAutoCombo = 0x39, /// /// The player has Spin Dash unlocked. /// IsSpinDash = 0x3F } /// /// An enum containing known world flags. /// public enum WorldFlags : uint { /// /// The player is dead. /// IsDead = 0x01, /// /// The player has taken damage or has been repelled by an enemy's shield. /// IsDamagedOrRepelled = 0x02, /// /// The player no longer has control. /// IsOutOfControl = 0x07, /// /// The player is in an auto run section. /// IsAutoRun = 0x0A, /// /// The player is in Cyber Space. /// IsCyberSpace = 0x1E, /// /// The player has landed on a wall during a wall jump sequence. /// IsWallJumpLand = 0x22, /// /// The player has Power Boost. /// IsPowerBoost = 0x28, /// /// The player has Power Boost in Cyber Space. /// IsCyberSpacePowerBoost = 0x29, /// /// The player is air tricking. /// IsAirTrick = 0x2A, /// /// The player is standing on collision pertaining to the height map. /// IsHeightMapCollision = 0x37, /// /// Determines whether the player can clip through terrain (requires flag at bit index 14 to be set). /// IsNoClip = 0x38, /// /// The player is in battle. /// IsBattle = 0x3A, /// /// The player has Nitro Boost. /// IsNitroBoost = 0x43 } } Library "Collections" by "Sajid & Hyper" does "Provides extended collection types." { #import "Allocators" using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; #define MAKE_BITSET_TYPE(NAME, TYPE) \ public struct NAME \ { \ public TYPE Value; \ \ public void Reset() \ { \ Value = 0; \ } \ \ public void Reset(TYPE in_bitIndex) \ { \ Value &= (TYPE)(~((TYPE)1 << (int)in_bitIndex)); \ } \ \ public void Flip(TYPE in_bitIndex) \ { \ Value ^= (TYPE)(((TYPE)1 << (int)in_bitIndex)); \ } \ \ public void Set() \ { \ Value = TYPE.MaxValue; \ } \ \ public void Set(TYPE in_bitIndex) \ { \ Value |= (TYPE)(((TYPE)1 << (int)in_bitIndex)); \ } \ \ public void Set(TYPE in_bitIndex, bool in_isEnabled) \ { \ if (in_isEnabled) \ { \ Set(in_bitIndex); \ } \ else \ { \ Reset(in_bitIndex); \ } \ } \ \ public bool Test(TYPE in_bitIndex) \ { \ return (Value & (TYPE)(((TYPE)1 << (int)in_bitIndex))) != 0; \ } \ } MAKE_BITSET_TYPE(BitSet8, byte); MAKE_BITSET_TYPE(BitSet16, ushort); MAKE_BITSET_TYPE(BitSet32, uint); MAKE_BITSET_TYPE(BitSet64, ulong); private readonly nint SIGN_BIT = (nint)((1u << ((sizeof(nint) * sizeof(byte)) - 1))); /// /// A struct representation of `csl::ut::MoveArray`. /// public struct MoveArray : IEnumerable where T : unmanaged { public T* pBuffer; public int Length; public int Capacity; public IAllocator* pAllocator; public int Count => Length; public ref T this[int in_index] { get => ref pBuffer[in_index]; } private bool IsInplace() { return (Capacity & SIGN_BIT) != 0; } public void Reserve(int in_length) { if (in_length <= Capacity) return; var newLength = sizeof(T) * in_length; var pNewBuffer = pAllocator->Alloc()(pAllocator, newLength, 16); if (pBuffer != null) Buffer.MemoryCopy(pBuffer, (T*)(long)pNewBuffer, newLength, newLength); if (!IsInplace()) pAllocator->Free()(pAllocator, pBuffer); Capacity = in_length; pBuffer = (T*)(long)pNewBuffer; } public void Resize(int in_length) { Reserve(in_length); Length = in_length; } public void Add(T in_item) { Length++; if (Length > Capacity) Reserve(Length * 2); pBuffer[Length - 1] = in_item; } public void RemoveAt(int in_index) { if (in_index > Length) return; pBuffer[in_index] = pBuffer[in_index + 1]; Length--; } public void Remove(T in_item) { var index = IndexOf(in_item); if (index != -1) RemoveAt(index); } public void Clear() { Length = 0; } public int IndexOf(T in_item) { for (int i = 0; i < Length; i++) { if (this[i].Equals(in_item)) return i; } return -1; } public IEnumerator GetEnumerator() { for (var i = 0; i < Count; i++) { yield return this[i]; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public List ToList() { var l = new List(); foreach (var e in this) l.Add(e); return l; } public override string ToString() { if (typeof(T) == typeof(byte)) return Encoding.ASCII.GetString(ToList().Select(x => (byte)(object)x).ToArray()); return base.ToString(); } } /// /// A struct representation of `csl::ut::ObjectMoveArray`. /// public struct ObjectMoveArray : IEnumerable where T : unmanaged { public T* pBuffer; public nint Length; public nint Capacity; public IAllocator* pAllocator; public nint Count => Length; public ref T this[nint in_index] { get => ref pBuffer[in_index]; } private bool IsInplace() { return (Capacity & SIGN_BIT) != 0; } public void Reserve(nint in_length) { if (in_length <= Capacity) return; var newLength = sizeof(T) * in_length; var pNewBuffer = pAllocator->Alloc()(pAllocator, newLength, 16); if (pBuffer != null) Buffer.MemoryCopy(pBuffer, (T*)(long)pNewBuffer, newLength, newLength); if (!IsInplace()) pAllocator->Free()(pAllocator, pBuffer); Capacity = in_length; pBuffer = (T*)(long)pNewBuffer; } public void Add(T in_item) { Length++; if (Length > Capacity) Reserve(Length * 2); pBuffer[Length - 1] = in_item; } public void RemoveAt(nint in_index) { if (in_index > Length) return; pBuffer[in_index] = pBuffer[in_index + 1]; Length--; } public void Remove(T in_item) { var index = IndexOf(in_item); if (index != -1) RemoveAt(index); } public void Clear() { Length = 0; } public nint IndexOf(T in_item) { for (nint i = 0; i < Length; i++) { if (this[i].Equals(in_item)) return i; } return -1; } public IEnumerator GetEnumerator() { for (var i = 0; i < Count; i++) { yield return this[i]; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public List ToList() { var l = new List(); foreach (var e in this) l.Add(e); return l; } } /// /// A custom `System.Collections.Generic.List` where items are added and retrieved like a stack. /// public class StackList : List { private int _capacity; public StackList(int in_capacity) { _capacity = in_capacity; } /// /// Adds an item to the top of the stack. /// /// The item to add. public new void Add(T in_item) { if (Count >= _capacity) { RemoveAt(Count - 1); } Insert(0, in_item); } /// /// Gets an item from any index in the stack. /// /// The index to get the item from in the stack. /// The item in the stack at the requested index. public T GetItemAt(int in_index) { if (Count == 0) return default; if (in_index >= Count) { return this[Count - 1]; } return this[in_index]; } /// /// Adds an item to the top of the stack. /// /// The item to add. public void Push(T in_item) { Add(in_item); } /// /// Gets an item from the top of the stack and removes it. /// /// The item at the top of the stack. public T Pop() { T item = GetItemAt(0); RemoveAt(0); return item; } /// /// Gets the item at the top of the stack. /// /// The item at the top of the stack. public T Peek() { return GetItemAt(0); } } } Library "Sonic" by "Hyper, NM & Ahremic" { #include "Helpers" noemit #lib "PlayerEffect" #import "Collections" #import "Effects" using System.Runtime.InteropServices; ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static class Effect { /* 0x1407ED9FC */ private static long _sigGetSonicEffectCyloopVisualModel = ScanSignature("\xE8\xCC\xCC\xCC\xCC\x48\x85\xC0\x74\x12\x41\x0F\x2F\xF0", "x????xxxxxxxxx"); FUNCTION_PTR(long, fpGetSonicEffectCyloopVisualModel, Memory.ReadCall(_sigGetSonicEffectCyloopVisualModel), ref SonicEffectCyloop in_pSonicEffectCyloop, int in_index) /* 0x1407EDA13 */ private static long _sigSetVisualModelVisibility = ScanSignature("\xE8\xCC\xCC\xCC\xCC\x0F\x28\x74\x24\x60\x44\x0F\x28\x44\x24\x40\x48\x83\x7D\x50\x00", "x????xxxxxxxxxxxxxxxx"); FUNCTION_PTR(bool, fpSetVisualModelVisibility, Memory.ReadCall(_sigSetVisualModelVisibility), long in_pVisualModel, bool in_isVisible, byte in_unk1) /// /// Sets whether the Cyloop aura should be rendered. /// /// Determines whether the aura should render - setting this to false uses default behaviour. public static void SetCyloopAuraVisibility(bool in_isEnabled) { var pSonicEffectCyloop = PlayerEffect.Get(); if (pSonicEffectCyloop == null) return; var pVisualModel = GET_FUNCTION_PTR(fpGetSonicEffectCyloopVisualModel)(ref *pSonicEffectCyloop, 4); if (pVisualModel == 0) return; pSonicEffectCyloop->IsLocalVisualModelUpdate = !in_isEnabled; GET_FUNCTION_PTR(fpSetVisualModelVisibility)(pVisualModel, in_isEnabled, 0); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// An enum containing all of Sonic's state IDs. /// public enum StateID : int { Default = -1, StateAcceleCombo1 = 149, // StateAttackRoot StateAcceleCombo2 = 150, // StateAttackRoot StateAquaBallJump = 121, StateAquaBallStand = 120, StateAquaBallStomping = 122, StateAttackRoot = 134, StateAuraTrain = 191, StateAvoid = 140, StateAvoidLocal = 143, StateAvoidToTarget = 142, StateAvoidUpper = 141, StateAwakening = 27, StateBallMove = 172, StateBaseJump = 102, StateBatterBox = 203, StateBattleStart = 158, StateBoarding = 183, StateBossCounter = 159, StateBrake = 6, StateBrakeNeutral = 7, StateBreathe = 44, StateBumpJump = 16, StateCaught = 167, StateChargeAttack = 151, // StateAttackRoot StateClimbing = 100, // StateWallActionRoot StateClimbingEdge = 99, // StateWallActionRoot StateCloudJump = 192, StateHomingFinish = 136, // StateAttackRoot StateComboMove = 131, StateComboStep = 132, StateComboWarp = 133, StateCrasher = 153, // StateAttackRoot StateCrossSlash = 155, // StateAttackRoot StateDamage = 29, // StateDamageRoot StateDamageBlowOff = 31, // StateDamageRoot StateDamageBlowOffHeavy = 32, // StateDamageRoot StateDamageLava = 38, StateDamageQuake = 33, // StateDamageRoot StateDamageRoot = 28, StateDamageRunning = 34, // StateDamageRoot StateDamageTurnBack = 30, // StateDamageRoot StateDead = 39, StateDebuff = 180, StateDestination = 188, StateDiving = 79, // StateDivingRoot StateDivingDamage = 81, // StateDivingRoot StateDivingFall = 80, // StateDivingRoot StateDivingRoot = 78, StateDivingSpecial = 84, // StateDivingSpecialRoot StateDivingSpecialDamage = 87, // StateDivingSpecialRoot StateDivingSpecialDashRing = 85, // StateDivingSpecialRoot StateDivingSpecialFall = 86, // StateDivingSpecialRoot StateDivingSpecialPush = 88, // StateDivingSpecialRoot StateDivingSpecialRoot = 83, StateDivingSpring = 82, // StateDivingRoot StateDrift = 111, StateDriftDash = 112, StateDriftAir = 113, StateDropDash = 114, StateFall = 15, StateFallWithKodama = 198, StateFallWithCannonball = 201, StateFallFlip = 21, StateFallingDead = 40, StateFallSlope = 20, StateFan = 171, StateFixedGoal = 128, StateFloat = 108, StateFly = 103, StateFlyLocal = 106, StateFlyLocal2D = 107, StateFlyOnPath = 105, StateFlyTurn = 104, StateGoal = 126, StateGoal2 = 127, StateGrind = 47, // StateGrindRoot StateGrindDamage = 50, // StateGrindRoot StateGrindDamageAir = 51, // StateGrindRoot StateGrindJump = 48, // StateGrindRoot StateGrindDoubleJump = 49, // StateGrindRoot StateGrindRoot = 46, StateGrindStep = 52, StateGuard = 148, StateGuardedFlipBack = 35, // StateDamageRoot StateHangPole = 173, StateHangPoleJump = 174, StateHoldStand = 162, StateHomingAttack = 63, // StateAttackRoot StateHomingAttackRoot = 62, // StateAttackRoot StateHomingAttackInStorm = 64, // StateAttackRoot StateHomingFinished = 65, // StateAttackRoot StateHomingRepelled = 66, StateHomingShot = 156, // StateAttackRoot StateImpactGimmick = 185, StateJump = 8, StateJumpWithKodama = 197, StateJumpBoardLaunch = 170, StateBounceJump = 11, StateRecoveryJump = 12, StateSpringJump = 165, StateSpringJumpHeadLand = 166, StateKickBox = 176, StateLavaDead = 45, StateLeftStep = 72, StateLeftStepRun = 74, PlayerStateLevitation = 215, StateLightDash = 26, StateLoopKick = 152, // StateAttackRoot StateMoveInWarningArea = 189, StateMoveToBatterBox = 204, StateMoveToBossArea = 190, StateMoveToReflexesPanel = 206, StateNoisyGoal = 129, StateOperateConsole = 184, StateParalysis = 37, StateParriedFlipBack = 36, StateParry = 144, StateParryStand = 145, // StateParry StatePipeMove = 168, StatePipeOut = 169, StatePressDead = 43, StatePursuitKick = 135, // StateAttackRoot StatePushBox = 175, StateQuickCyloop = 137, // StateAttackRoot StateQuickStep = 68, // StateQuickStepRoot StateQuickStepCrash = 71, // StateQuickStepRoot StateQuickStepJump = 76, StateQuickStepDoubleJump = 77, StateQuickStepLeft = 69, // StateQuickStepRoot StateQuickStepRight = 70, // StateQuickStepRoot StateQuickStepRoot = 67, StateRecoil = 19, StateRecovery = 164, StateReflexesPanel = 205, StateReflexesPanelLeftStep = 207, StateReflexesPanelRightStep = 208, StateRightStep = 73, StateRightStepRun = 75, StateRun = 4, StateRunWithKodama = 196, StateRunWithCannonball = 199, StateRunawayBee = 194, StateRunningStart = 125, StateSandSki = 177, StateSandSkiBlow = 178, StateSendSignal = 186, StateSleep = 0, StateSliding = 60, // StateSquatRoot StateSlidingToStand = 61, StateSlingshot = 179, StateSmash = 138, // StateAttackRoot StateSmashSS = 139, // StateAttackRoot StateSonicBoomKick = 154, // StateAttackRoot StateSpin = 115, StateSpinAttack = 14, StateSpinBoost = 118, StateSpinBoostCharge = 117, StateSpinMove = 119, StateSpinDash = 116, // StateAttackRoot StateSpinSlash = 157, // StateAttackRoot StateSquat = 18, // StateSquatRoot StateSquatRoot = 17, StateStandRoot = 1, StateStandWithKodama = 195, StateStand = 2, // StateStandRoot StateStandWithCannonball = 200, StateStolenEmerald = 182, StateStorm = 181, StateSuffocatingDead = 42, StateTakeBehind = 146, StateTakeBehindSS = 147, StateTalkMode = 163, StateThrowCannonball = 202, StateTimeUpDead = 130, StateTreadmill = 193, StateTreeJump = 276, StateTurn = 5, StateUpDead = 41, StateUpDownPole = 123, StateUpDownPoleDamage = 124, StateWakeUp = 3, StateWarpEnd = 161, StateWarpStart = 160, StateWaterFall = 187, StateAirBoost = 22, StateWithAnimalRoot = 209, StateFallWithAnimal = 213, // StateWithAnimalRoot StateJumpWithAnimal = 212, // StateWithAnimalRoot StateDoubleJump = 9, StateRunWithAnimal = 211, // StateWithAnimalRoot StateStandWithAnimal = 210, // StateWithAnimalRoot StatePutDownAnimal = 214, // StateWithAnimalRoot StateStomping = 53, // StateAttackRoot StateStompingAttack = 56, // StateAttackRoot StateStompingBounce = 59, // StateAttackRoot StateStompingDown = 55, // StateAttackRoot StateStompingFlip = 54, // StateAttackRoot StateStompingLand = 58, // StateAttackRoot StateStompingPress = 57, // StateAttackRoot StateWallHanging = 91, // StateWallActionRoot StateWallHoming = 93, StateWallJump = 97, StateWallJumpReady = 98, StateWallLanding = 94, // StateWallActionRoot StateWallLeave = 101, StateWallReset = 96, // StateWallActionRoot StateWallRest = 92, // StateWallActionRoot StateWallSlideDown = 95, // StateWallActionRoot StateWallActionRoot = 89, StateWallMove = 90, // StateWallActionRoot SuperSonicStateFingerSnap = 110, } } Library "GameManager" by "Hyper, ĐeäTh & Sajid" { #include "Helpers" noemit #lib "GameObject" #lib "GameService" #lib "Memory" #import "Allocators" #import "Collections" #import "GameApplication" #import "Messages" using System.Runtime.InteropServices; /// /// A struct representation of `hh::game::GameManager`. /// [StructLayout(LayoutKind.Explicit, Size = 0x358)] public struct Data { /// /// An array of pointers to `hh::game::GameObject` instances. /// [FieldOffset(0x130)] public ObjectMoveArray> GameObjects; /// /// An array of pointers to `hh::game::GameService` instances. /// [FieldOffset(0x150)] public ObjectMoveArray> GameServices; /// /// An array of pointers to `hh::game::GameManagerListener` instances. /// [FieldOffset(0x190)] public ObjectMoveArray GameManagerListeners; /// /// An array of pointers to `hh::game::GameObjectListener` instances. /// [FieldOffset(0x1B0)] public ObjectMoveArray GameObjectListeners; /// /// An array of pointers to `hh::game::ComponentListener` instances. /// [FieldOffset(0x1D0)] public ObjectMoveArray ComponentListeners; /// /// An array of pointers to `hh::game::GameStepListener` instances. /// [FieldOffset(0x210)] public ObjectMoveArray GameStepListeners; /// /// An instance of `hh::fnd::MessageQueue`. /// [FieldOffset(0x300)] public MessageQueue MessageQueue; /// /// A pointer to an instance of `app::MyApplication`. /// [FieldOffset(0x350)] public MyApplication* pMyApplication; } /* 0x140C478D8 */ private static long _sigGameManagerSingleton = (long)ScanSignature ( "\x48\x89\x2D\xCC\xCC\xCC\xCC\x8D\x75\x20", "xxx????xxx" ); /// /// Gets an instance of `hh::game::GameManager`. /// /// /// /// /// A pointer to an instance of `hh::game::GameManager`. public Data* Get() { if (_sigGameManagerSingleton == 0) return null; return *(Data**)Memory.ReadEffectiveAddress(_sigGameManagerSingleton); } /// /// Gets an instance of `hh::game::GameService` obtained by the current instance of `hh::game::GameManager` by name. /// /// /// /// /// The name of the instance of `hh::game::GameService` to find. /// A pointer to an instance of `hh::game::GameService`. public GameService.Data* GetService(string in_name) { var pGameManager = Get(); if (pGameManager == null) return null; var gameServices = pGameManager->GameServices; for (int i = 0; i < gameServices.Length; i++) { var pGameService = gameServices[i].pData; if (pGameService->pStaticClass->Name == in_name) return pGameService; } return null; } /// /// Gets an instance of `hh::game::GameService` obtained by the current instance of `hh::game::GameManager`. /// /// /// (); /// } /// ]]> /// /// A pointer to an instance of `hh::game::GameService`. public T* GetService() where T : unmanaged { var name = Helpers.GetInternalName(typeof(T)); return (T*)GetService(string.IsNullOrEmpty(name) ? typeof(T).Name : name); } /// /// Gets an instance of `hh::game::GameObject` obtained by the current instance of `hh::game::GameManager` by name. /// /// /// /// /// The name of the instance of `hh::game::GameObject` to find. /// A pointer to an instance of `hh::game::GameObject`. public GameObject.Data* GetGameObject(string in_name) { var pGameManager = Get(); if (pGameManager == null) return null; var gameObjects = pGameManager->GameObjects; for (int i = 0; i < gameObjects.Length; i++) { var pGameObject = gameObjects[i].pData; if (pGameObject->Name == in_name) return pGameObject; } return null; } /// /// Gets an instance of `hh::game::GameObject` obtained by the current instance of `hh::game::GameManager`. /// /// /// ("Sonic"); /// } /// ]]> /// /// A pointer to an instance of `hh::game::GameObject`. public T* GetGameObject() where T : unmanaged { var name = Helpers.GetInternalName(typeof(T)); return (T*)GetGameObject(string.IsNullOrEmpty(name) ? typeof(T).Name : name); } } Library "GameMode" by "Hyper" { #include "Helpers" noemit #lib "GameManager" #lib "GameService" #lib "Memory" #lib "RTTI" #lib "StringMapOperation" #import "Collections" #import "GameApplication" #import "GameModes" using System.Linq; using System.Runtime.InteropServices; private static bool _isInitialised = false; private static sbyte _destinationMode = -1; /// /// A struct representation of `app::game::GameMode`. /// [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct Data { /// /// A pointer to an instance of `hh::game::GameManager`. /// [FieldOffset(0x30)] public GameManager.Data* pGameManager; /// /// An array of pointers to instances of `hh::game::GameService`. /// [FieldOffset(0x90)] public ObjectMoveArray> GameServices; /// /// An array of pointers to instances of `app::game::GameModeExtension`. /// [FieldOffset(0xB0)] public ObjectMoveArray> Extensions; /// /// Gets the name of this `app::game::GameMode` instance via runtime info. /// /// The name of this `app::game::GameMode` instance. public string GetName() { fixed (Data* pThis = &this) { var namespaces = RTTI.GetClassNamespaces(pThis); return namespaces.Length <= 0 ? "GameModeUnknown" : namespaces.Last(); } } /// /// Gets an instance of `app::game::GameModeExtension` by name. /// /// The name of the extension. /// The requested extension by name. public GameModeExtension* GetExtension(string in_extensionName) { foreach (var pExtension in Extensions) { if (pExtension.pData->GetNameHash()() == StringMapOperation.ComputeHash(in_extensionName)) return pExtension.pData; } return null; } MAKE_GENERIC_API(GetExtension) } [LibraryInitializer] public void Init() { if (_isInitialised) return; fixed (sbyte* p_destinationMode = &_destinationMode) { // Set if we're entering Cyber Space from Training Simulator. WriteAsmHook ( $@" mov rax, {(long)p_destinationMode} mov byte ptr [rax], 1 mov rax, [rdi + 0x10] movaps xmmword ptr [rdi + 0x110], xmm0 mov rdx, [rax + 0x70] ", /* 0x140170517 */ ScanSignature ( "\x48\x8B\x47\x10\x0F\x29\x87\x10\x01\x00\x00", "xxxxxxxxxxx" ), HookBehavior.Replace ); // Set if we're returning to an island from Training Simulator after quitting Cyber Space. WriteAsmHook ( $@" movups xmm0, xmmword ptr [rsp + 0x210 + 0xFFFFFFFFFFFFFE10] mov qword ptr [rbp + 0x110 + 0xFFFFFFFFFFFFFFA0], rax mov word ptr [rdi + 0x120], 0x101 mov rax, {(long)p_destinationMode} mov byte ptr [rax], 0 ", /* 0x14016E547 */ ScanSignature ( "\x0F\x10\x44\x24\x20\x48\x89\x85\xB0\x00\x00\x00\x66\xC7\x87\x20\x01\x00\x00\x01\x01", "xxxxxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); // Set if we're returning to an island from Training Simulator after completing Cyber Space. WriteAsmHook ( $@" mov rbx, {TO_STRING_PTR("w6d01")} lea rcx, qword ptr [rbx] mov rax, {(long)p_destinationMode} mov byte ptr [rax], 0 xor ebx, ebx mov edx, ebx ", /* 0x14016E310 */ ScanSignature ( "\x33\xDB\x48\x8D\x0D\xCC\xCC\xCC\xCC\x8B\xD3", "xxxxx????xx" ), HookBehavior.Replace ); } _isInitialised = true; } [LibraryUpdate] public void Update() { if (GetName() != "GameModeTutorial") _destinationMode = (sbyte)DestinationMode.Unknown; } /// /// Gets the current instance of `app::game::GameMode`. /// /// The current instance of `app::game::GameMode`. public Data* GetCurrentGameMode() { var pGameManager = GameManager.Get(); if (pGameManager == null) return null; var pMyApplication = pGameManager->pMyApplication; if (pMyApplication == null) return null; var pApplicationSequenceExtension = pMyApplication->GetApplicationExtension(); if (pApplicationSequenceExtension == null) return null; var pGameMode = pApplicationSequenceExtension->pGameMode; if (pGameMode == null) return null; return pGameMode; } public Data* Get(string in_gameModeName) { if (in_gameModeName != GetName()) return null; return GetCurrentGameMode(); } MAKE_GENERIC_API(Get) /// /// Gets the name of the current instance of `app::game::GameMode`. /// /// The name of the current instance of `app::game::GameMode`. public string GetName() { var pGameMode = GetCurrentGameMode(); if (pGameMode == null) return "GameModeUnknown"; return pGameMode->GetName(); } /// /// Gets the destination game mode when transitioning out of `GameModeTutorial` (Training Simulator). /// /// The destination game mode represented by the `DestinationMode` enum. public DestinationMode GetTutorialDestination() { return (DestinationMode)_destinationMode; } /// /// An enum containing known destination game modes from `GameModeTutorial` (Training Simulator). /// public enum DestinationMode : sbyte { /// /// The destination game mode has not been set. /// Unknown = -1, /// /// The destination game mode is `GameModeStage` (Island). /// GameModeStage, /// /// The destination game mode is `GameModeCyberStage` (Cyber Space). /// GameModeCyberStage } } Library "PlayerCollision" by "Hyper" { using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x1490, Pack = 0x10)] public struct Data { [FieldOffset(0x94)] public uint CollisionFlags; } } Library "Time" by "Hyper" { #lib "DeltaTime" #lib "Logger" using System.Collections.Generic; private static bool _isInitialised = false; private static float* _pFrameRate; private static Dictionary _timers = new(); public class Timer { public string Name; public float Time; public bool IsEnabled; public Timer(string in_name, float in_time, bool in_isEnabled) { Name = in_name; Time = in_time; IsEnabled = in_isEnabled; } public override string ToString() => $"{Name} | {Time}"; } [LibraryUpdate] public void Update() { foreach (var entry in _timers) { if (entry.Value.IsEnabled) entry.Value.Time += GetDeltaTime(); } } /// /// Gets the current frame rate. /// /// The current frame rate. public float GetFrameRate(bool in_isRounded = true) { return DeltaTime.GetFrameRate(in_isRounded); } /// /// Gets the current frame delta. /// /// The current delta time. public float GetDeltaTime(bool in_isAverage = false) { return in_isAverage ? DeltaTime.GetDeltaTimeAverage() : DeltaTime.GetDeltaTime(); } /// /// Creates a timer. /// /// The name of the timer. /// Determines whether the timer should start upon creation. /// The elapsed time of the requested timer. public float CreateTimer(string in_name, bool in_isEnabled = true) { if (_timers.ContainsKey(in_name)) return _timers[in_name].Time; _timers.Add(in_name, new Timer(in_name, 0.0f, in_isEnabled)); return 0.0f; } /// /// Destroys a timer. /// /// The name of the timer. public void DestroyTimer(string in_name) { if (!_timers.ContainsKey(in_name)) return; _timers.Remove(in_name); } /// /// Gets the value of a timer. /// /// The name of the timer. /// The elapsed time of the requested timer. public float GetTimer(string in_name) { if (!_timers.ContainsKey(in_name)) { Logger.Error($"[Time] Timer \"{in_name}\" does not exist!"); return 0.0f; } return _timers[in_name].Time; } /// /// Sets the value of a timer. /// /// The name of the timer. /// The elapsed time to set. public void SetTimer(string in_name, float in_value) { if (!_timers.ContainsKey(in_name)) { Logger.Error($"[Time] Timer \"{in_name}\" does not exist!"); return; } _timers[in_name].Time = in_value; } /// /// Sets the value of a timer. /// /// The name of the timer. /// Determines whether the timer should be running. public void SetTimer(string in_name, bool in_isEnabled) { if (!_timers.ContainsKey(in_name)) { Logger.Error($"[Time] Timer \"{in_name}\" does not exist!"); return; } _timers[in_name].IsEnabled = in_isEnabled; } /// /// Sets the values of a timer. /// /// The name of the timer. /// The elapsed time to set. /// Determines whether the timer should be running. public void SetTimer(string in_name, float in_value, bool in_isEnabled) { SetTimer(in_name, in_value); SetTimer(in_name, in_isEnabled); } /// /// Resets a timer. /// /// The name of the timer. public void ResetTimer(string in_name) { SetTimer(in_name, 0.0f); } } Library "Reflection" by "Hyper" { #include "BlackboardStatus" noemit #lib "Bitwise" #lib "BlackboardStatus" #lib "Resources" #lib "SonicParameters" /// /// Gets a parameter from the specified hierarchy. /// /// /// /// /// An instance of `ReflectionInfo`. /// The hierarchy to get the reflection data from. /// A value pertaining to the data stored at the requested hierarchy. #define RFL_GET_PARAM(in_info, in_hierarchy) in_info.pData->in_hierarchy /// /// Sets a parameter at the specified hierarchy. /// /// /// /// /// An instance of `ReflectionInfo`. /// The hierarchy to get the reflection data from. /// The value to set the data at the specified hierarchy to. #define RFL_SET_PARAM(in_info, in_hierarchy, in_value) in_info.pData->in_hierarchy = in_value /// /// Resets a parameter back to default at the specified hierarchy. /// /// /// /// /// An instance of `ReflectionInfo`. /// The reflection struct type. /// The hierarchy to get the reflection data from. #define RFL_RESET_PARAM(in_info, in_type, in_hierarchy) in_info.pData->in_hierarchy = ((in_type)Reflection.GetOriginalData(in_info.Name)).in_hierarchy /// /// Gets a parameter from the specified hierarchy in the current contextual mode package. /// /// /// /// /// An instance of `ReflectionInfo`. /// The hierarchy to get the reflection data from. /// A value pertaining to the data stored at the requested hierarchy. #define RFL_GET_CONTEXTUAL_PLAYER_PARAM(in_info, in_hierarchy) \ (Player.Status.IsSideView() \ ? in_info.pData->cyberspaceSV.in_hierarchy \ : (BlackboardStatus.Get() != null && BlackboardStatus.Get()->WorldFlags[(int)BlackboardStatus.WorldFlags.IsCyberSpace >> 6].Test((ulong)BlackboardStatus.WorldFlags.IsCyberSpace)) \ ? in_info.pData->cyberspace.in_hierarchy \ : in_info.pData->forwardView.in_hierarchy) /// /// Sets a parameter at the specified hierarchy in the current contextual mode package. /// /// /// /// /// An instance of `ReflectionInfo`. /// The hierarchy to get the reflection data from. /// The value to set the data at the specified hierarchy to. #define RFL_SET_CONTEXTUAL_PLAYER_PARAM(in_info, in_hierarchy, in_value) \ if (Player.Status.IsSideView()) \ in_info.pData->cyberspaceSV.in_hierarchy = in_value; \ else if (BlackboardStatus.Get() != null && BlackboardStatus.Get()->WorldFlags[(int)BlackboardStatus.WorldFlags.IsCyberSpace >> 6].Test((ulong)BlackboardStatus.WorldFlags.IsCyberSpace)) \ in_info.pData->cyberspace.in_hierarchy = in_value; \ else \ in_info.pData->forwardView.in_hierarchy = in_value; /// /// Resets a parameter back to default at the specified hierarchy in the current contextual mode package. /// /// /// /// /// An instance of `ReflectionInfo`. /// The reflection struct type. /// The hierarchy to get the reflection data from. #define RFL_RESET_CONTEXTUAL_PLAYER_PARAM(in_info, in_type, in_hierarchy) \ if (Player.Status.IsSideView()) \ in_info.pData->cyberspaceSV.in_hierarchy = ((in_type)Reflection.GetOriginalData(in_info.Name)).cyberspaceSV.in_hierarchy; \ else if (BlackboardStatus.Get() != null && BlackboardStatus.Get()->WorldFlags[(int)BlackboardStatus.WorldFlags.IsCyberSpace >> 6].Test((ulong)BlackboardStatus.WorldFlags.IsCyberSpace)) \ in_info.pData->cyberspace.in_hierarchy = ((in_type)Reflection.GetOriginalData(in_info.Name)).cyberspace.in_hierarchy; \ else \ in_info.pData->forwardView.in_hierarchy = ((in_type)Reflection.GetOriginalData(in_info.Name)).forwardView.in_hierarchy; using System.Collections.Generic; private static bool _isInitialised = false; private static List _rflPointersQueue = new(); private static Dictionary _rflBackups = new(); private static Dictionary _rflPointers = new(); /// /// A class containing basic information pertaining to reflection data. /// public class ReflectionInfo where T : unmanaged { public string Name; public Type Type; public T* pData; public ReflectionInfo(string in_name, T* in_pData) { this.Name = in_name; this.Type = typeof(T); this.pData = in_pData; } public override string ToString() { return $"{Name} : 0x{((IntPtr)pData).ToString("X16")}"; } } [LibraryInitializer] public void Init() { if (_isInitialised) return; long GetReflectionPtr(string in_resourceName, string in_resourceType, long in_pResourceData) { if (in_resourceType != "ResReflection") return in_pResourceData; if (_rflPointersQueue.Contains(in_resourceName)) { long ptr = *(long*)(in_pResourceData + 0x60); if (_rflPointers.ContainsKey(in_resourceName)) { _rflPointers[in_resourceName] = ptr; } else { _rflPointers.Add(in_resourceName, ptr); } } return in_pResourceData; } Resources.AddResourceDataAction(GetReflectionPtr); _isInitialised = true; } /// /// Gets a pointer to a struct pertaining to the reflection data. /// /// The name of the reflection data to wait for. /// A pointer to a struct pertaining to the reflection data. public T* GetDataPtr(string in_rflName) where T : unmanaged { if (!_rflPointersQueue.Contains(in_rflName)) _rflPointersQueue.Add(in_rflName); if (!_rflPointers.ContainsKey(in_rflName)) return null; long ptr = _rflPointers[in_rflName]; if (ptr == 0) return null; // Check for BINA signature. if (*(int*)(ptr - 0x40) != 0x414E4942) return null; var result = (T*)ptr; if (result != null && !_rflBackups.ContainsKey(in_rflName)) _rflBackups.Add(in_rflName, *result); return result; } /// /// Gets information about the requested reflection data. /// /// The name of the reflection data to wait for. /// A `ReflectionInfo` class containing the name, type and pointer to the reflection data. public ReflectionInfo GetDataInfo(string in_rflName) where T : unmanaged { return new ReflectionInfo(in_rflName, GetDataPtr(in_rflName)); } /// /// Gets the original struct by name for given reflection data (if it was backed up by `GetDataPtr()`). /// /// The name of the reflection data to get. /// A struct pertaining to the original reflection data. public object GetOriginalData(string in_rflName) { if (!_rflBackups.ContainsKey(in_rflName)) return null; return _rflBackups[in_rflName]; } } Library "BlackboardItem" by "Hyper" does "Provides access to `app::player::BlackboardItem` from Sonic Frontiers." { #import "Blackboard" using System.Runtime.InteropServices; /// /// A struct representation of `app::player::BlackboardBattle`. /// [StructLayout(LayoutKind.Explicit, Size = 0x50, Pack = 0x10)] public struct Data { /// /// An instance of `app::player::BlackboardContent`, the base class for `app::player::BlackboardItem`. /// [FieldOffset(0)] public BlackboardContent BlackboardContent; /// /// The maximum amount of rings the player can hold. /// [FieldOffset(0x24)] public int RingCapacity; /// /// The current ring count for the player. /// [FieldOffset(0x28)] public int RingCount; } /// /// Gets an instance of `app::player::BlackboardItem`. /// /// /// /// /// A pointer to an instance of `app::player::BlackboardItem`. public Data* Get() { return (Data*)Blackboard.GetPlayerBlackboardContent("BlackboardItem"); } } Library "Player" by "Hyper, NM, Ahremic, Skyth & Sajid" { #include "BlackboardStatus" noemit #include "Helpers" noemit #lib "BlackboardStatus" #lib "Collections" #lib "GameManager" #lib "GameObject" #lib "MessageManager" #lib "Reflection" #lib "StringMapOperation" #lib "VectorHelpers" #lib "Sonic" #lib "SonicParameters" #lib "Amy" #lib "AmyParameters" #lib "Knuckles" #lib "KnucklesParameters" #lib "Tails" #lib "TailsParameters" #import "GOComponents" #import "Messages" #import "Objects" #import "Plugins" #import "Postures" #import "Services" #import "States" #load "System.Numerics.dll" using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Runtime.InteropServices; private static bool _isInitialised = false; private static float _grindStepRadius = 0.0f; /// /// A struct representation of `app::player::Player`. /// [StructLayout(LayoutKind.Explicit, Size = 0x2F0, Pack = 0x10)] public struct Data { /// /// An instance of `hh::game::GameObject`, the base class for `app::player::Player`. /// [FieldOffset(0)] public GameObject.Data GameObject; /// /// A pointer to an instance of `PlayerHsmContext`. /// [FieldOffset(0x2E0)] public PlayerHsmContext* pContext; } /// /// A struct representation of `app::player::PlayerHsmContext`. /// [StructLayout(LayoutKind.Explicit, Size = 0x88)] public struct PlayerHsmContext { /// /// A pointer to an instance of `app::player::Player`. /// [FieldOffset(0x20)] public Data* pPlayer; /// /// A pointer to an instance of `app::player::BlackboardStatus`. /// [FieldOffset(0x28)] public BlackboardStatus.Data* pBlackboardStatus; /// /// A pointer to an instance of `app::player::GOCPlayerHsm`. /// [FieldOffset(0x38)] public GOCPlayerHsm* pGOCPlayerHsm; /// /// A pointer to an instance of `app::player::GOCPlayerPosture`. /// [FieldOffset(0x40)] public GOCPlayerPosture* pGOCPlayerPosture; /// /// A pointer to an instance of `app::player::PlayerHsmContext::OutOfControlTimerList`. /// [FieldOffset(0x78)] public long pOutOfControlTimerList; /// /// A pointer to an instance of `app::player::PlayerHsmContext::DamagedObjects`. /// [FieldOffset(0x80)] public long pDamagedObjects; } [LibraryInitializer] public void Init() { if (_isInitialised) return; // Always construct app::player::AmyInfo. WriteNop ( /* 0x14091181B */ ScanSignature ( "\x74\x3E\x48\x8B\x07\xBA\xD8\x00\x00\x00", "xxxxxxxxxx" ), 2 ); // Always construct app::player::KnucklesInfo. WriteNop ( /* 0x1409117D0 */ ScanSignature ( "\x74\x47\x48\x8B\x07\xBA\xC0\x00\x00\x00", "xxxxxxxxxx" ), 2 ); // Always construct app::player::TailsInfo. WriteNop ( /* 0x140911785 */ ScanSignature ( "\x74\x47\x48\x8B\x07\xBA\x20\x01\x00\x00", "xxxxxxxxxx" ), 2 ); fixed (float* p_grindStepRadius = &_grindStepRadius) { WriteAsmHook ( $@" mov rcx, {(long)p_grindStepRadius} cmp dword ptr [rcx], 0 je zeroRadius movss xmm1, dword ptr [rcx] jmp exit zeroRadius: movss xmm1, dword ptr [rsp + 0x68 + 0x28] exit: xor ecx, ecx movss dword ptr [rsp + 0x68 + 0xFFFFFFFFFFFFFFE8], xmm1 xorps xmm0, xmm0 mov qword ptr [rsp + 0x68 + 0xFFFFFFFFFFFFFFB8], rcx ", /* 0x1408B3E51 */ ScanSignature ( "\x33\xC9\xF3\x0F\x11\x4C\x24\x50", "xxxxxxxx" ), HookBehavior.Replace ); } _isInitialised = true; } [LibraryUpdate] public void Update() { var pLevelInfo = GameManager.GetService(); if (pLevelInfo == null) return; var pStageData = pLevelInfo->pStageData; if (pStageData == null) return; // Update current stage attributes to include other characters. pStageData->AttributeFlags |= (1 << (int)StageInfo.Attributes.Sonic); pStageData->AttributeFlags |= (1 << (int)StageInfo.Attributes.Amy); pStageData->AttributeFlags |= (1 << (int)StageInfo.Attributes.Knuckles); pStageData->AttributeFlags |= (1 << (int)StageInfo.Attributes.Tails); } public PlayerType GetPlayerType() { var pLevelInfo = GameManager.GetService(); if (pLevelInfo == null) return PlayerType.Unknown; return (PlayerType)pLevelInfo->PlayerInfo[0]->CharacterIndex; } public Data* GetPlayerData() { var pLevelInfo = GameManager.GetService(); if (pLevelInfo == null) return null; return (Data*)MessageManager.GetMessengerFromHandle(pLevelInfo->PlayerInfo[0]->PlayerHandle); } public PlayerHsmContext* GetPlayerContext() { var pPlayer = GetPlayerData(); if (pPlayer == null) return null; return pPlayer->pContext; } public void SetPlayerType(PlayerType in_playerType) { if (in_playerType == PlayerType.Unknown) return; Messages.SendMessageToGameManager(new MsgChangePlayerCharacter(in_playerType)); } public enum PlayerType : sbyte { Unknown = -1, Sonic, Amy, Knuckles, Tails } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static class Animation { /* 0x1408122E0 */ private static long _sigSetAnimation = Memory.ReadCall(ScanSignature("\xE8\xCC\xCC\xCC\xCC\x80\xBD\xB0\x00\x00\x00\x00\x48\x8B\x9C\x24\xB8\x00\x00\x00", "x????xxxxxxxxxxxxxxx")); FUNCTION_PTR(void, fpSetAnimation, _sigSetAnimation, GOCPlayerVisual* in_pGOCPlayerVisual, long in_pAnimationName, byte in_unk1) /* 0x140813140 */ private static long _sigSetAnimationParameter = ScanSignature("\x40\x53\x48\x83\xEC\x30\x48\x8B\x81\x10\x01\x00\x00\x48\x8B\xDA", "xxxxxxxxxxxxxxxx"); FUNCTION_PTR(void, fpSetAnimationParameter, _sigSetAnimationParameter, GOCPlayerVisual* in_pGOCPlayerVisual, long in_pParameterName, float in_value) public static void SetAnimation(string in_animationName) { var pPlayer = GetPlayerData(); if (pPlayer == null) return; var pGOCPlayerVisual = GameObject.GetGOC(&pPlayer->GameObject); if (pGOCPlayerVisual == null) return; GET_FUNCTION_PTR(fpSetAnimation)(pGOCPlayerVisual, TO_STRING_PTR(in_animationName), 0xFE); } public static void SetAnimationParameter(string in_parameterName, float in_value) { var pPlayer = GetPlayerData(); if (pPlayer == null) return; var pGOCPlayerVisual = GameObject.GetGOC(&pPlayer->GameObject); if (pGOCPlayerVisual == null) return; GET_FUNCTION_PTR(fpSetAnimationParameter)(pGOCPlayerVisual, TO_STRING_PTR(in_parameterName), in_value); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public enum CollisionType : byte { Default, Damage = 2, DamageHoming = 3 } public static class Collision { /* 0x14086A0B0 */ private static long _sigGetStatePluginCollision = ScanSignature("\x40\x56\x48\x83\xEC\x20\x48\x8B\x41\x38\x48\x8B\xB0\x08\x01\x00\x00\x48\x85\xF6\x74\x65\x48\x8B\x46\x20\x48\x89\x5C\x24\x30\x48\x8B\x5E\x18\x48\x89\x7C\x24\x38\x48\x8D\x3C\xC3\x48\x3B\xDF\x74\x19\x48\x8B\x0B\x48\x8B\x01\xFF\x50\xCC\x3D\x8E\xB4\x47\x3B", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx?xxxxx"); FUNCTION_PTR(long, fpGetStatePluginCollision, _sigGetStatePluginCollision, PlayerHsmContext* in_pPlayerHsmContext) /* 0x1408ED200 */ private static long _sigSetCollisionSphere = ScanSignature("\x40\x53\x48\x83\xEC\x50\x0F\x28\x05\xCC\xCC\xCC\xCC\x48\x8B\xD9\x88\x54\x24\x20", "xxxxxxxxx????xxxxxxx"); FUNCTION_PTR(long, fpSetCollisionSphere, _sigSetCollisionSphere, long in_pStatePluginCollision, CollisionType in_type, float in_radius) /* 0x14BB87C00 */ private static long _sigSetEntityCollision = ScanSignature("\x40\x53\x48\x83\xEC\x20\x48\x8B\x41\x50\x0F\xB6\xDA", "xxxxxxxxxxxxx"); FUNCTION_PTR(void, fpSetEntityCollision, _sigSetEntityCollision, PlayerHsmContext* in_pPlayerHsmContext, bool in_isEnabled) public static long GetPlugin() { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return 0; return GET_FUNCTION_PTR(fpGetStatePluginCollision)(pPlayerContext); } public static long SetCollisionSphere(CollisionType in_type, float in_radius) { var pStatePluginCollision = GetPlugin(); if (pStatePluginCollision == 0) return 0; return GET_FUNCTION_PTR(fpSetCollisionSphere)(pStatePluginCollision, in_type, in_radius); } public static void SetEntityCollision(bool in_isEnabled) { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return; GET_FUNCTION_PTR(fpSetEntityCollision)(pPlayerContext, in_isEnabled); } public static void SetGrindStepRadius(float in_radius) { _grindStepRadius = in_radius; } public static void ResetGrindStepRadius() { _grindStepRadius = 0.0f; } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static class Effect { /* 0x1408DF420 */ private static long _sigPlayEffect = ScanSignature("\x48\x8B\xC4\x48\x89\x58\x08\x48\x89\x68\x18\x48\x89\x70\x20\x57\x48\x81\xEC\xA0\x00\x00\x00\xF3", "xxxxxxxxxxxxxxxxxxxxxxxx"); FUNCTION_PTR(long, fpPlayEffect, _sigPlayEffect, StatePluginBase* in_pStatePluginEffect, uint in_handleNameHash, long in_pEffectName) /* 0x14B912E80 */ private static long _sigStopEffect = ScanSignature("\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x8B\x41\x30\x48\x8D", "xxxxxxxxxxxxxxxx"); FUNCTION_PTR(long, fpStopEffect, _sigStopEffect, StatePluginBase* in_pStatePluginEffect, uint in_handleNameHash) /* 0x140901E20 */ private static long _sigPlayAnimationEffect = ScanSignature("\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x57\x48\x83\xEC\x20\x48\x8B\xF2\x48\x8B\xF9\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD8", "xxxxxxxxxxxxxxxxxxxxxx????xxx"); FUNCTION_PTR(bool, fpPlayAnimationEffect, _sigPlayAnimationEffect, PlayerHsmContext* in_pPlayerHsmContext, long in_pEffectName) /* 0x14BC65500 */ private static long _sigStopAnimationEffects = ScanSignature("\x40\x53\x48\x83\xEC\x20\x48\x89\xCB\xE8\xCC\xCC\xCC\xCC\x48\x85\xC0", "xxxxxxxxxx????xxx"); FUNCTION_PTR(long, fpStopAnimationEffects, _sigStopAnimationEffects, PlayerHsmContext* in_pPlayerHsmContext) public static void PlayEffect(string in_handleName, string in_effectName) { var pStatePluginEffect = State.GetStatePlugin("StatePluginEffect"); if (pStatePluginEffect == null) return; GET_FUNCTION_PTR(fpPlayEffect)(pStatePluginEffect, StringMapOperation.ComputeHash(in_handleName), TO_STRING_PTR(in_effectName)); } public static void StopEffect(string in_handleName) { var pStatePluginEffect = State.GetStatePlugin("StatePluginEffect"); if (pStatePluginEffect == null) return; GET_FUNCTION_PTR(fpStopEffect)(pStatePluginEffect, StringMapOperation.ComputeHash(in_handleName)); } public static void PlayAnimationEffect(string in_name) { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return; GET_FUNCTION_PTR(fpPlayAnimationEffect, _sigPlayAnimationEffect)(pPlayerContext, TO_STRING_PTR(in_name)); } public static void StopAnimationEffects() { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return; GET_FUNCTION_PTR(fpStopAnimationEffects)(pPlayerContext); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public enum InputActionType { PlayerJump = 0, // A PlayerCyloop = 1, // Y PlayerAttack = 2, // X PlayerLightDash = 3, // LS PlayerBoost = 4, // RT PlayerDrift = 5, // Unknown PlayerChangeSuperSonic = 6, // Unknown PlayerLeftStep = 7, // LB PlayerRightStep = 8, // RB PlayerStomping = 9, // B PlayerAction = 10, // Unknown PlayerActionAlways = 11, // Unknown PlayerSmash = 12, // Unknown CameraGaze = 13, // RS PlayerSonicboom = 14 // LT } public static class Input { private enum ButtonState { Pressed, Down, Released } UNMANAGED_FUNCTION_DELEGATE(bool, TInputCommonDelegate, PlayerHsmContext* in_pPlayerHsmContext, InputActionType in_actionType) /* 0x1409C80D0 */ private static long _sigIsPressed = ScanSignature ( "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x63\xFA\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD8\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x48\x8B\x5C\x24\x30\x48\x8B\x80\x90\x00\x00\x00\x48\x8B\x48\x78\x0F\xB6\x44\xF9\x07\xD0", "xxxxxxxxxxxxxx????xxxx????xxxxxxx????xxxxxxxxxxxxxxxxxxxxxx" ); /* 0x1409C82A0 */ private static long _sigIsDown = ScanSignature ( "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x63\xFA\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD8\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x48\x8B\x5C\x24\x30\x48\x8B\x80\x90\x00\x00\x00\x48\x8B\x48\x78\x0F\xB6\x44\xF9\x07\xF6", "xxxxxxxxxxxxxx????xxxx????xxxxxxx????xxxxxxxxxxxxxxxxxxxxxx" ); /* 0x1409C8250 */ private static long _sigIsReleased = ScanSignature ( "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x63\xFA\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD8\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x48\x8B\x5C\x24\x30\x48\x8B\x80\x90\x00\x00\x00\x48\x8B\x48\x78\x0F\xB6\x44\xF9\x07\xC0", "xxxxxxxxxxxxxx????xxxx????xxxxxxx????xxxxxxxxxxxxxxxxxxxxxx" ); private static bool CheckButtonState(ButtonState in_buttonState, InputActionType in_actionType) { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return false; long ptr = 0; switch (in_buttonState) { case ButtonState.Pressed: ptr = _sigIsPressed; break; case ButtonState.Down: ptr = _sigIsDown; break; case ButtonState.Released: ptr = _sigIsReleased; break; } if (ptr == 0) return false; return CREATE_UNMANAGED_FUNCTION_PTR(TInputCommonDelegate, ptr)(pPlayerContext, in_actionType); } public static bool IsPressed(InputActionType in_actionType) { return CheckButtonState(ButtonState.Pressed, in_actionType); } public static bool IsDown(InputActionType in_actionType) { return GetPlayerContext() == null ? false : !CheckButtonState(ButtonState.Down, in_actionType); } public static bool IsReleased(InputActionType in_actionType) { return CheckButtonState(ButtonState.Released, in_actionType); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static class Kinematics { public static GOCPlayerKinematicParams* Get() { var pPlayer = GetPlayerData(); if (pPlayer == null) return null; return GameObject.GetGOC(&pPlayer->GameObject); } public static Vector3 GetForward() { var kinematics = Get(); if (kinematics == null) return Vector3.Zero; return VectorHelpers.GetForward(kinematics->Rotation); } public static float GetMagnitude() { var kinematics = Get(); if (kinematics == null) return 0.0f; return VectorHelpers.GetMagnitude(kinematics->Velocity); } public static float GetHorizontalMagnitude() { var kinematics = Get(); if (kinematics == null) return 0.0f; return VectorHelpers.GetHorizontalMagnitude(kinematics->Velocity); } public static float GetVerticalMagnitude() { var kinematics = Get(); if (kinematics == null) return 0.0f; return VectorHelpers.GetVerticalMagnitude(kinematics->Velocity); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static class Message { private static bool _isInitialised = false; private static int _currentMessageID = -1; private static void Init() { if (_isInitialised) return; fixed (int* p_currentMessageID = &_currentMessageID) { WriteAsmHook ( $@" mov eax, [rdx + 8] mov r14, {(long)p_currentMessageID} mov dword ptr [r14], eax mov r14, rdx movaps xmmword ptr [rsp + 0x260 + 0xFFFFFFFFFFFFFFD0], xmm6 ", /* 0x140864C1B */ ScanSignature ( "\x8B\x42\x08\x4C\x8B\xF2\x0F\x29\xB4\x24\x30\x02\x00\x00", "xxxxxxxxxxxxxx" ), HookBehavior.Replace ); } _isInitialised = true; } public static int GetMessageID() { Init(); return _currentMessageID; } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static class Posture { public static PlayerPosture* GetPosture(string in_postureName) { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return null; var pGOCPlayerPosture = pPlayerContext->pGOCPlayerPosture; if (pGOCPlayerPosture == null) return null; var pPostureMoveManager = pGOCPlayerPosture->pPostureMoveManager; if (pPostureMoveManager == null) return null; return pPostureMoveManager->GetPlayerPosture(in_postureName); } MAKE_STATIC_GENERIC_API(GetPosture) } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static class Sound { /* 0x140AE69F0 */ private static long _sigPlaySound = ScanSignature("\x4C\x8B\xDC\x49\x89\x5B\x08\x57\x48\x81\xEC\x80\x00\x00\x00", "xxxxxxxxxxxxxxx"); FUNCTION_PTR(int*, fpPlaySound, _sigPlaySound, GOComponent* in_pGOCSound, int* in_pUnk1, long in_pSoundName, float in_unk2) /* 0x1405A90FF */ private static long _sigStopSound = Memory.ReadCall(ScanSignature("\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCF\xE8\xCC\xCC\xCC\xCC\x33\xD2\x48\x8B\xCF\xF3\x0F\x10\x90\x90\x00\x00\x00", "x????xxxx????xxxxxxxxxxxxx")); FUNCTION_PTR(int*, fpStopSound, _sigStopSound, int* in_pSoundHandle) /* 0x14BC4BA20 */ private static long _sigPlayVoice = ScanSignature("\x48\x89\x74\x24\x10\x57\x48\x83\xEC\x20\x49\x63\xC0", "xxxxxxxxxxxxx"); FUNCTION_PTR(long, fpPlayVoice, _sigPlayVoice, uint* in_pStringHash, PlayerHsmContext* in_pPlayerHsmContext, int in_index) public static int PlaySound(string in_soundName) { var pPlayer = GetPlayerData(); if (pPlayer == null) return 0; var pGOCSound = GameObject.GetGOC(&pPlayer->GameObject, "GOCSound"); if (pGOCSound == null) return 0; int zero = 0; return *(GET_FUNCTION_PTR(fpPlaySound)(pGOCSound, &zero, TO_STRING_PTR(in_soundName), 0.0f)); } public static void StopSound(int* in_pSoundHandle) { GET_FUNCTION_PTR(fpStopSound)(in_pSoundHandle); } public static void PlayVoice(int in_index) { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return; // voice uint hash = 0x6B2E132; GET_FUNCTION_PTR(fpPlayVoice)(&hash, pPlayerContext, in_index); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static class State { private static bool _isInitialised = false; private static Dictionary> _discardedStates = new() { { PlayerType.Sonic, new() }, { PlayerType.Amy, new() }, { PlayerType.Knuckles, new() }, { PlayerType.Tails, new() } }; private static Dictionary> _redirectedStates = new() { { PlayerType.Sonic, new() }, { PlayerType.Amy, new() }, { PlayerType.Knuckles, new() }, { PlayerType.Tails, new() } }; private static int _currentStateID = -1; private static Collections.StackList _stateStackTrace = new(10); public delegate T TStateNotifyAction(T in_stateId, T[] in_stateStackTrace); private static List _stateNotifyActions = new(); /* 0x140802400 */ private static long _sigSetState = ScanSignature("\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x57\x48\x83\xEC\x20\x48\x8B\xD9\x41\x8B\xF8\x48\x81\xC1\x88\x00\x00\x00\x8B\xF2\xE8\xCC\xCC\xCC\xCC\x3B", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx????x"); FUNCTION_PTR(void, fpSetState, _sigSetState, GOCPlayerHsm* in_pGOCPlayerHsm, int in_stateId, int in_unk1) /* 0x14091ED60 */ private static long _sigAddStateParameter = ScanSignature("\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x10\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x41\x56\x48\x83\xEC\x20\x48\x8B\x02\x48\x8B\xE9", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); FUNCTION_PTR(void, fpAddStateParameter, _sigAddStateParameter, PlayerStateParameter* in_pPlayerStateParameter, long in_pStateParameter) UNMANAGED_FUNCTION(int, SetStateID, int in_stateId) { if (in_stateId != -1) { _stateStackTrace.Push(_currentStateID); _currentStateID = in_stateId; } foreach (var action in _stateNotifyActions) in_stateId = (int)action.DynamicInvoke(_currentStateID, _stateStackTrace.ToArray()); var playerType = GetPlayerType(); if (_discardedStates[playerType].Contains(in_stateId)) return -2; if (_redirectedStates[playerType].ContainsKey(in_stateId)) return _redirectedStates[playerType][in_stateId]; return in_stateId; } private static void Init() { if (_isInitialised) return; WriteAsmHook ( $@" mov edx, dword ptr [rbx + 0x114] cmp edx, -1 jz exit mov ecx, edx mov rax, {GET_UNMANAGED_FUNCTION_PTR(SetStateID)} call rax mov edx, eax cmp edx, -2 jne exit mov r15, qword ptr [rsp + 0x38 + 0xFFFFFFFFFFFFFFE8] add rsp, 0x28 pop rbp pop rbx ret exit: movzx eax, byte ptr [rbx + 0x11C] ", /* v1.42: 0x1408AB9BD */ ScanSignature ( "\x8B\x93\x14\x01\x00\x00\x83\xFA\xFF", "xxxxxxxxx" ), HookBehavior.Replace ); _isInitialised = true; } public static T GetCurrentStateID() { Init(); return (T)(object)_currentStateID; } public static T GetPreviousStateID(int in_stackIndex = 0) { Init(); return (T)(object)_stateStackTrace.GetItemAt(in_stackIndex); } public static PlayerType GetPlayerTypeFromStateID() { if (typeof(T) == typeof(Amy.StateID)) { return PlayerType.Amy; } else if (typeof(T) == typeof(Knuckles.StateID)) { return PlayerType.Knuckles; } else if (typeof(T) == typeof(Tails.StateID)) { return PlayerType.Tails; } return PlayerType.Sonic; } public static T* GetState() where T : unmanaged { Init(); var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return null; var pGOCPlayerHsm = pPlayerContext->pGOCPlayerHsm; if (pGOCPlayerHsm == null) return null; string name = ((Sonic.StateID)_currentStateID).ToString(); switch (GetPlayerType()) { case PlayerType.Amy: name = ((Amy.StateID)_currentStateID).ToString(); break; case PlayerType.Knuckles: name = ((Knuckles.StateID)_currentStateID).ToString(); break; case PlayerType.Tails: name = ((Tails.StateID)_currentStateID).ToString(); break; } var nameAttr = Helpers.GetInternalName(typeof(T)); if (name != (string.IsNullOrEmpty(nameAttr) ? typeof(T).Name : nameAttr)) return null; return (T*)pGOCPlayerHsm->Hsm.Base.pState; } public static StatePluginBase* GetStatePlugin(string in_pluginName) { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return null; var pStatePluginManager = pPlayerContext->pGOCPlayerHsm->pStatePluginManager; if (pStatePluginManager == null) return null; return pStatePluginManager->GetStatePlugin(in_pluginName); } MAKE_STATIC_GENERIC_API(GetStatePlugin) public static void AddStateParameter(T in_stateParameter) where T : unmanaged { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return; var pPlayerStateParameter = pPlayerContext->pGOCPlayerHsm->pPlayerStateParameter; if (pPlayerStateParameter == null) return; var pMemory = Marshal.AllocHGlobal(Marshal.SizeOf(in_stateParameter)); { Marshal.StructureToPtr(in_stateParameter, pMemory, false); } GET_FUNCTION_PTR(fpAddStateParameter)(pPlayerStateParameter, (long)pMemory); } public static StateParameter* GetStateParameter(string in_parameterName) { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return null; var pPlayerStateParameter = pPlayerContext->pGOCPlayerHsm->pPlayerStateParameter; if (pPlayerStateParameter == null) return null; foreach (var pStateParameter in pPlayerStateParameter->StateParameters) { if (pStateParameter == 0) continue; if (((StateParameter*)pStateParameter)->GetNameHash()() == StringMapOperation.ComputeHash(in_parameterName)) return (StateParameter*)pStateParameter; } return null; } MAKE_STATIC_GENERIC_API(GetStateParameter) public static void AddStateNotifyAction(TStateNotifyAction in_action) { Init(); if (_stateNotifyActions.Contains(in_action)) return; _stateNotifyActions.Add(in_action); } public static void RemoveStateNotifyAction(TStateNotifyAction in_action) { Init(); if (!_stateNotifyActions.Contains(in_action)) return; _stateNotifyActions.Remove(in_action); } public static void Redirect(T in_source, T in_destination) { Init(); var playerType = GetPlayerTypeFromStateID(); var src = (int)(object)in_source; var dest = (int)(object)in_destination; if (_redirectedStates[playerType].ContainsKey(src)) { _redirectedStates[playerType][src] = dest; return; } _redirectedStates[playerType].Add(src, dest); } public static void Discard(T in_source) { Init(); var playerType = GetPlayerTypeFromStateID(); var src = (int)(object)in_source; if (_discardedStates[playerType].Contains(src)) return; _discardedStates[playerType].Add(src); } public static void Restore(T in_source) { Init(); var playerType = GetPlayerTypeFromStateID(); var src = (int)(object)in_source; if (_discardedStates[playerType].Contains(src)) _discardedStates[playerType].Remove(src); if (_redirectedStates[playerType].ContainsKey(src)) _redirectedStates[playerType].Remove(src); } public static void SetState(T in_destination) { var pPlayerContext = GetPlayerContext(); if (pPlayerContext == null) return; GET_FUNCTION_PTR(fpSetState)(pPlayerContext->pGOCPlayerHsm, (int)(object)in_destination, 0); } public static void SetState(T1 in_destination, T2 in_stateParameter) where T2 : unmanaged { AddStateParameter(in_stateParameter); SetState(in_destination); } public static bool IsStateActive(params T[] in_states) { return in_states.Contains(GetCurrentStateID()); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static class Status { public static bool IsGrounded() { var pLevelInfo = GameManager.GetService(); if (pLevelInfo == null) return false; return pLevelInfo->PlayerInfo[0]->IsGrounded; } public static bool IsGroundedSpecial() { return IsGrounded() || IS_STATE_FLAG(IsGrind) || IS_STATE_FLAG(IsSpringJump) || IS_STATE_FLAG(IsWallClimb) || IS_STATE_FLAG(IsWallClimbIdle); } public static bool IsLockOnCursorVisible() { var pUICursor = GameManager.GetGameObject(); if (pUICursor == null) return false; var pGOCTinyFsm = GameObject.GetGOC(&pUICursor->Base); if (pGOCTinyFsm == null) return false; var pUILockonContext = pGOCTinyFsm->GetContext(); if (pUILockonContext == null) return false; return pUILockonContext->pGOCCollider != null; } public static GameObject.Data* GetLockOnTarget() { var pUICursor = GameManager.GetGameObject(); if (pUICursor == null) return null; var pGOCTinyFsm = GameObject.GetGOC(&pUICursor->Base); if (pGOCTinyFsm == null) return null; var pUILockonContext = pGOCTinyFsm->GetContext(); if (pUILockonContext == null) return null; var pGOCCollider = pUILockonContext->pGOCCollider; if (pGOCCollider == null) return null; return pGOCCollider->pGameObject; } public static bool IsSpecialAction() { return IS_STATE_FLAG(IsGrind) || IS_STATE_FLAG(IsDiving) || IS_STATE_FLAG(IsDivingBoost) || IS_STATE_FLAG(IsDrift) || IS_STATE_FLAG(IsWallClimb) || IS_STATE_FLAG(IsWallClimbIdle) || IS_STATE_FLAG(IsBoarding) || IS_STATE_FLAG(IsSpringJump) || IS_WORLD_FLAG(IsDead) || IS_WORLD_FLAG(IsOutOfControl) || IS_WORLD_FLAG(IsAutoRun) || IS_WORLD_FLAG(IsNitroBoost); } public static bool IsDropDashCharge() { var pStateDoubleJump = State.GetState(); if (pStateDoubleJump != null) return pStateDoubleJump->DropDashChargeTimer > 0.0f; var pStateRecoveryJump = State.GetState(); if (pStateRecoveryJump != null) return pStateRecoveryJump->IsDropDashCharge; return false; } public static GOCPlayerParameter.ModePackageType GetModePackageType() { var pPlayer = GetPlayerData(); if (pPlayer == null) return GOCPlayerParameter.ModePackageType.ForwardView; var pGOCPlayerParameter = GameObject.GetGOC(&pPlayer->GameObject); if (pGOCPlayerParameter == null) return GOCPlayerParameter.ModePackageType.ForwardView; return pGOCPlayerParameter->CurrentModePackageType; } public static bool IsSideView() { return GetModePackageType() == GOCPlayerParameter.ModePackageType.SideView; } public static bool IsUnderwater() { return GetModePackageType() == GOCPlayerParameter.ModePackageType.Water; } } } Library "Converse" by "Hyper & RagdollClash" { #include "Helpers" noemit #lib "Memory" #load "System.Xml.dll" #load "System.Xml.Linq.dll" using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; private static bool _isInitialised = false; public enum Language : sbyte { Unknown = -1, English, French, Italian, German, Spanish, Polish, Portuguese, Russian, Japanese, ChineseTraditional, ChineseSimplified, Korean } private static sbyte _language = -1; public class RedirectedString { public string Key { get; set; } public string Value { get; set; } public bool IsRawAttributes { get; set; } public RedirectedString(string in_key, string in_value, bool in_isRawAttributes = false) { Key = in_key; Value = in_value; IsRawAttributes = in_isRawAttributes; } } public class ReplacementString { public string Pattern { get; set; } public string Replacement { get; set; } public bool IsRegex { get; set; } public bool IsRawAttributes { get; set; } public ReplacementString(string in_pattern, string in_replacement, bool in_isRegex = false, bool in_isRawAttributes = false) { Pattern = in_pattern; Replacement = in_replacement; IsRegex = in_isRegex; IsRawAttributes = in_isRawAttributes; } } private static List _redirectedStrings = new(); private static List _replacementStrings = new(); public delegate string TConverseNotifyAction(string in_key, string in_textRaw, string in_textXml); private static Dictionary _converseNotifyActions = new(); UNMANAGED_FUNCTION(long, RedirectString, long in_pCnvrsKey, long in_pCnvrsText, int in_cnvrsTextLength) { var result = string.Empty; var cnvrsKey = string.Empty; var cnvrsText = string.Empty; if (in_pCnvrsKey != 0) cnvrsKey = Marshal.PtrToStringAnsi((nint)in_pCnvrsKey); if (in_pCnvrsText != 0 && in_cnvrsTextLength > 0) result = cnvrsText = Marshal.PtrToStringUni((nint)in_pCnvrsText, in_cnvrsTextLength); foreach (var entry in _redirectedStrings) { if (entry.Key != cnvrsKey) continue; result = entry.IsRawAttributes ? entry.Value : WriteAttributes(entry.Value); } foreach (var entry in _converseNotifyActions) { result = entry.Key(cnvrsKey, result, ReadAttributes(result)); if (!entry.Value) result = WriteAttributes(result); } foreach (var entry in _replacementStrings) { var text = entry.IsRawAttributes ? result : ReadAttributes(result); if (string.IsNullOrEmpty(text)) break; text = entry.IsRegex ? new Regex(entry.Pattern).Replace(text, entry.Replacement) : text.Replace(entry.Pattern, entry.Replacement); result = entry.IsRawAttributes ? text : WriteAttributes(text); } // Fallback for null strings. if (string.IsNullOrEmpty(result)) result = " "; if (result != cnvrsText) { var length = result.Length; var buffer = Marshal.AllocHGlobal(sizeof(int) + (length * sizeof(char))); Marshal.WriteInt32(buffer, length); Marshal.Copy(result.ToCharArray(), 0, buffer + sizeof(int), length); return (long)buffer; } return -1L; } UNMANAGED_FUNCTION(void, FreeString, long in_pCnvrsText) { Marshal.FreeHGlobal((nint)in_pCnvrsText); } [LibraryInitializer] public void Init() { if (_isInitialised) return; void ConverseHook(long in_addr) { WriteAsmHook ( $@" mov r8d, dword ptr [rsp + 0x28] ; Converse Text Length mov rdx, qword ptr [rsp + 0x20] ; Converse Text mov rcx, rsi ; Converse Key mov rax, {GET_UNMANAGED_FUNCTION_PTR(RedirectString)} call rax mov rbx, rax ; Preserve result in RBX. ; Check if result is -1 or null, use original string if so. cmp rbx, -1 je original test rbx, rbx jz original mov r8d, dword ptr [rbx] ; Redirected Text Length lea rdx, qword ptr [rbx + 0x04] ; Redirected Text jmp cnvrs original: mov r8d, dword ptr [rsp + 0x28] ; Converse Text Length mov rdx, qword ptr [rsp + 0x20] ; Converse Text cnvrs: mov rcx, qword ptr [rdi + 0x08] ; Allocator push rbx mov rax, {Memory.ReadCall(in_addr + 0x09)} call rax pop rbx ; Check if redirect result is -1, skip free if so. cmp rbx, -1 je exit ; Free redirected string. mov rcx, rbx mov rbx, rax sub rsp, 32 mov rax, {GET_UNMANAGED_FUNCTION_PTR(FreeString)} call rax add rsp, 32 mov rax, rbx ; Restore original result. exit: ", in_addr, HookBehavior.Replace ); } WriteNop ( /* v1.42: 0x14D89049D */ ScanSignature ( "\x0F\x84\xF7\x00\x00\x00\x48\x8D\x8F\xC8\x00\x00\x00", "xxxxxxxxxxxxx" ), 6 ); ConverseHook ( /* v1.42: 0x14D8904D1 */ ScanSignature ( "\x44\x8B\x44\x24\x28\x48\x8B\x4F\x08\xE8\xCC\xCC\xCC\xCC\x48\x89\xC2\x48\x8B\x8F\xF0\x00\x00\x00", "xxxxxxxxxx????xxxxxxxxxx" ) ); WriteNop ( /* v1.42: 0x14D89053A */ ScanSignature ( "\x74\x5E\x44\x8B\x44\x24\x28", "xxxxxxx" ), 2 ); ConverseHook ( /* v1.42: 0x14D89053C */ ScanSignature ( "\x44\x8B\x44\x24\x28\x48\x8B\x4F\x08\xE8\xCC\xCC\xCC\xCC\x48\x89\xC2\x48\x89\xF9", "xxxxxxxxxx????xxxxxx" ) ); fixed (sbyte* p_language = &_language) { /* v1.42: 0x146E3A1CC */ var sig = Memory.ReadCall ( ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x89\xC1\xE8\xCC\xCC\xCC\xCC\x48\x8B\x4C\x24\x30", "x????xxxx????xxxxx" ) ); WriteAsmHook ( $@" mov rax, qword ptr [rcx + 8] movzx ecx, byte ptr [rax + 9] mov rax, {(long)p_language} mov byte ptr [rax], cl mov rax, {Memory.ReadJump(sig + 8)} jmp rax ", sig, HookBehavior.Replace ); } _isInitialised = true; } // Puyo Text Editor XML interoperability. /* References; - https://github.com/nickworonekin/puyo-text-editor/blob/main/src/PuyoTextEditor/Text/CnvrsTextEncoding.cs#L27 - https://github.com/nickworonekin/puyo-text-editor/blob/main/src/PuyoTextEditor/Text/CnvrsTextEncoding.cs#L105 */ /* MIT License Copyright (c) 2021 Nick Woronekin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //////////////////////////////////////////////////////////////////////////////////// public enum AttributeType { Colour = 0xE000, Variable = 0xE001, Image = 0xE005, ColourEnd = 0xE010 } [MethodImpl(MethodImplOptions.AggressiveInlining)] private ushort GetNameLength(ushort in_value) => (ushort)((((in_value & 0x0FF0) >> 4) / 2) - 1); [MethodImpl(MethodImplOptions.AggressiveInlining)] private ushort SetNameLength(int in_value) => (ushort)((((in_value + 1) * 2) << 4) & 0x0FF0); /// /// Creates a "colour" tag. /// /// The name of this colour. /// The value of this colour. /// The text to colour. public string Colour(string in_name, uint in_argb, string in_text) => $"{in_text}"; // Alias for the Americans. public string Color(string in_name, uint in_argb, string in_text) => Colour(in_name, in_argb, in_text); /// /// Creates a "var" tag. /// /// The name of the internal variable to display. public string Variable(string in_name) => $""; /// /// Creates an "image" tag. /// /// The name of the image to display. public string Image(string in_name) => $""; /// /// Parses binary Converse attributes and replaces them with XML keys that are interoperable with Puyo Text Editor. /// /// The Unicode string containing binary Converse attributes. /// The input string where known binary Converse attributes are replaced with XML keys. public string ReadAttributes(string in_text) { if (string.IsNullOrEmpty(in_text)) return in_text; var result = new StringBuilder(); for (int i = 0; i < in_text.Length; i++) { var c = in_text[i]; switch ((AttributeType)(c & 0xF00F)) { case AttributeType.Colour: { // End if ((AttributeType)c == AttributeType.ColourEnd) { result.Append(""); break; } i++; var nameLength = GetNameLength(c) - 2; var argb = (uint)(in_text[i] << 16 | (in_text[i + 1])); i += 2; var name = in_text.Substring(i, nameLength); result.Append($""); i += nameLength; break; } case AttributeType.Variable: { i++; var nameLength = GetNameLength(c); var name = in_text.Substring(i, nameLength); result.Append($""); i += nameLength; break; } case AttributeType.Image: { i++; var nameLength = GetNameLength(c); var name = in_text.Substring(i, nameLength); result.Append($""); i += nameLength; break; } default: result.Append(c); break; } } return result.ToString(); } /// /// Encodes XML Converse attributes back into their binary form. /// /// The Unicode string containing XML Converse attributes. /// The current XML element - used for recursion. /// The input string where XML Converse attributes are replaced with known binary attributes. public string WriteAttributes(string in_text, XElement in_element = null) { if (string.IsNullOrEmpty(in_text)) return in_text; var result = new StringBuilder(); var root = in_element ?? XElement.Parse($"{in_text}"); foreach (var node in root.Nodes()) { if (node is XElement eNode) { switch (eNode.Name.LocalName) { case "color": case "colour": { var name = eNode.Attribute("name").Value; var argb = uint.Parse(eNode.Attribute("value").Value, NumberStyles.HexNumber); result.Append((char)(ushort)(0xE000 | SetNameLength(name.Length + 2))); result.Append((char)(ushort)(argb >> 16)); result.Append((char)(ushort)(argb & 0xFFFF)); result.Append(name.ToCharArray()); result.Append('\0'); result.Append(WriteAttributes(in_text, eNode)); result.Append((char)(ushort)0xE010); break; } case "var": { var name = eNode.Attribute("name").Value; result.Append((char)(ushort)(0xE001 | SetNameLength(name.Length))); result.Append(name.ToCharArray()); result.Append('\0'); break; } case "image": { var name = eNode.Attribute("name").Value; result.Append((char)(ushort)(0xE005 | SetNameLength(name.Length))); result.Append(name.ToCharArray()); result.Append('\0'); break; } } } else if (node is XText tNode) { result.Append(tNode.Value.ToCharArray()); } } return result.ToString(); } /// /// Determines whether a char is a binary Converse attribute. /// /// The char suspected of containing a binary Converse attribute. /// A boolean representation of whether the input char is a binary Converse attribute. public bool IsAttribute(char in_char) { var attributes = ((AttributeType[])Enum.GetValues(typeof(AttributeType))).ToList(); foreach (var attribute in attributes) { if ((char)attribute == in_char) return true; } return false; } /// /// Omits binary Converse attributes from a Unicode string. /// /// The Unicode string containing binary Converse attributes. /// The input string where binary Converse attributes are removed. public string OmitAttributes(string in_text) { var result = new StringBuilder(); var chars = in_text.ToCharArray(); for (int i = 0; i < chars.Length; i++) { var c = chars[i]; if (IsAttribute(c)) continue; result.Append(c); } return result.ToString(); } //////////////////////////////////////////////////////////////////////////////////// /// /// Gets the current language being used by the game. /// /// The current language of the game represented by the Language enum. public Language GetCurrentLanguage() { return (Language)_language; } /// /// Registers a function of the `TConverseNotifyAction` type into the event handler for when Converse strings are loaded. /// /// The delegate to add. /// Determines whether the delegate should receive the Converse string with binary attributes. public void AddConverseNotifyAction(TConverseNotifyAction in_action, bool in_isRawAttributes = false) { if (_converseNotifyActions.ContainsKey(in_action)) { _converseNotifyActions[in_action] = in_isRawAttributes; return; } _converseNotifyActions.Add(in_action, in_isRawAttributes); } /// /// Removes a function of the `TConverseNotifyAction` type. /// /// The delegate to remove. public void RemoveConverseNotifyAction(TConverseNotifyAction in_action) { if (!_converseNotifyActions.ContainsKey(in_action)) return; _converseNotifyActions.Remove(in_action); } /// /// Redirects a string belonging to a specific key to a custom string (this will create a new string if the key does not exist). /// /// The Converse key to redirect to a new string. /// The string to display when the requested string is used by the game. /// Determines whether the redirected string contains binary Converse attributes. public void Redirect(string in_key, string in_text, bool in_isRawAttributes = false) { if (string.IsNullOrEmpty(in_key)) return; var first = _redirectedStrings.FirstOrDefault(x => x.Key == in_key); if (first != null) { first.Value = in_text; first.IsRawAttributes = in_isRawAttributes; return; } _redirectedStrings.Add(new RedirectedString(in_key, in_text, in_isRawAttributes)); } /// /// Redirects a string belonging to a specific key to a custom string (this will create a new string if the key does not exist). /// /// The substring pattern to search for in a Converse string. /// The string to replace the pattern once found. /// Determines whether the pattern uses regular expressions. /// Determines whether the replacement string contains binary Converse attributes. public void Replace(string in_pattern, string in_replacement, bool in_isRegex = false, bool in_isRawAttributes = false) { if (string.IsNullOrEmpty(in_pattern)) return; var first = _replacementStrings.FirstOrDefault(x => x.Pattern == in_pattern); if (first != null) { first.Replacement = in_replacement; first.IsRegex = in_isRegex; first.IsRawAttributes = in_isRawAttributes; return; } _replacementStrings.Add(new ReplacementString(in_pattern, in_replacement, in_isRegex, in_isRawAttributes)); } /// /// Unregisters a redirected key or replacement pattern from the event handler. /// /// The Converse key or replacement pattern to unregister. public void Restore(string in_key) { if (string.IsNullOrEmpty(in_key)) return; _redirectedStrings.RemoveAll(x => x.Key == in_key); _replacementStrings.RemoveAll(x => x.Pattern == in_key); } } Library "Amy" by "Hyper" { /// /// An enum containing all of Amy's state IDs. /// public enum StateID : int { Default = -1, StateAcceleCombo1 = 149, // StateAttackRoot StateAcceleCombo2 = 150, // StateAttackRoot StateAquaBallJump = 121, StateAquaBallStand = 120, StateAquaBallStomping = 122, StateAttackRoot = 134, StateAuraTrain = 191, StateAvoid = 140, StateAvoidLocal = 143, StateAvoidToTarget = 142, StateAvoidUpper = 141, StateAwakening = 27, StateBallMove = 172, StateBaseJump = 102, StateBatterBox = 203, StateBattleStart = 158, StateBoarding = 183, StateBossCounter = 159, StateBrake = 6, StateBrakeNeutral = 7, StateBreathe = 44, StateBumpJump = 16, StateCaught = 167, StateChargeAttack = 151, // StateAttackRoot StateClimbing = 100, StateClimbingEdge = 99, StateCloudJump = 192, StateHomingFinish = 136, // StateAttackRoot StateComboMove = 131, StateComboStep = 132, StateComboWarp = 133, StateCrasher = 153, // StateAttackRoot StateCrossSlash = 155, // StateAttackRoot StateDamage = 29, // StateDamageRoot StateDamageBlowOff = 31, // StateDamageRoot StateDamageBlowOffHeavy = 32, // StateDamageRoot StateDamageLava = 38, StateDamageQuake = 33, // StateDamageRoot StateDamageRoot = 28, StateDamageRunning = 34, // StateDamageRoot StateDamageTurnBack = 30, // StateDamageRoot StateDead = 39, StateDebuff = 180, StateDestination = 188, StateDiving = 79, // StateDivingRoot StateDivingDamage = 81, // StateDivingRoot StateDivingFall = 80, // StateDivingRoot StateDivingRoot = 78, StateDivingSpecial = 84, // StateDivingSpecialRoot StateDivingSpecialDamage = 87, // StateDivingSpecialRoot StateDivingSpecialDashRing = 85, // StateDivingSpecialRoot StateDivingSpecialFall = 86, // StateDivingSpecialRoot StateDivingSpecialPush = 88, // StateDivingSpecialRoot StateDivingSpecialRoot = 83, StateDivingSpring = 82, // StateDivingRoot StateDrift = 111, StateDriftDash = 112, StateDriftAir = 113, StateDropDash = 114, StateFall = 15, StateFallWithKodama = 198, StateFallWithCannonball = 201, StateFallFlip = 21, StateFallingDead = 40, StateFallSlope = 20, StateFan = 171, StateFixedGoal = 128, StateFloat = 108, StateFly = 103, StateFlyLocal = 106, StateFlyLocal2D = 107, StateFlyOnPath = 105, StateFlyTurn = 104, StateGoal = 126, StateGoal2 = 127, StateGrind = 47, // StateGrindRoot StateGrindDamage = 50, // StateGrindRoot StateGrindDamageAir = 51, // StateGrindRoot StateGrindJump = 48, // StateGrindRoot StateGrindDoubleJump = 49, // StateGrindRoot StateGrindRoot = 46, StateGrindStep = 52, StateGuard = 148, StateGuardedFlipBack = 35, // StateDamageRoot StateHangPole = 173, StateHangPoleJump = 174, StateHoldStand = 162, StateHomingAttack = 63, // StateAttackRoot StateHomingAttackRoot = 62, // StateAttackRoot StateHomingAttackInStorm = 64, // StateAttackRoot StateHomingFinished = 65, // StateAttackRoot StateHomingRepelled = 66, StateHomingShot = 156, // StateAttackRoot StateImpactGimmick = 185, StateJump = 8, StateJumpWithKodama = 197, StateJumpBoardLaunch = 170, StateBounceJump = 11, StateRecoveryJump = 12, StateSpringJump = 165, StateSpringJumpHeadLand = 166, StateKickBox = 176, StateLavaDead = 45, StateLeftStep = 72, StateLeftStepRun = 74, PlayerStateLevitation = 215, StateLightDash = 26, StateLoopKick = 152, // StateAttackRoot StateMoveInWarningArea = 189, StateMoveToBatterBox = 204, StateMoveToBossArea = 190, StateMoveToReflexesPanel = 206, StateNoisyGoal = 129, StateOperateConsole = 184, StateParalysis = 37, StateParriedFlipBack = 36, StateParry = 144, StateParryStand = 145, // StateParry StatePipeMove = 168, StatePipeOut = 169, StatePressDead = 43, StatePursuitKick = 135, // StateAttackRoot StatePushBox = 175, StateQuickCyloop = 137, // StateAttackRoot StateQuickStep = 68, // StateQuickStepRoot StateQuickStepCrash = 71, // StateQuickStepRoot StateQuickStepJump = 76, StateQuickStepDoubleJump = 77, StateQuickStepLeft = 69, // StateQuickStepRoot StateQuickStepRight = 70, // StateQuickStepRoot StateQuickStepRoot = 67, StateRecoil = 19, StateRecovery = 164, StateReflexesPanel = 205, StateReflexesPanelLeftStep = 207, StateReflexesPanelRightStep = 208, StateRightStep = 73, StateRightStepRun = 75, StateRun = 4, StateRunWithKodama = 196, StateRunWithCannonball = 199, StateRunawayBee = 194, StateRunningStart = 125, StateSandSki = 177, StateSandSkiBlow = 178, StateSendSignal = 186, StateSleep = 0, StateSliding = 60, // StateSquatRoot StateSlidingToStand = 61, StateSlingshot = 179, StateSmash = 138, // StateAttackRoot StateSmashSS = 139, // StateAttackRoot StateSonicBoomKick = 154, // StateAttackRoot StateSpin = 115, StateSpinAttack = 14, StateSpinBoost = 118, StateSpinBoostCharge = 117, StateSpinMove = 119, StateSpinDash = 116, // StateAttackRoot StateSpinSlash = 157, // StateAttackRoot StateSquat = 18, // StateSquatRoot StateSquatRoot = 17, StateStandRoot = 1, StateStandWithKodama = 195, StateStand = 2, // StateStandRoot StateStandWithCannonball = 200, StateStolenEmerald = 182, StateStorm = 181, StateSuffocatingDead = 42, StateTakeBehind = 146, StateTakeBehindSS = 147, StateTalkMode = 163, StateThrowCannonball = 202, StateTimeUpDead = 130, StateTreadmill = 193, StateTreeJump = 276, StateTurn = 5, StateUpDead = 41, StateUpDownPole = 123, StateUpDownPoleDamage = 124, StateWakeUp = 3, StateWarpEnd = 161, StateWarpStart = 160, StateWaterFall = 187, StateAirBoost = 22, AmyStateTarotBoostAir = 24, // AmyStateTarotBikeRoot StateDoubleJump = 9, StateHighJump = 11, StatePropellerJump = 10, AmyStateStomping = 53, // StateAttackRoot AmyStateStompingBounce = 59, // StateAttackRoot AmyStateStompingDown = 55, // StateAttackRoot AmyStateStompingLand = 58, // StateAttackRoot StateTarotAttack = 237, // StateAttackRoot StateTarotAttack2 = 238, // StateAttackRoot AmyStateTarotRollingRoot = 239, // StateAttackRoot AmyStateTarotRolling = 240, // StateAttackRoot AmyStateTarotRollingJump = 241, // StateAttackRoot AmyStateTarotRollingFall = 242, // StateAttackRoot AmyStateTarotRollingStun = 243, // StateAttackRoot StateCyHammer = 244, // StateAttackRoot StateAirCyHammer = 245, // StateAttackRoot AmyStateTarotBikeRoot = 246, AmyStateTarotBuildRoot = 247, // AmyStateTarotBikeRoot AmyStateTarotBuild = 248, // AmyStateTarotBikeRoot AmyStateTarotBuildAir = 249, // AmyStateTarotBikeRoot AmyStateTarotBuildFall = 250, // AmyStateTarotBikeRoot AmyStateTarotBoostRoot = 251, // AmyStateTarotBikeRoot AmyStateTarotBoost = 252, // AmyStateTarotBikeRoot AmyStateTarotBoostTurn = 253, // AmyStateTarotBikeRoot AmyStateTarotBoostStep = 254, // AmyStateTarotBikeRoot AmyStateTarotBoostJump = 255, // AmyStateTarotBikeRoot AmyStateTarotBoostFall = 256, // AmyStateTarotBikeRoot AmyStateTarotDrift = 257, // AmyStateTarotBikeRoot AmyStateCharmAttack = 258, // StateAttackRoot AmyStateCharmAttackFollow = 259, StatePropellerHover = 260, } } Library "GameObject" by "Hyper, ĐeäTh & Sajid" { #include "Helpers" noemit #import "GameTypes" #import "Collections" #import "GOComponents" #lib "Helpers" #lib "GameManager" #lib "MessageManager" #lib "HandleManagerBase" #lib "Memory" using System.Runtime.InteropServices; /// /// A struct representation of `hh::game::GameObject`. /// [StructLayout(LayoutKind.Explicit, Size = 0x258, Pack = 0x10)] public struct Data : IMessenger { DEFINE_BASE_PROPERTY(void*, Allocator) DEFINE_BASE_PROPERTY(int, RefCount) DEFINE_BASE_PROPERTY(int, Handle) DEFINE_BASE_PROPERTY(MessageManager.Data*, MessageManager) [FieldOffset(0x00)] public Messenger Base; /// /// A pointer to an instance of `app::GameManager`. /// [FieldOffset(0x48)] public GameManager.Data* pGameManager; /// /// The flags for this game object. /// [FieldOffset(0x30)] public byte Flags; /// /// An array of pointers to `hh::game::GOComponent` instances. /// [FieldOffset(0x58)] public ObjectMoveArray> Components; /// /// The name of this game object. /// [FieldOffset(0xB8)] public Helpers.UnmanagedString Name; public override string ToString() => Name.ToString(); /// /// Destroys this game object. /// public void Kill() { Flags |= 1; } } /// /// Gets an instance of `hh::game::GOComponent` obtained by the input `hh::game::GameObject` instance by name. /// /// /// /// /// An instance of `hh::game::GameObject`. /// The name of the instance of `hh::game::GOComponent` to find. /// A pointer to an instance of `hh::game::GOComponent`. public GOComponent* GetGOC(Data* in_pGameObject, string in_name) { if (in_pGameObject == null) return null; var components = in_pGameObject->Components; for (int i = 0; i < components.Length; i++) { var pComponent = components[i].pData; if (pComponent->pStaticClass->Name == in_name) return pComponent; } return null; } /// /// Gets an instance of `hh::game::GOComponent` obtained by the input `hh::game::GameObject` instance. /// /// /// (pSonic); /// } /// ]]> /// /// An instance of `hh::game::GameObject`. /// A pointer to an instance of `hh::game::GOComponent`. public T* GetGOC(Data* in_pGameObject) where T : unmanaged { var name = Helpers.GetInternalName(typeof(T)); return (T*)(long)GetGOC(in_pGameObject, string.IsNullOrEmpty(name) ? typeof(T).Name : name); } } Library "Effects" by "Hyper" { #lib "PlayerEffect" using System.Runtime.InteropServices; /// /// A struct representation of `app::player::PlayerEffectFootSmoke`. /// [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerEffectFootSmoke { /// /// An instance of `app::player::PlayerEffect`, the base class for `app::player::PlayerEffectFootSmoke`. /// [FieldOffset(0)] public PlayerEffect.Data PlayerEffect; /// /// The index of the foot smoke effects to use. /// [FieldOffset(0x4C)] public byte FootSmokeIndex; /// /// Bit flags for this effect. /// [FieldOffset(0x4D)] public byte Flags; } /// /// A struct representation of `app::player::SonicEffectCyloop`. /// [StructLayout(LayoutKind.Explicit, Size = 0xC8)] public struct SonicEffectCyloop { /// /// An instance of `app::player::PlayerEffect`, the base class for `app::player::SonicEffectCyloop`. /// [FieldOffset(0)] public PlayerEffect.Data PlayerEffect; /// /// Determines if the visual model should update locally within `app::player::SonicEffectCyloop` or externally. /// [FieldOffset(0xC0)] public bool IsLocalVisualModelUpdate; } } Library "MessageManager" by "Sajid & Hyper" { #lib "Memory" #lib "HandleManagerBase" #import "Collections" #import "GameTypes" #import "Messages" using System.Runtime.InteropServices; /// /// A struct representation of `hh::fnd::MessageManager`. /// [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct Data { [FieldOffset(0)] public ReferencedObject Base; [FieldOffset(0x20)] public MoveArray> Messages; } /* 0x1525C0FDF */ private static long _sigMessageManagerSingleton = ScanSignature ( "\x48\x8B\x05\xCC\xCC\xCC\xCC\x48\x89\x43\x20", "xxx????xxxx" ); /* 0x152BA6262 */ private static long _sigMessageManagerHandleManagerSingleton = ScanSignature ( "\x48\x89\x05\xCC\xCC\xCC\xCC\x48\x89\xF8", "xxx????xxx" ); public Data* Get() { if (_sigMessageManagerSingleton == 0) return null; return *(Data**)Memory.ReadEffectiveAddress(_sigMessageManagerSingleton); } public HandleManagerBase.Data* GetHandleManager() { if (_sigMessageManagerHandleManagerSingleton == 0) return null; return *(HandleManagerBase.Data**)Memory.ReadEffectiveAddress(_sigMessageManagerHandleManagerSingleton); } public Messenger* GetMessengerFromHandle(int in_handle) { var manager = GetHandleManager(); if (manager == null) return null; return (Messenger*)manager->GetObject(in_handle); } } Library "Services" by "Hyper" { #include "Helpers" noemit #lib "GameManager" #lib "Helpers" #lib "Memory" #lib "PhotoModeParameters" #lib "Resources" #import "Collections" #import "GameTypes" #import "Graphics" #import "SaveData" #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; /// /// A struct representation of `app::camera::CameraService`. /// [StructLayout(LayoutKind.Explicit, Size = 0x1B8)] public struct CameraService { /// /// Determines if the camera is being controlled by the player. /// [FieldOffset(0x1AC)] public bool IsFreeCamera; /// /// Bit flags for the current camera. /// [FieldOffset(0x1AE)] public CameraFlags Flags; [Flags] public enum CameraFlags : short { IsControllable = 0x01 } /// /// A struct representation of `app::camera::CameraService::LockonInfo`. /// [StructLayout(LayoutKind.Explicit, Size = 0x78)] public struct LockonInfo { } } /// /// A struct representation of `app::game::ExpManager`. /// [StructLayout(LayoutKind.Explicit, Size = 0xF0)] public struct ExpManager { /// /// An instance of `hh::game::GameService`, the base class for `app::game::ExpManager`. /// [FieldOffset(0)] public GameService.Data GameService; /// /// The experience data for Sonic. /// [FieldOffset(0x80)] public PlayerData Sonic; /// /// The experience data for Amy. /// [FieldOffset(0x9C)] public PlayerData Amy; /// /// The experience data for Knuckles. /// [FieldOffset(0xB8)] public PlayerData Knuckles; /// /// The experience data for Tails. /// [FieldOffset(0xD4)] public PlayerData Tails; /// /// A struct representation of the experience data for each character. /// [StructLayout(LayoutKind.Sequential)] public struct PlayerData { /// /// The amount of skill pieces being added to the total. /// public int PendingSkillPieces; /// /// The total amount of skill pieces. /// public int TotalSkillPieces; /// /// The total amount of skill points. /// public short TotalSkillPoints; } } /// /// A struct representation of `app::game::GrindService`. /// [StructLayout(LayoutKind.Explicit, Size = 0x1E0)] public struct GrindService { /// /// An instance of `hh::game::GameService`, the base class for `app::game::GrindService`. /// [FieldOffset(0)] public GameService.Data GameService; /// /// Determines whether to show the procedural models for grind rails. /// [FieldOffset(0x1D0)] public bool ShowGrindRails; } /// /// A struct representation of `app::level::LevelInfo`. /// [StructLayout(LayoutKind.Explicit, Size = 0x100)] public struct LevelInfo { /// /// An instance of `hh::game::GameService`, the base class for `app::level::LevelInfo`. /// [FieldOffset(0)] public GameService.Data GameService; /// /// A pointer to an instance of the current `app::level::StageData`. /// [FieldOffset(0x78)] public StageInfo.StageData* pStageData; /// /// An array of pointers to `app::level::PlayerInformation` instances. /// [FieldOffset(0xC8)] UNMANAGED_FIXED_ARRAY(PlayerInformation*, PlayerInfo, 1) /// /// Gets the name ID of the current stage. /// /// The current stage ID. public static string GetCurrentStageID() { var pLevelInfo = GameManager.GetService(); if (pLevelInfo == null) return string.Empty; if (pLevelInfo->pStageData == null) return string.Empty; return pLevelInfo->pStageData->Name.ToString(); } public static bool IsCustomStage() { var pLevelInfo = GameManager.GetService(); if (pLevelInfo == null) return false; if (pLevelInfo->pStageData == null) return false; return pLevelInfo->pStageData->CyberName[1] != '-'; } /// /// A struct representation of `app::level::PlayerInformation`. /// [StructLayout(LayoutKind.Explicit, Size = 0x540, Pack = 0x10)] public struct PlayerInformation { /// /// The handle value for the player object. /// [FieldOffset(0x10)] public int PlayerHandle; /// /// The index of the current player character. /// /// 0 - Sonic /// 1 - Amy /// 2 - Knuckles /// 3 - Tails /// [FieldOffset(0x18)] public byte CharacterIndex; /// /// Determines if the current player is grounded. /// [FieldOffset(0x2EE)] public bool IsGrounded; } } /// /// A struct representation of `hh::fmv::MovieManager`. /// [StructLayout(LayoutKind.Explicit, Size = 0xE8)] public struct MovieManager { /// /// An array of handles to instances of `app::gfx::MoviePlayerObject`. /// [FieldOffset(0x98)] public ObjectMoveArray Handles; public static HandleManagerBase.Data* GetHandleManager() { /* 0x150274D5F */ long sig = ScanSignature ( "\x48\x8B\x0D\xCC\xCC\xCC\xCC\x48\x8B\xD6\xE8\xCC\xCC\xCC\xCC\x38\x5C\x24\x70", "xxx????xxxx????xxxx" ); if (sig == 0) return null; /* 0x143DAB038 */ return *(HandleManagerBase.Data**)Memory.ReadEffectiveAddress(sig); } public static MoviePlayerObject* GetMoviePlayerObjectFromHandle(int in_handle) { var manager = GetHandleManager(); if (manager == null) return null; return (MoviePlayerObject*)manager->GetObject(in_handle); } public MoviePlayer* GetCurrentMoviePlayer() { if (Handles.Length <= 0) return null; var pMoviePlayerObject = GetMoviePlayerObjectFromHandle(Handles[0]); if (pMoviePlayerObject == null) return null; return pMoviePlayerObject->pMoviePlayer; } } /// /// A struct representation of `app::game::PhotoModeService`. /// [StructLayout(LayoutKind.Explicit, Size = 0x1F0, Pack = 0x10)] public struct PhotoModeService { /// /// An instance of `hh::game::GameService`, the base class for `app::game::PhotoModeService`. /// [FieldOffset(0)] public GameService.Data GameService; /// /// A pointer to an instance of `photomode.rfl`. /// [FieldOffset(0x88)] public Resources.Data* pRflPhotoMode; /// /// A pointer to the `PhotoModeParameters` struct from `photomode.rfl`. /// [FieldOffset(0x90)] public PhotoModeParameters.Root* pPhotoModeParameters; /// /// Determines whether Photo Mode is enabled. /// [FieldOffset(0xDC)] public bool IsEnabled; /// /// The index of the current filter applied to the viewport. /// [FieldOffset(0xE0)] public int FilterIndex; } /// /// A struct representation of `app::save::SaveManager`. /// [StructLayout(LayoutKind.Explicit, Size = 0x228)] public struct SaveManager { [FieldOffset(0x70)] public void* pGameStepListener; [FieldOffset(0x78)] public void* pFrameworkNotificationListener; [FieldOffset(0x80)] public void* pUserInfoEventListener; [FieldOffset(0x88)] public void* pStatsListener; [FieldOffset(0xB8)] public SaveInterface* pSaveInterface; } /// /// A struct representation of `app::ScriptSequenceManager`. /// [StructLayout(LayoutKind.Explicit, Size = 0x170)] public struct ScriptSequenceManager { /// /// An instance of `hh::game::GameService`, the base class for `app::ScriptSequenceManager`. /// [FieldOffset(0)] public GameService.Data GameService; /// /// A pointer to the vftable for the inherited `hh::game::GameStepListener`. /// [FieldOffset(0x70)] public long pGameStepListener; /// /// A pointer to the vftable for the inherited `hh::game::SaveManagerListener`. /// [FieldOffset(0x78)] public long pSaveManagerListener; /// /// An array of pointers to instances of `app::ScriptSequence`. /// [FieldOffset(0x80)] public ObjectMoveArray> ScriptSequences; /// /// A pointer to an LPCRITICAL_SECTION. /// [FieldOffset(0xF8)] public long pCriticalSection; /// /// An array of callback functions. /// [FieldOffset(0x120)] public ObjectMoveArray CallbackFunctions; /// /// A pointer to an instance of `script.rfl`. /// [FieldOffset(0x140)] public Resources.Data* pRflScript; /// /// A pointer to an instance of `talk_event_camera_preset.rfl`. /// [FieldOffset(0x150)] public Resources.Data* pRflTalkEventCameraPreset; /// /// A struct representation of `app::ScriptSequence`. /// [StructLayout(LayoutKind.Explicit, Size = 0x250)] public struct ScriptSequence { /// /// A pointer to an instance of `app::ScriptSequenceManager`. /// [FieldOffset(0x38)] public ScriptSequenceManager* pScriptSequenceManager; /// /// A fixed array of instances of `app::game::Script`. /// [FieldOffset(0x48)] UNMANAGED_FIXED_ARRAY(Script*, pScripts, 5) /// /// The name of this sequence. /// [FieldOffset(0x74)] public fixed byte pSequenceName[64]; /// /// The type of overlay being displayed for the current sequence. /// [FieldOffset(0xC0)] public int OverlayType; /// /// The amount of overlay jobs present in the current sequence. /// [FieldOffset(0xC8)] public int OverlayJobCount; /// /// A struct representation of `app::game::Script`. /// [StructLayout(LayoutKind.Explicit, Size = 0xD8)] public struct Script { /// /// A pointer to the Lua state. /// [FieldOffset(0x18)] public long pLuaState; } } /// /// A struct representation of the user data for storing callback functions. /// [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct CallbackData { /// /// The name of this callback function. /// [FieldOffset(0x08)] public Helpers.UnmanagedString Name; /// /// A pointer to the function pertaining to this callback. /// [FieldOffset(0x10)] public long pFunction; public override string ToString() => Name.ToString(); } } /// /// A struct representation of `app::level::StageInfo`. /// [StructLayout(LayoutKind.Explicit, Size = 0xB8)] public struct StageInfo { /// /// An instance of `hh::game::GameService`, the base class for `app::level::StageInfo`. /// [FieldOffset(0)] public GameService.Data GameService; /// /// A pointer to an instance of `app::fnd::AppResourceManagerListener`. /// [FieldOffset(0x70)] public long pAppResourceManagerListener; /// /// An array of pointers to instances of `app::level::StageData`. /// [FieldOffset(0x78)] public ObjectMoveArray> Stages; /// /// A struct representation of `app::level::StageData`. /// [StructLayout(LayoutKind.Explicit, Size = 0x170)] public struct StageData { /// /// The name of this stage. /// [FieldOffset(0x18)] public MoveArray Name; /// /// The name of the scene parameters to use. /// [FieldOffset(0x48)] public MoveArray SceneParamName; /// /// The directory location of this stage. /// [FieldOffset(0x78)] public MoveArray Location; /// /// The name of this Cyber Space stage. /// [FieldOffset(0x90)] public MoveArray CyberName; /// /// The index of this stage. /// [FieldOffset(0xA8)] public int StageIndex; /// /// The index of this Cyber Space stage (used for Arcade Mode). /// [FieldOffset(0xAC)] public int CyberStageIndex; /// /// The index of the world this stage takes place in. /// [FieldOffset(0xB0)] public int WorldIndex; /// /// The index of the default scene parameters to use. /// [FieldOffset(0xB4)] public int DefaultSceneParamIndex; /// /// The attributes of this stage. /// [FieldOffset(0xB8)] public long AttributeFlags; /// /// The missions for this stage. /// [FieldOffset(0xC0)] public long MissionFlags; /// /// The static sector IDs for the terrain instances for this stage. /// [FieldOffset(0xC8)] public ObjectMoveArray StaticSectors; /// /// The dynamic sector IDs for the terrain instances for this stage. /// [FieldOffset(0xE8)] public ObjectMoveArray DynamicSectors; /// /// The time limit of this stage for the time extend mode. /// [FieldOffset(0x10C)] public float TimeLimit; /// /// The height the player dies at in this stage (unused). /// [FieldOffset(0x110)] public float DeadHeight; /// /// The duration of the noise effect when warping into Cyber Space. /// [FieldOffset(0x114)] public float NoiseTime; /// /// The required ring count to complete the ring mission. /// [FieldOffset(0x124)] public int RingMissionThreshold; /// /// The gameplay mode for this stage. /// [FieldOffset(0x128)] public CyberModes CyberMode; /// /// Rank times for Cyber Space. /// [FieldOffset(0x12C)] public RankTimes Ranks; /// /// Rank times for Cyber Space on Extreme difficulty. /// [FieldOffset(0x13C)] public RankTimes RanksVeryHard; /// /// Rank times for Cyber Space Challenge. /// [FieldOffset(0x14C)] public RankTimes RanksChallenge; /// /// Rank times for Cyber Space Challenge (totalled). /// [FieldOffset(0x15C)] public RankTimes RanksChallengeAll; [StructLayout(LayoutKind.Sequential)] public struct RankTimes { public int S, A, B, C; public RankTimes(int in_s, int in_a, int in_b, int in_c) { S = in_s; A = in_a; B = in_b; C = in_c; } } } public enum Attributes { Cyber = 0x01, Minigame = 0x02, Hacking = 0x03, LastBoss = 0x04, MasterTrial = 0x05, Tutorial = 0x06, Navmesh = 0x08, HeightField = 0x09, PointCloud = 0x0A, Autosave = 0x0B, Diving = 0x0D, SideStep = 0x0E, Athletic = 0x0F, Boarding = 0x10, Drift = 0x11, SideView = 0x12, Lava = 0x13, Sonic = 0x14, Tails = 0x15, Amy = 0x16, Knuckles = 0x17, BattleRush = 0x18, BossRush = 0x19, Extra = 0x1A, DeleteFallDeadCollision = 0x1B, DeleteAirWallCollision = 0x1C, DeleteGrindRail = 0x1D, ChangeNewCollision = 0x1E, RestrictDebris = 0x1F, SpecialParryEffect = 0x20 } public enum CyberModes : byte { LowGravity = 0x01, TimeExtend = 0x02, SpeedScale = 0x03, Nitro = 0x04, MaxSpeedChallenge = 0x05 } public enum Missions { Goal = 0x01, Rank = 0x02, NoDamage = 0x03, Ring = 0x04, RedRing = 0x05, NumberRing = 0x06, SilverMoonRing = 0x07, HideGoal = 0x08, ShadowTails = 0x09, Mine = 0x0A, Animal = 0x0B } } /// /// A struct representation of `app::game::TimeService`. /// [StructLayout(LayoutKind.Explicit, Size = 0x140)] public struct TimeService { /// /// An instance of `hh::game::GameService`, the base class for `app::game::TimeService`. /// [FieldOffset(0)] public GameService.Data GameService; [FieldOffset(0x88)] public Time CurrentTime; [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct Time { [FieldOffset(0)] public int Days; [FieldOffset(0x04)] public int Hours; [FieldOffset(0x08)] public int Minutes; [FieldOffset(0x0C)] public float Seconds; } } /// /// A struct representation of `app::ui::UIOverlayService`. /// [StructLayout(LayoutKind.Explicit, Size = 0x160)] public struct UIOverlayService { /// /// An instance of `hh::game::GameService`, the base class for `app::ui::UIOverlayService`. /// [FieldOffset(0)] public GameService.Data GameService; [FieldOffset(0x120)] public ObjectMoveArray> OverlayJobs; /// /// A struct representation of `app::ui::RequestOverlayBegin`. /// [StructLayout(LayoutKind.Explicit)] public struct RequestOverlayBegin { [FieldOffset(0x18)] public int OverlayType; [FieldOffset(0x48)] public Helpers.UnmanagedString Caption; } /// /// A struct representation of `app::ui::RequestOverlayCaption`. /// [StructLayout(LayoutKind.Explicit, Size = 0x70)] public struct RequestOverlayCaption { [FieldOffset(0)] public RequestOverlayBegin Base; } /// /// A struct representation of `app::ui::RequestOverlayWindow`. /// [StructLayout(LayoutKind.Explicit, Size = 0xC0)] public struct RequestOverlayWindow { [FieldOffset(0)] public RequestOverlayBegin Base; } /// /// A struct representation of `app::ui::UIOverlayService::OverlayJob`. /// [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct OverlayJob { [FieldOffset(0x18)] public RequestOverlayBegin* pRequestOverlay; } } } Library "GameApplication" by "Hyper" { #include "Helpers" noemit #lib "GameMode" #lib "Memory" #lib "StringMapOperation" #import "Collections" using System.Runtime.InteropServices; /// /// A struct representation of `app::MyApplication`. /// [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct MyApplication { [FieldOffset(0x80)] public ObjectMoveArray> ApplicationExtensions; public ApplicationExtension* GetApplicationExtension(string in_extensionName) { foreach (var pApplicationExtension in ApplicationExtensions) { if (pApplicationExtension.pData->GetNameHash()() == StringMapOperation.ComputeHash(in_extensionName)) return pApplicationExtension.pData; } return null; } MAKE_GENERIC_API(GetApplicationExtension) } /// /// A struct representation of `app::game::ApplicationExtension`. /// [StructLayout(LayoutKind.Explicit)] public struct ApplicationExtension { VFUNCTION_PTR(ApplicationExtension, 1, uint, GetNameHash) } /// /// A struct representation of `app::game::ApplicationSequenceExtension`. /// [StructLayout(LayoutKind.Explicit, Size = 0x140, Pack = 0x10)] public struct ApplicationSequenceExtension { [FieldOffset(0x78)] public GameMode.Data* pGameMode; } } Library "PlayerVisuals" by "Hyper & NM" { #include "Helpers" noemit using System.Runtime.InteropServices; /// /// A struct representation of `app::player::PlayerVisual`. /// [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerVisual { VFUNCTION_PTR(PlayerVisual, 1, uint, GetNameHash) } /// /// A struct representation of `app::player::VisualSuperSonic`. /// [StructLayout(LayoutKind.Explicit, Size = 0x130)] public struct VisualSuperSonic { [FieldOffset(0x000)] public PlayerVisual Base; [FieldOffset(0x118)] public bool IsSuperSonic2; } } Library "States" by "Hyper" { #include "Helpers" noemit #lib "Helpers" #lib "Memory" #import "Collections" #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; /// /// A struct representation of `hh::ut::internal::StateImpl`. /// [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct StateImpl { /// /// The unique ID pertaining to this state. /// [FieldOffset(0x18)] public int StateID; } /// /// A struct representation of `hh::ut::internal::StateDescImpl`. /// [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct StateDescImpl { /// /// The name of this state. /// [FieldOffset(0)] public Helpers.UnmanagedString Name; } /// /// A struct representation of `hh::ut::StateBase`. /// [StructLayout(LayoutKind.Sequential, Size = 0xB0)] public struct StateBase { public StateImpl Base; } /// /// A struct representation of `hh::ut::StateBase`. /// [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct StateDesc { } /// /// A struct representation of `hh::ut::internal::HsmImpl`. /// [StructLayout(LayoutKind.Explicit, Size = 0x70)] public struct HsmImpl { /// /// The index of the current state. /// [FieldOffset(0x0C)] public int CurrentStateIndex; /// /// An array of pointers to `hh::ut::internal::StateImpl` instances. /// [FieldOffset(0x20)] public ObjectMoveArray> States; /// /// A pointer to an instance of `hh::ut::internal::StateImpl`. /// [FieldOffset(0x40)] public StateImpl* pState; } /// /// A struct representation of `hh::ut::HsmBase`. /// [StructLayout(LayoutKind.Sequential, Size = 0x70)] public struct HsmBase { public HsmImpl Base; } /// /// A struct representation of `app::player::PlayerStateParameter`. /// [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerStateParameter { /// /// An array of pointers to `app::player::StateParameter` instances. /// [FieldOffset(0x10)] public ObjectMoveArray StateParameters; } /// /// A struct representation of `app::player::StateParameter`. /// [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct StateParameter { [FieldOffset(0)] public long pVftable; [FieldOffset(0x08)] public int Flags; public StateParameter() { } public StateParameter(int in_flags) { Flags = in_flags; } VFUNCTION_PTR(StateParameter, 2, uint, GetNameHash) } /// /// A struct representation of `app::player::StateAvoid::Parameter`. /// [Helpers.InternalName("StateAvoid::Parameter"), StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct StateAvoidParameter { [FieldOffset(0)] public StateParameter Base = new StateParameter(1); /// /// The direction Sonic should dodge towards. /// [FieldOffset(0x10)] public Quaternion Direction; [FieldOffset(0x20)] public short Flags; public StateAvoidParameter() { /* 0x14154BE28 */ Base.pVftable = Memory.ReadEffectiveAddress ( /* 0x1409C59D0 */ ScanSignature ( "\x48\x8D\x05\xCC\xCC\xCC\xCC\x8B\x53\x08\x49\x89\x00\x41\x89\x50\x08\x0F\x28\x43\x10\x41\x0F\x11\x40\x10\x0F\xB6\x4B\x20", "xxx????xxxxxxxxxxxxxxxxxxxxxxx" ) ); } public StateAvoidParameter(Quaternion in_direction) : this() { Direction = in_direction; Flags = 1; } /* 0x1409C2AB0 */ private static long _sigGetDirectionRelativeToCameraPlane = ScanSignature("\x40\x55\x56\x41\x56\x48\x81\xEC\x00\x01\x00\x00\x48", "xxxxxxxxxxxxx"); FUNCTION_PTR(Quaternion*, fpGetDirectionRelativeToCameraPlane, _sigGetDirectionRelativeToCameraPlane, Quaternion* in_pDirection, Player.PlayerHsmContext* in_pPlayerContext, bool in_isLeft) /// /// Gets the direction Sonic should dodge in relative to the camera plane. /// /// Determines if Sonic is dodging to the right. /// A quaternion facing the direction Sonic should dodge. public static Quaternion GetDirectionRelativeToCameraPlane(bool in_isRight = false) { Quaternion result = Quaternion.Identity; var pPlayerContext = Player.GetPlayerContext(); if (pPlayerContext == null) return result; GET_FUNCTION_PTR(fpGetDirectionRelativeToCameraPlane)(&result, pPlayerContext, !in_isRight); return result; } } /// /// A struct representation of `app::player::StateDoubleJump`. /// [StructLayout(LayoutKind.Explicit, Size = 0xC8)] public struct StateDoubleJump { /// /// The amount of time the Drop Dash has been charged for. /// [FieldOffset(0xB4)] public float DropDashChargeTimer; /// /// Bit flags for the state of the A button. /// [FieldOffset(0xC4)] public byte InputFlags; } /// /// A struct representation of `app::player::StateParry`. /// [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct StateParry { [FieldOffset(0xD4)] public byte Flags; } /// /// A struct representation of `app::player::StateRecoveryJump`. /// [StructLayout(LayoutKind.Explicit, Size = 0xC8)] public struct StateRecoveryJump { /// /// Determines whether the player is charging a Drop Dash. /// [FieldOffset(0xC4)] public bool IsDropDashCharge; } /// /// A struct representation of `app::player::StateSpringJump::Parameter`. /// [Helpers.InternalName("StateSpringJump::Parameter"), StructLayout(LayoutKind.Explicit)] public struct StateSpringJumpParameter { [FieldOffset(0)] public StateParameter Base; /// /// The flags determined by the type of spring. /// [FieldOffset(0x50)] public int Flags; } /// /// A struct representation of `app::player::StateStompingLand`. /// [StructLayout(LayoutKind.Explicit, Size = 0xC0)] public struct StateStompingLand { /// /// The amount of times the player has stomp bounced. /// [FieldOffset(0xB0)] public int StompBounceCount; } /// /// A struct representation of `app::player::StateStompingLand::Parameter`. /// [Helpers.InternalName("StateStompingLand::Parameter"), StructLayout(LayoutKind.Explicit)] public struct StateStompingLandParameter { [FieldOffset(0)] public StateParameter Base = new StateParameter(1); /// /// The amount of times the player has stomp bounced. /// [FieldOffset(0x14)] public int StompBounceCount; public StateStompingLandParameter() { /* 0x14153C238 */ Base.pVftable = Memory.ReadEffectiveAddress ( /* 0x14096D7C5 */ ScanSignature ( "\x48\x8D\x05\xCC\xCC\xCC\xCC\x48\x8B\xCF\x48\x89\x45\xB7", "xxx????xxxxxxx" ) ); } public StateStompingLandParameter(int in_stompBounceCount) : this() { StompBounceCount = in_stompBounceCount; } } /// /// A struct representation of `app::player::StateTailsFly`. /// [StructLayout(LayoutKind.Explicit, Size = 0xB8)] public struct StateTailsFly { /// /// The phase of this state. /// [FieldOffset(0xA8)] public PhaseType Phase; public enum PhaseType : int { /// /// The intro animation of Tails spinning beneath him. /// Intro, /// /// The initial altitude rise after the previous animation is complete. /// Rise, /// /// Tails is flying. /// Flying, /// /// Tails is tired. /// Tired } } } Library "SaveData" by "Hyper" { #lib "GameData" #lib "GameManager" #lib "Memory" #import "Collections" #import "Services" #define SAVE_GET_PARAM(in_hierarchy) (SaveData.GetCurrentSaveData() == null ? null : SaveData.GetCurrentSaveData()->in_hierarchy) #define SAVE_SET_PARAM(in_hierarchy, in_value) if (SaveData.GetCurrentSaveData() != null) SaveData.GetCurrentSaveData()->in_hierarchy = in_value using System.Runtime.InteropServices; /// /// A struct representation of `app::save::SaveInterface`. /// [StructLayout(LayoutKind.Explicit, Size = 0x490)] public struct SaveInterface { [FieldOffset(0x18)] public void* pUserInfoEventListener; /// /// An array of pointers to instances of `app::save::UserElement`. /// [FieldOffset(0x98)] public ObjectMoveArray> UserElements; /// /// The last save data header loaded, for some reason. /// [FieldOffset(0xB8)] public GameData.HeaderData LastLoadedHeader; } /// /// A struct representation of `app::save::UserElement`. /// [StructLayout(LayoutKind.Explicit, Size = 0x154E40, Pack = 0x10)] public struct UserElement { /// /// An instance of the current save data. /// [FieldOffset(0x50)] public GameData.Root GameData; /// /// An array of save data headers. /// [FieldOffset(0x154DB8)] public ObjectMoveArray Headers; } public static GameData.Root* GetCurrentSaveData() { var pSaveManager = GameManager.GetService(); if (pSaveManager == null) return null; var pSaveInterface = pSaveManager->pSaveInterface; if (pSaveInterface == null) return null; if (pSaveInterface->UserElements.Length <= 0) return null; return &pSaveInterface->UserElements[0].pData->GameData; } } Library "Allocators" by "Hyper, Sajid & ĐeäTh" { #include "Helpers" noemit /// /// A struct representation of the `csl::fnd::IAllocator` interface. /// public struct IAllocator { /// /// Destroys an instance of an allocator with the `csl::fnd::IAllocator` interface. /// /// The instance to destroy. VFUNCTION_PTR(IAllocator, 0, void, Dtor, IAllocator* in_pThis) /// /// Allocates an amount of memory to be used for a resource. /// /// The amount of memory to allocate. /// The alignment of the data. VFUNCTION_PTR(IAllocator, 1, void*, Alloc, IAllocator* in_pThis, long in_size, int in_alignment) /// /// Frees used memory at a location. /// /// A pointer to the memory to free. VFUNCTION_PTR(IAllocator, 2, void, Free, IAllocator* in_pThis, void* in_pMemory) } } Library "Objects" by "Hyper" { #lib "GameObject" #lib "Helpers" #import "GOComponents" using System.Runtime.InteropServices; /// /// A struct representation of `app::ui::UICursor`. /// [Helpers.InternalName("Cursor"), StructLayout(LayoutKind.Explicit, Size = 0x248)] public struct UICursor { [FieldOffset(0)] public GameObject.Data Base; } /// /// A struct representation of `app::ui::UILockonContext`. /// [StructLayout(LayoutKind.Explicit, Size = 0x160, Pack = 0x10)] public struct UILockonContext { /// /// A pointer to the collider component for the target object. /// [FieldOffset(0x50)] public GOComponent* pGOCCollider; } } Library "NoisePresetParameters" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct UVShift { [FieldOffset(0x00)] public float blockLNoiseSizeX; [FieldOffset(0x04)] public float blockLNoiseSizeY; [FieldOffset(0x08)] public float blockHNoiseSizeX; [FieldOffset(0x0C)] public float blockHNoiseSizeY; [FieldOffset(0x10)] public float bNoiseHighRate; [FieldOffset(0x14)] public float intensity; [FieldOffset(0x18)] public float pixelShiftIntensity; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct ColorShift { [FieldOffset(0x00)] public float blockLNoiseSize; [FieldOffset(0x04)] public float blockHNoiseSize; [FieldOffset(0x08)] public float bNoiseHighRate; [FieldOffset(0x0C)] public float intensity; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct InterlaceNoise { [FieldOffset(0x00)] public float blockLNoiseSize; [FieldOffset(0x04)] public float blockHNoiseSize; [FieldOffset(0x08)] public float bNoiseHighRate; [FieldOffset(0x0C)] public float intensity; [FieldOffset(0x10)] public float dropout; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct ColorDropout { [FieldOffset(0x00)] public float blockLNoiseSizeX; [FieldOffset(0x04)] public float blockLNoiseSizeY; [FieldOffset(0x08)] public float blockHNoiseSizeX; [FieldOffset(0x0C)] public float blockHNoiseSizeY; [FieldOffset(0x10)] public float bNoiseHighRate; [FieldOffset(0x14)] public float intensity; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct InvertColor { [FieldOffset(0x00)] public float blockLNoiseSizeX; [FieldOffset(0x04)] public float blockLNoiseSizeY; [FieldOffset(0x08)] public float blockHNoiseSizeX; [FieldOffset(0x0C)] public float blockHNoiseSizeY; [FieldOffset(0x10)] public float bNoiseHighRate; [FieldOffset(0x14)] public float intensity; [FieldOffset(0x18)] public float invertAllRate; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct GlayScaleColor { [FieldOffset(0x00)] public float blockLNoiseSizeX; [FieldOffset(0x04)] public float blockLNoiseSizeY; [FieldOffset(0x08)] public float blockHNoiseSizeX; [FieldOffset(0x0C)] public float blockHNoiseSizeY; [FieldOffset(0x10)] public float bNoiseHighRate; [FieldOffset(0x14)] public float intensity; [FieldOffset(0x18)] public float invertAllRate; } [StructLayout(LayoutKind.Explicit, Size = 0xA4)] public struct FxCyberSpaceStartNoiseParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public UVShift uvShift; [FieldOffset(0x20)] public ColorShift colorShift; [FieldOffset(0x30)] public InterlaceNoise interlaceNoise; [FieldOffset(0x44)] public ColorDropout colorDrop; [FieldOffset(0x5C)] public InvertColor invertColor; [FieldOffset(0x78)] public GlayScaleColor glayscaleColor; [FieldOffset(0x94)] public float noiseSpeed; [FieldOffset(0x98)] public float noiseBias; [FieldOffset(0x9C)] public float noiseWaveAmplitude; [FieldOffset(0xA0)] public float noiseWaveCycle; } [StructLayout(LayoutKind.Explicit, Size = 0x520)] public struct Root { [FieldOffset(0x00)] public unsafe fixed byte /* FxCyberSpaceStartNoiseParameter[8] */ _presets[1312]; public unsafe FxCyberSpaceStartNoiseParameter* presets { get { fixed (byte* p_presets = _presets) return (FxCyberSpaceStartNoiseParameter*)p_presets; } } } } Library "GOComponentManager" by "Hyper" { #lib "Memory" #lib "HandleManagerBase" #import "GameTypes" #import "GOComponents" using System.Runtime.InteropServices; /* 0x150274D5F */ private static long _sigGOComponentManagerHandleManagerSingleton = ScanSignature ( "\x48\x89\x05\xCC\xCC\xCC\xCC\x8D\x55\x50", "xxx????xxx" ); public HandleManagerBase.Data* GetHandleManager() { if (_sigGOComponentManagerHandleManagerSingleton == 0) return null; return *(HandleManagerBase.Data**)Memory.ReadEffectiveAddress(_sigGOComponentManagerHandleManagerSingleton); } public GOComponent* GetGOCFromHandle(int in_handle) { var manager = GetHandleManager(); if (manager == null) return null; return (GOComponent*)manager->GetObject(in_handle); } } Library "Graphics" by "Hyper & angryzor" { #lib "Helpers" #import "Allocators" #import "GameTypes" using System.Runtime.InteropServices; /// /// A struct representation of `hh::gfnd::Renderable`. /// [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct Renderable { [FieldOffset(0)] public ReferencedObject Base; [FieldOffset(0x28)] public void* pRenderableContainerNode; [FieldOffset(0x30)] public byte PreferredContainer; /// /// The name of this `hh::gfnd::Renderable` instance. /// [FieldOffset(0x38)] public Helpers.UnmanagedString Name; } /// /// A struct representation of `app::gfx::MoviePlayerObject`. /// [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct MoviePlayerObject { /// /// Determines whether the game clears the movie buffer once finished playing. /// [FieldOffset(0x10)] public bool IsClearBufferOnEnd; /// /// The handle to this instance. /// [FieldOffset(0x18)] public int Handle; /// /// A pointer to an instance of `hh::fmv::MoviePlayer`. /// [FieldOffset(0x20)] public MoviePlayer* pMoviePlayer; } /// /// A struct representation of `hh::fmv::MoviePlayer`. /// [StructLayout(LayoutKind.Explicit, Size = 0xA4)] public struct MoviePlayer { /// /// A pointer to an instance of `hh::fmv::MoviePlayer::MyRenderable`. /// [FieldOffset(0x20)] public MyRenderable* pMyRenderable; [FieldOffset(0x92)] public MovieFlags Flags; [Flags] public enum MovieFlags : ushort { /// /// Determines whether this movie is paused. /// This may require a signal from the game to actually pause. /// IsPaused = 0x80, /// /// Determines whether this movie is finished. /// IsFinished = 0x200 } /// /// A struct representation of `hh::fmv::MoviePlayer::MyRenderable`. /// [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct MyRenderable { [FieldOffset(0)] public Renderable Base; /// /// A pointer to an instance of `hh::fmv::MoviePlayer`. /// [FieldOffset(0x50)] public MoviePlayer* pMoviePlayer; } } /// /// A struct representation of `hh::fmv::MoviePlayerCri`. /// [StructLayout(LayoutKind.Explicit, Size = 0x190)] public struct MoviePlayerCri { [FieldOffset(0)] public MoviePlayer Base; [FieldOffset(0xA8)] public void* pCriManaPlayer; [FieldOffset(0xB0)] public CriMovieStatus Status; public enum CriMovieStatus : int { IsInitialising = 0, IsBegin = 4, IsPlaying = 5, IsFinished = 6 } } } Library "Cameras" by "Hyper" { #include "Helpers" noemit #lib "Helpers" #lib "MathHelpers" #lib "StandardCameraConfig" #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; /// /// A struct representation of a wrapper for storing instances of `app_cmn::camera::CameraController` in arrays. /// [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct CameraControllerWrapper { /// /// A pointer to an instance of `app_cmn::camera::CameraController`. /// [FieldOffset(0)] public CameraController* pCameraController; } /// /// A struct representation of `app_cmn::camera::CameraController`. /// [StructLayout(LayoutKind.Explicit, Size = 0xC8)] public struct CameraController { /// /// The position of the camera. /// [FieldOffset(0x20)] public Vector3 Position; VFUNCTION_PTR(CameraController, 1, long, GetName) } /// /// A struct representation of `app::game::ObjPhotoModeCamera`. /// [Helpers.InternalName("PhotoModeCamera"), StructLayout(LayoutKind.Explicit, Size = 0x268)] public struct ObjPhotoModeCamera { /// /// A pointer to an instance of `app::camera::PhotoModeCamera`. /// [FieldOffset(0x258)] public PhotoModeCamera* pPhotoModeCamera; } /// /// A struct representation of `app::camera::PhotoModeCamera`. /// [StructLayout(LayoutKind.Explicit, Size = 0x210)] public struct PhotoModeCamera { /// /// The current orbit centre position of the camera. /// [FieldOffset(0x20)] public Vector3 Centre; /// /// The current yaw of the camera. /// [FieldOffset(0x50)] public float Yaw; /// /// The current pitch of the camera. /// [FieldOffset(0x54)] public float Pitch; /// /// The current distance from the orbit centre of the camera. /// [FieldOffset(0x58)] public float Distance; /// /// The current amount of tilt between pi and negative pi. /// [FieldOffset(0x90)] public float Tilt; /// /// The current amount of zoom between pi and negative pi. /// [FieldOffset(0xA8)] public float Zoom; /// /// The starting orbit centre position of the camera (used for resetting). /// [FieldOffset(0x170)] public Vector3 StartCentre; /// /// The starting yaw of the camera (used for resetting). /// [FieldOffset(0x1A0)] public float StartYaw; /// /// The starting pitch of the camera (used for resetting). /// [FieldOffset(0x1A4)] public float StartPitch; /// /// The starting distance from the orbit centre of the camera (used for resetting). /// [FieldOffset(0x1A4)] public float StartDistance; /// /// The starting amount of tilt for the camera (used for resetting). /// [FieldOffset(0x1E0)] public float StartTilt; /// /// The starting amount of zoom for the camera (used for resetting). /// [FieldOffset(0x1F8)] public float StartZoom; /// /// The index of the current speed of the camera. /// [FieldOffset(0x204)] public int SpeedIndex; } /// /// A struct representation of `app::camera::StandardCamera`. /// [StructLayout(LayoutKind.Explicit)] public struct StandardCamera { [FieldOffset(0)] public CameraController Base; /// /// A pointer to an instance of `app::camera::StandardCameraContext`. /// [FieldOffset(0xE8)] public StandardCameraContext* pContext; } /// /// A struct representation of `app::camera::StandardCameraContext`. /// [StructLayout(LayoutKind.Explicit, Size = 0x1E0)] public struct StandardCameraContext { /// /// A pointer to the `StandardCameraConfig` struct from `standard_camera.rfl`. /// [FieldOffset(0x20)] public StandardCameraConfig.Root* pStandardCameraConfig; /// /// The position of the camera. /// [FieldOffset(0x30)] public Vector3 Position; /// /// The nearest point of the camera view frustum. /// [FieldOffset(0xB0)] public float NearPlaneZ; /// /// The furthest point of the camera view frustum. /// [FieldOffset(0xB4)] public float FarPlaneZ; /// /// The current field of view in radians. /// [FieldOffset(0xB8)] public float FieldOfView; /// /// The distance of the camera to the player. /// [FieldOffset(0xC0)] public float Distance; /// /// The suspension length when the player picks up speed (e.g. boost). /// [FieldOffset(0xC4)] public float DistanceSuspension; /// /// The height of the camera. /// [FieldOffset(0xF8)] public float Elevation; /// /// The current field of view on the Y axis in radians. /// [FieldOffset(0x12C)] public float FieldOfViewY; /// /// The scalar for field of view, based on the user configuration. /// [FieldOffset(0x130)] public float FieldOfViewScalar; /// /// Gets the current field of view in degrees. /// /// The current field of view in degrees. public float GetFieldOfView() { return MathHelpers.ToDegrees(FieldOfView); } /// /// Sets the current field of view. /// NOTICE: this function currently has a hard limit of 89 FOV maximum. /// /// The field of view in degrees. public void SetFieldOfView(float in_degrees) { if (pStandardCameraConfig == null) return; float fovY = FieldOfViewY * pStandardCameraConfig->option.minFovyRate; // HACK (Hyper): temporary fix, limits FOV to 0-89 to prevent unstable game state. // TODO (Hyper): figure out what's causing Bullet to throw up at 90+ FOV. in_degrees = MathHelpers.Clamp(in_degrees, 0.0f, 89.0f); FieldOfViewScalar = ((MathHelpers.ToRadians(in_degrees) - fovY) / (FieldOfViewY - fovY)); } } } Library "GOComponents" by "Hyper & NM" { #include "Helpers" noemit #lib "GameObject" #lib "GOComponentManager" #lib "Helpers" #lib "Memory" #lib "Player" #lib "PlayerCollision" #lib "PlayerEffect" #lib "StringMapOperation" #import "Cameras" #import "Collections" #import "PlayerVisuals" #import "Plugins" #import "Postures" #import "States" #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; /// /// A struct representation of `hh::game::GOComponent`. /// [StructLayout(LayoutKind.Explicit, Size = 0x80)] public struct GOComponent { /// /// A pointer to an instance of `hh::game::GameObject` acting as the parent of this component. /// [FieldOffset(0x28)] public GameObject.Data* pGameObject; /// /// A pointer to an instance of `GOComponentStaticClass`. /// [FieldOffset(0x48)] public GOComponentStaticClass* pStaticClass; } /// /// A struct representation of the static class for storing information about a game object component. /// [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct GOComponentStaticClass { /// /// The name of this game object component. /// [FieldOffset(0)] public Helpers.UnmanagedString Name; public override string ToString() => Name.ToString(); } /// /// A struct representation of `hh::anim::GOCAnimationSingle`. /// [StructLayout(LayoutKind.Explicit, Size = 0x100)] public struct GOCAnimationSingle { [FieldOffset(0)] public GOComponent Base; [FieldOffset(0x90)] public void* pUnknownClass; } /// /// A struct representation of `hh::anim::GOCAnimator`. /// [StructLayout(LayoutKind.Explicit, Size = 0x130)] public struct GOCAnimator { [FieldOffset(0)] public GOCAnimationSingle Base; /// /// A pointer to an instance of `hh::anim::TriggerListener`. /// [FieldOffset(0x100)] public void* pTriggerListener; /// /// A pointer to an instance of `hh::anim::AnimationStateListener`. /// [FieldOffset(0x108)] public void* pAnimationStateListener; } /// /// A struct representation of `app::player::GOCCamera`. /// [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct GOCCamera { [FieldOffset(0)] public GOComponent Base; /// /// An array of pointers to `CameraControllerWrapper` instances. /// [FieldOffset(0x80)] public ObjectMoveArray Cameras; /// /// Gets an instance of `app_cmn::camera::CameraController` by name. /// /// The name of the camera controller. /// An instance of `app_cmn::camera::CameraController` requested by name. public CameraController* GetCameraController(string in_cameraName) { foreach (var pWrapper in Cameras) { if (pWrapper.pCameraController == null) continue; if (FROM_STRING_PTR(pWrapper.pCameraController->GetName()()) == in_cameraName) return pWrapper.pCameraController; } return null; } MAKE_GENERIC_API(GetCameraController) } /// /// A struct representation of `app::player::GOCEventTimer`. /// [StructLayout(LayoutKind.Explicit, Size = 0xC8)] public struct GOCEventTimer { [FieldOffset(0)] public GOComponent Base; [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct TimerData { /// /// The duration of this timer. /// [FieldOffset(0x04)] float Duration; /// /// The time the display will turn yellow. /// [FieldOffset(0x0C)] float TimeYellow; /// /// The time the display will turn red. /// [FieldOffset(0x10)] float TimeRed; } } /// /// A struct representation of `app::player::GOCPlayerBlackboard`. /// [StructLayout(LayoutKind.Explicit, Size = 0x88)] public struct GOCPlayerBlackboard { [FieldOffset(0)] public GOComponent Base; /// /// A pointer to an instance of `app::player::Blackboard`. /// [FieldOffset(0x80)] public Blackboard.Data* pBlackboard; } /// /// A struct representation of `app::player::GOCPlayerCollider`. /// [StructLayout(LayoutKind.Explicit, Size = 0x100)] public struct GOCPlayerCollider { [FieldOffset(0)] public GOComponent Base; [FieldOffset(0xE8)] public PlayerCollision.Data* pPlayerCollision; } /// /// A struct representation of `app::player::GOCPlayerEffect`. /// [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct GOCPlayerEffect { [FieldOffset(0)] public GOComponent Base; /// /// A pointer to an instance of `app::player::EffectList`. /// [FieldOffset(0x88)] public PlayerEffect.EffectList* pEffectList; } /// /// A struct representation of `app::player::GOCPlayerEyesight`. /// [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct GOCPlayerEyesight { [FieldOffset(0)] public GOComponent Base; [FieldOffset(0x80)] public ObjectMoveArray> EyesightComponents; public PlayerEyesightComponent* GetEyesightComponent(string in_eyesightName) { foreach (var pEyesight in EyesightComponents) { if (pEyesight.pData->GetNameHash()() == StringMapOperation.ComputeHash(in_eyesightName)) return pEyesight.pData; } return null; } MAKE_GENERIC_API(GetEyesightComponent) } /// /// A struct representation of `app::player::PlayerEyesightComponent`. /// [StructLayout(LayoutKind.Explicit, Size = 0x90)] public struct PlayerEyesightComponent { VFUNCTION_PTR(PlayerEyesightComponent, 3, uint, GetNameHash) } /// /// A struct representation of `app::player::HomingEyesight`. /// [StructLayout(LayoutKind.Explicit, Size = 0x150, Pack = 0x10)] public struct HomingEyesight { [FieldOffset(0)] public PlayerEyesightComponent Base; [FieldOffset(0xD8)] public ObjectMoveArray> Targets; /// /// Gets the target based on its priority. /// The highest priority (0) is the current homing target. /// /// Determines if this function retrieves the lowest priority homing target. /// The homing target at the requested priority. public TargetData* GetPriorityTarget(bool in_isLow = false) { if (Targets.Length == 0) return null; return Targets[in_isLow ? Targets.Length - 1 : 0].pData; } /// /// Gets the target nearest to the player based on its relative position. /// /// The nearest target to the player. public TargetData* GetNearestTarget() { if (Targets.Length == 0) return null; var minTarget = Targets[0]; var minDist = minTarget.pData->Distance; foreach (var pTarget in Targets) { if (pTarget.pData->Distance < minDist) { minTarget = pTarget; minDist = pTarget.pData->Distance; } } return minTarget.pData; } /// /// Determines if the input target data belongs to an enemy. /// /// The target to check. /// A boolean representation of whether the input target data belongs to an enemy. public bool IsTargetEnemy(TargetData* in_pTarget = null) { if (in_pTarget == null) { in_pTarget = GetPriorityTarget(); if (in_pTarget == null) return false; } var pGameObject = in_pTarget->GetGameObject(); if (pGameObject == null) return false; // Enemies will always use GOCHealth. return GameObject.GetGOC(pGameObject, "GOCHealth") != null; } /// /// A struct representation of `app::player::HomingEyesight::TargetData`. /// [StructLayout(LayoutKind.Explicit, Size = 0xE0, Pack = 0x10)] public struct TargetData { /// /// The handle value for the collider component for the target object. /// [FieldOffset(0x20)] public int GOCColliderHandle; /// /// The position of the target object. /// [FieldOffset(0x30)] public Vector3 Position; /// /// The distance between the player and the target object. /// [FieldOffset(0xC0)] public float Distance; /// /// Gets the instance of `hh::game::GameObject` associated with this target data. /// /// An instance of `hh::game::GameObject`. public GameObject.Data* GetGameObject() { var pGOComponent = GOComponentManager.GetGOCFromHandle(GOCColliderHandle); if (pGOComponent == null) return null; return pGOComponent->pGameObject; } } } /// /// A struct representation of `app::player::GOCPlayerHsm`. /// [StructLayout(LayoutKind.Explicit, Size = 0x170)] public struct GOCPlayerHsm { [FieldOffset(0)] public GOComponent Base; /// /// A pointer to an instance of `hh::ut::HsmBase`. /// [FieldOffset(0x88)] public HsmBase Hsm; /// /// A pointer to an instance of `app::player::PlayerStateParameter`. /// [FieldOffset(0x100)] public PlayerStateParameter* pPlayerStateParameter; /// /// A pointer to an instance of `app::player::StatePluginManager`. /// [FieldOffset(0x108)] public StatePluginManager* pStatePluginManager; /// /// The current state ID. /// [FieldOffset(0x114)] public int StateID; /// /// The current state's parent ID. /// [FieldOffset(0x118)] public int ParentStateID; /// /// Gets the current state ID. /// /// The current state ID. public int GetStateID() { if (Hsm.Base.CurrentStateIndex != 0) return Hsm.Base.States[Hsm.Base.CurrentStateIndex - 1].pData->StateID; return -1; } } /// /// A struct representation of `app::player::GOCPlayerKinematicParams`. /// [StructLayout(LayoutKind.Explicit, Size = 0x5E0, Pack = 0x10)] public struct GOCPlayerKinematicParams { [FieldOffset(0)] public GOComponent Base; /// /// The current position of the player. /// [FieldOffset(0x80)] public Vector3 Position; /// /// The current rotation of the player. /// [FieldOffset(0x90)] public Quaternion Rotation; /// /// The current velocity of the player. /// [FieldOffset(0xD0)] public Vector3 Velocity; [FieldOffset(0x120)] public Vector3 WorldInput; /// /// Bit flags for kinematics. /// [FieldOffset(0x1C5)] public KinematicsFlags Flags; /// /// An enum containing known flags for player kinematics. /// [Flags] public enum KinematicsFlags : byte { /// /// The player is on the ground. /// IsGrounded = 2 } } /// /// A struct representation of `app::player::GOCPlayerParameter`. /// [StructLayout(LayoutKind.Explicit, Size = 0x1A8)] public struct GOCPlayerParameter { [FieldOffset(0)] public GOComponent Base; /// /// The current mode package type. /// [FieldOffset(0xB8)] public ModePackageType CurrentModePackageType; /// /// An enum containing the different mode package types from the player's reflection data. /// public enum ModePackageType : int { /// /// The player is in 3D. /// ForwardView, /// /// The player is underwater. /// Water, /// /// The player is in Cyber Space 3D. /// CyberSpace, /// /// The player is in 2D. /// SideView } } /// /// A struct representation of `app::player::GOCPlayerPosture`. /// [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct GOCPlayerPosture { [FieldOffset(0)] public GOComponent Base; /// /// A pointer to an instance of `app::player::PlayerPostureContext`. /// [FieldOffset(0x80)] public PlayerPostureContext* pPlayerPostureContext; /// /// A pointer to an instance of `app::player::PostureMoveManager`. /// [FieldOffset(0x88)] public PostureMoveManager* pPostureMoveManager; /// /// A pointer to an instance of `app::player::PostureInputManager`. /// [FieldOffset(0x90)] public void* pPostureInputManager; } /// /// A struct representation of `app::player::GOCPlayerVisual`. /// [StructLayout(LayoutKind.Explicit, Size = 0x180)] public struct GOCPlayerVisual { [FieldOffset(0x000)] public GOComponent Base; /// /// A pointer to an instance of `app::player::PlayerVisual`. /// [FieldOffset(0x108)] public PlayerVisual* pPlayerVisual; /// /// Retrieves the contained , given that its name matches . /// /// The name of the visual to retrieve. /// A pointer to the if the names match; otherwise, null. public PlayerVisual* GetVisual(string in_visualName) { if (pPlayerVisual->GetNameHash()() == StringMapOperation.ComputeHash(in_visualName)) return pPlayerVisual; else return null; } MAKE_GENERIC_API(GetVisual) } /// /// A struct representation of `hh::ui::GOCSprite`. /// [StructLayout(LayoutKind.Explicit, Size = 0x230)] public struct GOCSprite { [FieldOffset(0)] public GOComponent Base; /// /// A pointer to an instance of `hh::ui::GOCSprite::Renderable`. /// [FieldOffset(0x178)] public Renderable* pRenderable; /// /// Bit flags for the sprite state. /// [FieldOffset(0x180)] public byte Flags; /// /// A struct representation of `hh::ui::GOCSprite::Renderable`. /// [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct Renderable { /// /// The name of this renderable. /// [FieldOffset(0x38)] public Helpers.UnmanagedString Name; /// /// A pointer to an instance of `hh::ui::GOCSprite` acting as the parent of this object. /// [FieldOffset(0x50)] public GOCSprite* pGOCSprite; } } /// /// A struct representation of `app_cmn::fsm::GOCTinyFsm`. /// [Helpers.InternalName("GOCTinyFsm2"), StructLayout(LayoutKind.Explicit, Size = 0x168)] public struct GOCTinyFsm { [FieldOffset(0)] public GOComponent Base; /// /// A pointer to an instance of `app_cmn::fsm::GOCTinyFsmContext`. /// [FieldOffset(0x80)] public void* pGOCTinyFsmContext; public T* GetContext() where T : unmanaged { return (T*)pGOCTinyFsmContext; } } /// /// A struct representation of `app::player::GOCTransform`. /// [StructLayout(LayoutKind.Explicit, Size = 0x110)] public struct GOCTransform { [FieldOffset(0)] public GOComponent Base; /// /// The current position of the transform. /// [FieldOffset(0xC0)] public Vector3 Position; /// /// The current rotation of the transform. /// [FieldOffset(0xD0)] public Quaternion Rotation; /// /// The current scale of the transform. /// [FieldOffset(0xE0)] public Vector3 Scale; } } Library "GameService" by "Hyper & Sajid" { #include "Helpers" noemit #lib "GameManager" #import "Allocators" using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; private static bool _isInitialised = false; private static List _userServiceClassPtrs = new(); /// /// A struct representation of `hh::game::GameService`. /// [StructLayout(LayoutKind.Explicit, Size = 0x70)] public struct Data { /// /// A pointer to a memory allocator. /// [FieldOffset(0x08)] public IAllocator* pAllocator; /// /// A pointer to an instance of `app::GameManager`. /// [FieldOffset(0x30)] public GameManager.Data* pGameManager; /// /// A pointer to an instance of `GameServiceStaticClass`. /// [FieldOffset(0x38)] public GameServiceStaticClass* pStaticClass; } /// /// A struct representation of the static class for storing information about a game service. /// [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct GameServiceStaticClass { /// /// The name of this game service. /// [FieldOffset(0)] public Helpers.UnmanagedString Name; public override string ToString() => Name.ToString(); } UNMANAGED_FUNCTION(long, CreateServices, long in_ppClasses) { var classes = new List(); // Copy array contents to our list. while (Read(in_ppClasses) != 0) { classes.Add(Read(in_ppClasses)); in_ppClasses += 8; } // Add user service class pointers. foreach (var ptr in _userServiceClassPtrs) { if (classes.Contains(ptr)) continue; classes.Add(ptr); } classes.Add(0); var classesArr = classes.ToArray(); fixed (long* pClasses = classesArr) return (long)pClasses; } [LibraryInitializer] public void Init() { if (_isInitialised) return; WriteAsmHook ( $@" push r14 sub rsp, 0x20 mov rax, qword ptr [rdx] mov r14, rdx mov rbx, rcx mov rcx, r14 mov rdx, {GET_UNMANAGED_FUNCTION_PTR(CreateServices)} call rdx mov r14, rax mov rax, qword ptr [rax] ", /* 0x147140C75 */ ScanSignature ( "\x41\x56\x48\x83\xEC\x20\x48\x8B\x02\x49\x89\xD6", "xxxxxxxxxxxx" ), HookBehavior.Replace ); _isInitialised = true; } /// /// Adds a pointer to a `GameServiceStaticClass` struct to the user pointers list of game services to load. /// public void AddUserService(long in_ptr) { if (_userServiceClassPtrs.Contains(in_ptr)) return; _userServiceClassPtrs.Add(in_ptr); } /// /// Removes a pointer to a `GameServiceStaticClass` struct. /// public void RemoveUserService(long in_ptr) { if (!_userServiceClassPtrs.Contains(in_ptr)) return; _userServiceClassPtrs.Remove(in_ptr); } } Patch "Disable Cyloop Camera" in "Camera" by "Hyper" { WriteNop ( /* 0x1408577FE */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x4C\x8D\x05\xCC\xCC\xCC\xCC\x48\x8B\xD3\x48\x8D\x4D\x40", "x????xxx????xxxxxxx" ), 5 ); } Patch "Disable Skill Camera Events" in "Camera" by "Hyper" does /* Disables the camera events for skills. The "Dramatic Battle Skill Camera" option in the game settings must be enabled for this code to work. This code behaves the same as the option described above, but keeps the camera events for performing special attacks on titans, as well as the Quick Cyloop camera. Affected skills; - Cross Slash - Cyclone Kick - Grand Slam - Homing Shot - Loop Kick - Recovery Smash - Sonic Boom - Spin Slash - Stomp Attack - Wild Rush */ { WriteProtected ( /* 0x1408D5986 */ ScanSignature ( "\x0F\x84\x83\x00\x00\x00\x44\x38\x36", "xxxxxxxxx" ), 0xE9, 0x84, 0x00, 0x00, 0x00 ); WriteNop ( /* 0x14087F9E9 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x41\xC7\x86\xAC\x00\x00\x00\x03\x00\x00\x00", "x????xxxxxxxxxxx" ), 5 ); } Code "Restore Unused Spin Charge Camera Shake" in "Camera" by "Hyper" // #include "Reflection" noemit #lib "Reflection" #lib "SonicParameters" #lib "AmyParameters" #lib "KnucklesParameters" #lib "TailsParameters" // { var SonicParametersInfo = Reflection.GetDataInfo("player_common"); var AmyParametersInfo = Reflection.GetDataInfo("amy_common"); var KnucklesParametersInfo = Reflection.GetDataInfo("knuckles_common"); var TailsParametersInfo = Reflection.GetDataInfo("tails_common"); if (SonicParametersInfo.pData != null) RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, spinBoost.cameraShakeName, "SpinBoostCharge"); if (AmyParametersInfo.pData != null) RFL_SET_PARAM(AmyParametersInfo, forwardView.spinBoost.cameraShakeName, "SpinBoostCharge"); if (KnucklesParametersInfo.pData != null) RFL_SET_PARAM(KnucklesParametersInfo, forwardView.spinBoost.cameraShakeName, "SpinBoostCharge"); if (TailsParametersInfo.pData != null) RFL_SET_PARAM(TailsParametersInfo, forwardView.spinBoost.cameraShakeName, "SpinBoostCharge"); } Patch "Smooth Camera (v1.42)" in "Camera" by "Ahremic" does "Replaces linear camera interpolation with a sigmoid solution, using Ken Perlin's ''Smoother Step'' second-order hermite polynomial." // static float value01 = 1.0f; static float value03 = 3.0f; static float value05 = 5.0f; static float value10 = 10.0f; // { // Linear coordinate interpolator WriteProtected(0x1467D940D, Assemble("mov edx, 0x60")); WriteProtected(0x1467D944C, Assemble("mov edx, 0x60")); // Target Base interpolator WriteProtected(0x1467D94FD, Assemble("mov edx, 0x100")); WriteProtected(0x1467D94D9, Assemble("mov edx, 0x100")); WriteProtected(0x1467D9492, Assemble("mov edx, 0x100")); // Base Ctor type A WriteAsmHook ( "movss dword ptr [rdi + 0xF0], xmm6", 0x146780EB5, HookBehavior.After ); // Base Ctor type B WriteAsmHook ( "movss dword ptr [rdi + 0xF0], xmm6", 0x1400C417A, HookBehavior.After ); // Linear Ctor WriteAsmHook ( "movss dword ptr [rdi + 0x50], xmm6", 0x1400C3D20, HookBehavior.After ); // Initialize our value in camera init/reset functions (whatever these are), just to be safe. // Base WriteAsmHook ( "mov [rdi + 0xF0], eax", 0x146788681, HookBehavior.After ); // Linear. This function can't use before/after because of a call being invoked, and a bug with how HMM interprets calls in x64 assembly, potentially. WriteAsmHook ( $@" ; Prologue mov [rsp + 8], rbx push rdi sub rsp, 0x20 mov eax, [rcx + 0x20] mov rdi, rcx ; Custom data mov [rdi + 0x50], eax ", 0x1400C40C0, HookBehavior.Replace ); // Smoother-step algorithm by Ken Perlin // https://en.wikipedia.org/wiki/Smoothstep fixed (float* pValue01 = &value01) fixed (float* pValue03 = &value03) fixed (float* pValue05 = &value05) fixed (float* pValue10 = &value10) { // Base cam update WriteAsmHook ( $@" movss xmm2, dword ptr [rcx + 0xF0] xorps xmm0, xmm0 subss xmm2, dword ptr [rdx] comiss xmm0, xmm2 movss dword ptr [rcx + 0xF0], xmm2 jb jumpA mov dword ptr [rcx + 0xF0], 0 xorps xmm2, xmm2 jumpA: movss xmm3, dword ptr [rcx + 0xD0] comiss xmm3, xmm0 jbe jumpB divss xmm2, xmm3 jmp jumpC jumpB: mov rax, {(long)pValue01} movss xmm2, dword ptr [rax] jumpC: movaps xmm0, xmm2 movaps xmm1, xmm2 mov rax, {(long)pValue03} mulss xmm0, dword ptr [rax] addss xmm1, xmm2 mov rax, {(long)pValue05} subss xmm1, dword ptr [rax] mulss xmm1, xmm0 movaps xmm0, xmm2 mulss xmm0, xmm2 mov rax, {(long)pValue10} addss xmm1, dword ptr [rax] mulss xmm0, xmm2 mulss xmm1, xmm0 mulss xmm1, xmm3 movss dword ptr [rcx + 0xD4], xmm1 ret ", 0x1400C48F0, HookBehavior.Replace ); // Linear cam update WriteAsmHook ( $@" movss xmm2, dword ptr [rcx + 0x50] xorps xmm0, xmm0 subss xmm2, dword ptr [rdx] comiss xmm0, xmm2 movss dword ptr [rcx + 0x50], xmm2 jb jumpA mov dword ptr [rcx + 0x50], 0 xorps xmm2, xmm2 jumpA: movss xmm3, dword ptr [rcx + 0x20] comiss xmm3, xmm0 jbe jumpB divss xmm2, xmm3 jmp jumpC jumpB: mov rax, {(long)pValue01} movss xmm2, dword ptr [rax] jumpC: movaps xmm0, xmm2 movaps xmm1, xmm2 mov rax, {(long)pValue03} mulss xmm0, dword ptr [rax] addss xmm1, xmm2 mov rax, {(long)pValue05} subss xmm1, dword ptr [rax] mulss xmm1, xmm0 movaps xmm0, xmm2 mulss xmm0, xmm2 mov rax, {(long)pValue10} addss xmm1, dword ptr [rax] mulss xmm0, xmm2 mulss xmm1, xmm0 mulss xmm1, xmm3 movss dword ptr [rcx + 0x24], xmm1 ret ", 0x14677AED0, HookBehavior.Replace ); } } Patch "Disable Drop Dash Camera Delay" in "Camera" by "Hyper" { WriteProtected ( /* v1.41: 0x140956C32 */ ScanSignature ( "\x73\x2A\xF3\x0F\x10\x05\xCC\xCC\xCC\xCC\x45\x33\xC9", "xxxxxx????xxx" ), 0xEB ); } Patch "Disable Camera Shake" in "Camera" by "Hyper" does "Disables camera shake during combat." // #lib "Memory" // { Memory.WriteForceJump ( /* 0x1400C2C8C */ ScanSignature ( "\x0F\x85\xB6\x03\x00\x00\x48\x8B\x41\x28", "xxxxxxxxxx" ) ); } Patch "Disable Spin Charge Camera" in "Camera" by "Hyper" does /* Disables the zoom camera when charging a Spin Dash. Notes; - It is recommended that you use this with Increased Spin Charge Rotation Speed. */ { WriteNop ( /* 0x1408A67DC */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCF\xBB\x24\x00\x00\x00", "x????xxxxxxxx" ), 5 ); } Patch "Disable Jellyfish Camera Lock-On" in "Camera" by "Hyper" does "Disables the lock-on camera when the Jellyfish enemy in Ares jumps into the sky." { WriteProtected ( /* 0x1404EC078 */ ScanSignature ( "\x75\x08\x48\x8B\xCE\xE8\x00\x00\x00\x00\x45\x33\xC0\x48\x8B\xCE\x41\x8D\x50\x01\xE8\x00\x00\x00\x00\x41\xB0\x01\x33\xD2\x48\x8B\xCE\x48\x8B\x5C\x24\x00\x48\x8B\x74\x24\x00\x48\x83\xC4\x20\x5F\xE9\x00\x00\x00\x00", "xxxxxx????xxxxxxxxxxx????xxxxxxxxxxxx?xxxx?xxxxxx????" ), 0xEB ); WriteNop ( /* 0x1404ED414 */ ScanSignature ( "\xE8\x00\x00\x00\x00\x48\x8B\xCF\xE8\x00\x00\x00\x00\xBA\x00\x00\x00\x00\x48\x8B\xCF\xE8\x00\x00\x00\x00\xC6\x46\x50\x01\x80\x7E\x50\x00\x74\x2E\x0F\x28\xD6\x33\xD2\x48\x8B\xCF\xE8\x00\x00\x00\x00\x84\xC0\x74\x1D\x48\x8B\xCF\xE8\x00\x00\x00\x00\xBA\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\xCF\xE8\x00\x00\x00\x00\x48\x8B\x5C\x24\x00\x32\xC0\x48\x8B\x6C\x24\x00\x48\x8B\x74\x24\x00\x0F\x28\x74\x24\x00\x48\x83\xC4\x30\x5F\xC3", "x????xxxx????x????xxxx????xxxxxxxxxxxxxxxxxxx????xxxxxxxx????x????xxxx????xxxx????xxxx?xxxxxx?xxxx?xxxx?xxxxxx" ), 5 ); } Patch "Disable Sequence Colliders" in "Cheats" by "Hyper" does /* Disables invisible walls that are usually removed by specific events. This will not remove invisible walls surrounding the islands. */ { WriteProtected ( ScanSignature ( /* v1.41: 0x14968CE78 */ "\x0F\x84\x19\x01\x00\x00\x83\xE9\x01", "xxxxxxxxx" ), 0xEB, 0x16 ); } Code "Checkpoint Creator" in "Cheats" by "Hyper" does /* Allows you to create virtual checkpoints anywhere and restore them. Controller Layout; - LB + RB + LS + RS (for 1.5 seconds) - create checkpoint from position - LB + RB + LS + RS - restore position from checkpoint Keyboard Layout; - Plus - create checkpoint from position - Minus - restore position from checkpoint Notes; - It is recommended to have parry unlocked when using the controller layout. */ // #lib "BlackboardStatus" #lib "GameMode" #lib "Lua" #lib "Memory" #lib "Player" #lib "Time" #lib "Win32" #import "GOComponents" #load "System.Numerics.dll" using System.Numerics; static string _lastGameModeName = string.Empty; static Vector3 _checkpointPosition = Vector3.Zero; static Quaternion _checkpointRotation = Quaternion.Identity; static bool _isRecentRespawn = false; static bool _isInputBuffered = false; static float _inputTimer = 0.0f; static float _inputTimerThreshold = 1.5f; // { if (_lastGameModeName != GameMode.GetName()) { Lua.Call("LoadLevel", "zev_sonic_pow_up"); _checkpointPosition = Vector3.Zero; _checkpointRotation = Quaternion.Identity; _lastGameModeName = GameMode.GetName(); } if (!Win32.IsGameForegroundWindow()) return; if (!Memory.TryGetPointer(Player.Kinematics.Get(), out GOCPlayerKinematicParams* out_pKinematics)) return; bool isMinusKeyDown = (GetAsyncKeyState(Keys.OemMinus) & 0x8000) != 0; bool isPlusKeyDown = (GetAsyncKeyState(Keys.Oemplus) & 0x8000) != 0; if (isMinusKeyDown || (Player.Input.IsDown(Player.InputActionType.PlayerLightDash) && Player.Input.IsDown(Player.InputActionType.CameraGaze) && Player.Input.IsDown(Player.InputActionType.PlayerLeftStep) && Player.Input.IsDown(Player.InputActionType.PlayerRightStep))) { _isInputBuffered = true; _inputTimer = isMinusKeyDown ? _inputTimerThreshold : _inputTimer + Time.GetDeltaTime(); } else { _isInputBuffered = false; _isRecentRespawn = false; } if (_isRecentRespawn) _inputTimer = 0.0f; if (_inputTimer >= _inputTimerThreshold) { Player.Effect.PlayEffect("CheckpointEffect", "ef_ob_seed01_powerseed01_sonicbuff01"); Player.Sound.PlaySound("obj_pointmarker"); _checkpointPosition = out_pKinematics->Position; _checkpointRotation = out_pKinematics->Rotation; _isRecentRespawn = true; } else if (isPlusKeyDown || (_inputTimer > 0.0f && !_isInputBuffered)) { _inputTimer = 0.0f; if (_checkpointPosition == Vector3.Zero && _checkpointRotation == Quaternion.Identity) return; if (!isPlusKeyDown) { Player.Effect.PlayEffect("WarpEffect", "ef_ob_portalgate_out01"); Player.Sound.PlaySound("sn_sonic_boom"); } out_pKinematics->Position = _checkpointPosition; out_pKinematics->Rotation = _checkpointRotation; } } Patch "Always Sandstorm" in "Weather" by "Hyper" does /* Forces the weather to Sandstorm on supported islands. Supported islands; - Ares */ // #lib "Memory" // { void NOP(long addr) => WriteProtected(addr, 0xEB, 0x22); /* 0x1401EE652 */ long callerFuncAddr = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCB\x8B\xF0\xE8\xCC\xCC\xCC\xCC\x8B\xF8", "x????xxxxxx????xx" ); /* 0x1401EE3ED */ NOP(Memory.ReadCall(callerFuncAddr) + 0x2D); /* 0x1401EE4DD */ NOP(Memory.ReadCall(callerFuncAddr + 0x0A) + 0x2D); } Patch "Always Sunny" in "Weather" by "Hyper" does /* Forces the weather to Sunny on supported islands. Supported islands; - Kronos - Ares - Chaos - Rhea - Ouranos */ // #lib "Memory" // { void NOP(long addr) => WriteProtected(addr, 0xEB); /* 0x1401EE652 */ long callerFuncAddr = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCB\x8B\xF0\xE8\xCC\xCC\xCC\xCC\x8B\xF8", "x????xxxxxx????xx" ); /* 0x1401EE3ED */ NOP(Memory.ReadCall(callerFuncAddr) + 0x2D); /* 0x1401EE4DD */ NOP(Memory.ReadCall(callerFuncAddr + 0x0A) + 0x2D); } Patch "Disable Forced Weather for Bosses" in "Weather" by "Hyper" does "Disables the weather being forced to Sunny for Giganto and Supreme." // #lib "Memory" // { // Giganto Memory.WriteForceJump ( /* 0x1402A8186 */ ScanSignature ( "\x74\x0A\x33\xD2\x48\x8B\xC8\xE8\xCC\xCC\xCC\xCC\x48\x8B\x46\x18\x48\x8B\x48\x28\x48\x8B\x59\x48\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD8\x48\x85\xC0", "xxxxxxxx????xxxxxxxxxxxxx????xxxxxxx????xxxxxx" ) ); // Supreme Memory.WriteForceJump ( /* 0x14030AA45 */ ScanSignature ( "\x74\x0A\x33\xD2\x48\x8B\xC8\xE8\xCC\xCC\xCC\xCC\x48\x8B\x46\x18\x48\x8B\x48\x28\x48\x8B\x59\x48\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x45\x33\xE4", "xxxxxxxx????xxxxxxxxxxxxx????xxxxxxx????xxx" ) ); // Supreme (Another Story) Memory.WriteForceJump ( /* 0x14033668C */ ScanSignature ( "\x74\x0A\x33\xD2\x48\x8B\xC8\xE8\xCC\xCC\xCC\xCC\x48\x8B\x46\x18\x48\x8B\x48\x28\x48\x8B\x59\x48\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD8\x0F\x57\xF6", "xxxxxxxx????xxxxxxxxxxxxx????xxxxxxx????xxxxxx" ) ); } Patch "Always Rainy" in "Weather" by "Hyper" does /* Forces the weather to Rainy on supported islands. Supported islands; - Kronos - Chaos - Rhea - Ouranos */ // #lib "Memory" // { void NOP(long addr) => WriteProtected(addr, 0xEB, 0x38); /* 0x1401EE652 */ long callerFuncAddr = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCB\x8B\xF0\xE8\xCC\xCC\xCC\xCC\x8B\xF8", "x????xxxxxx????xx" ); /* 0x1401EE3ED */ NOP(Memory.ReadCall(callerFuncAddr) + 0x2D); /* 0x1401EE4DD */ NOP(Memory.ReadCall(callerFuncAddr + 0x0A) + 0x2D); } Patch "Always Cloudy" in "Weather" by "Hyper" does /* Forces the weather to Cloudy on supported islands. Supported islands; - Kronos - Ares - Chaos - Rhea - Ouranos */ // #lib "Memory" // { void NOP(long addr) => WriteProtected(addr, 0xEB, 0x4E); /* 0x1401EE652 */ long callerFuncAddr = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCB\x8B\xF0\xE8\xCC\xCC\xCC\xCC\x8B\xF8", "x????xxxxxx????xx" ); /* 0x1401EE3ED */ NOP(Memory.ReadCall(callerFuncAddr) + 0x2D); /* 0x1401EE4DD */ NOP(Memory.ReadCall(callerFuncAddr + 0x0A) + 0x2D); } Code "Always Night" in "Time" by "Hyper" does "Forces the time to always be 12:00 AM on the islands." // #lib "Lua" // { Lua.SetPrintPreviousError(false); Lua.Call("SetTime", 0.0f, 0.0f); Lua.Call("SetTimePause", true); Lua.SetPrintPreviousError(true); } Code "Always Day" in "Time" by "Hyper" does "Forces the time to always be 8:00 AM on the islands." // #lib "Lua" // { Lua.SetPrintPreviousError(false); Lua.Call("SetTime", 8.0f, 0.0f); Lua.Call("SetTimePause", true); Lua.SetPrintPreviousError(true); } Code "Always Sunrise" in "Time" by "Hyper" does "Forces the time to always be 4:15 AM on the islands." // #lib "Lua" // { Lua.SetPrintPreviousError(false); Lua.Call("SetTime", 4.0f, 15.0f); Lua.Call("SetTimePause", true); Lua.SetPrintPreviousError(true); } Patch "Disable Time Velocity Multiplier" in "Time" by "Hyper" does "Disables the time rate increasing based on how fast Sonic is moving." { WriteNop ( /* 0x1401D4B64 */ ScanSignature ( "\xF3\x0F\x10\x78\x04\xF3\x0F\x59\x75\x04", "xxxxxxxxxx" ), 5 ); } Code "Time Advancer" in "Time" by "Hyper" does /* Allows you to advance time forward or backward using hotkeys at a rate of one in-game hour per second. Keyboard Layout; - Page Up/Right Square Bracket - advance time forwards - Page Down/Left Square Bracket - advance time backwards */ // #lib "GameManager" #lib "Logger" #lib "Lua" #lib "Time" #lib "Win32" #import "Services" static bool _isUpdateTime = false; static float _hours = -1.0f; static float _minutes = -1.0f; static float _rate = 60.0f; static bool IsKeyDown(Keys in_keys) { return (GetAsyncKeyState(in_keys) & 0x8000) != 0; } // { var pTimeService = GameManager.GetService(); if (pTimeService == null) return; _hours = pTimeService->CurrentTime.Hours; if (!Win32.IsGameForegroundWindow()) return; float delta = Time.GetDeltaTime() * _rate; if (IsKeyDown(Keys.PageUp) || IsKeyDown(Keys.OemCloseBrackets)) { _minutes += 1.0f * delta; _isUpdateTime = true; } if (IsKeyDown(Keys.PageDown) || IsKeyDown(Keys.OemOpenBrackets)) { _minutes -= 1.0f * delta; _isUpdateTime = true; } if (_minutes > 59.0f) { _hours += 1.0f; _minutes = 0.0f; } else if (_minutes < 0.0f) { _hours -= 1.0f; _minutes = 59.0f; } if (_hours > 23.0f) { _hours = 0.0f; } else if (_hours < 0.0f) { _hours = 23.0f; } if (_isUpdateTime) { Logger.Utility($"[Time Advancer] Current Time: {_hours:00}:{_minutes:00}"); Lua.SetPrintPreviousError(false); Lua.Call("SetTime", _hours, _minutes); Lua.SetPrintPreviousError(true); _isUpdateTime = false; } } Code "Always Sunset" in "Time" by "Hyper" does "Forces the time to always be 8:45 PM on the islands." // #lib "Lua" // { Lua.SetPrintPreviousError(false); Lua.Call("SetTime", 20.0f, 45.0f); Lua.Call("SetTimePause", true); Lua.SetPrintPreviousError(true); } Patch "Disable Power Boost Audio" in "Audio" by "Hyper" { // Activation SFX WriteNop ( /* 0x1408D2B23 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\xBA\xA1\x23\x00\x00\x48\x8D\x4C\x24\x68", "x????xxxxxxxxxx" ), 5 ); // Trail SFX WriteProtected ( /* 0x141413C68 */ ScanSignature ( "sn_powerboost\0", "xxxxxxxxxxxxxx" ), System.Text.Encoding.UTF8.GetBytes("sn_boost_run\0") ); } Patch "Disable Water Audio Filter" in "Audio" by "Hyper" { WriteProtected ( /* 0x1408B5626 */ ScanSignature ( "\x74\x65\x84\xC9\x0F\x85\x31\x01\x00\x00", "xxxxxxxxxx" ), 0xEB ); } Patch "Disable Monologue Restrictions" in "Audio" by "WasifBoomz" does /* Removes restrictions for random monologue playback during gameplay. Notes; - This allows monologues to play anywhere, rather than only on heightmap terrain. */ { WriteProtected ( /* 0x1401CA016 */ ScanSignature ( "\x74\x0E\x8B\x47\x48", "xxxxx" ), 0xEB ); } Patch "Disable Decelerate Collision" in "Physics" by "Hyper" does /* Disables the collision flag that kills all horizontal velocity when jumping. Examples; - The bridge in Kronos above the river. - The cliffsides in Ares. */ { // v1.41: 0x14089A44F var sig = ScanSignature ( "\x89\x41\x34\x8B\x42\x38\x89\x41\x38\x8B\x42\x3C\x89\x41\x3C\x0F\xB6\x42\x40\x88\x41\x40\x48\x8B\xC1", "xxxxxxxxxxxxxxxxxxxxxxxxx" ); if (sig == 0) return; WriteAsmHook("and eax, 0xFFFFFDFF", sig, HookBehavior.After); } Patch "Tighter Jump Rotation" in "Physics" by "Hyper" does "Allows for tighter mid-air control for more precise movements when jumping, similar to SONIC THE HEDGEHOG (2006)." // static float Threshold = 0.05f; // { fixed (float* pThreshold = &Threshold) { WriteAsmHook ( $@" push rax mov rax, {(long)pThreshold} mulss xmm7, cs:[rax] maxss xmm0, xmm6 mulss xmm0, dword ptr [rsp + 0x140 + 0xFFFFFFFFFFFFFF30] pop rax ", /* 0x1407F562A */ ScanSignature ( "\xF3\x0F\x59\x3D\xCC\xCC\xCC\xCC\xF3\x0F\x5F\xC6", "xxxx????xxxx" ), HookBehavior.Replace ); } } Code "Reduced Homing Delay" in "Physics" by "Hyper" does "Reduces the delay after performing a homing attack, allowing you to perform chained homing attacks much quicker." // #lib "BlackboardStatus" static bool _isInitialised = false; static bool _isSuper = false; static float _delay = 0.2f; // { if (!_isInitialised) { fixed (bool* p_isSuper = &_isSuper) fixed (float* p_delay = &_delay) { WriteAsmHook ( $@" mov rdx, {(long)p_isSuper} cmp byte ptr [rdx], 0 jnz isSuper mov rdx, {(long)p_delay} movss xmm2, dword ptr [rdx] jmp exit isSuper: movss xmm2, dword ptr [r15 + rdi + 0x18] exit: mov edx, eax mov rcx, r13 mov dword ptr [rbp + 0x57 + 0x28], eax ", /* 0x14082379C */ ScanSignature ( "\xF3\x41\x0F\x10\x54\x3F\x18", "xxxxxxx" ), HookBehavior.Replace ); } _isInitialised = true; } _isSuper = BlackboardStatus.IsSuper(); } Code "Allow Gravity to Affect Parry" in "Physics" by "Hyper" does /* Applies gravity to air parry after a short period of time, based on the current difficulty setting. The air parry durations are as follows; - Easy: 3 seconds - Normal: 1.5 seconds - Hard: 1 second - Extreme: 0.8 seconds */ // #lib "BlackboardStatus" #lib "DeltaTime" #lib "GameManager" #lib "GameMode" #lib "Memory" #lib "Player" #import "BlackboardStatus" #import "GOComponents" #import "Services" #import "States" #load "System.Numerics.dll" using System.Collections.Generic; using System.Numerics; const float _normalGravity = -9.81f; const float _lowGravity = -3.27f; static bool _isLanded = false; static int _sfxHandle = 0; static float _gravity = -9.81f; static float _mass = 30.0f; static float _parryTime = 0.0f; static Dictionary _parryDurations = new() { { DifficultySetting.Easy, 3.0f }, { DifficultySetting.Normal, 1.5f }, { DifficultySetting.Hard, 1.0f }, { DifficultySetting.Extreme, 0.8f } }; static void PlayEffects() { if (_sfxHandle != 0) return; _sfxHandle = Player.Sound.PlaySound("sn_relative_wind"); Player.Effect.PlayEffect("AirParryEffect", "ef_ft_dash_ge01"); } static void StopEffects() { if (_sfxHandle == 0) return; fixed (int* p_sfxHandle = &_sfxHandle) Player.Sound.StopSound(p_sfxHandle); _sfxHandle = 0; Player.Effect.StopEffect("AirParryEffect"); } // { if (GameMode.GetName() == "GameModeCyberStage") { if (Memory.TryGetPointer(GameManager.GetService(), out var out_pLevelInfo) && out_pLevelInfo->pStageData != null) { if (out_pLevelInfo->pStageData->CyberMode == StageInfo.CyberModes.LowGravity) { _gravity = _lowGravity; } else { _gravity = _normalGravity; } } } else { _gravity = _normalGravity; } if (Player.State.GetCurrentStateID() != Sonic.StateID.StateParry) { StopEffects(); _parryTime = 0.0f; return; } // HACK: don't update when paused. if (GameManager.GetGameObject("MainMenu") != null || GameManager.GetGameObject("MapMenu") != null) return; if (!Memory.TryGetPointer(BlackboardStatus.Get(), out var out_pBlackboardStatus)) return; if (!Memory.TryGetPointer(Player.Kinematics.Get(), out var out_pKinematics)) return; if (BlackboardStatus.IsSuper()) return; var deltaTime = DeltaTime.GetDeltaTime(); _parryTime += deltaTime; if (Player.Status.IsGrounded()) { out_pKinematics->Velocity = Vector3.Zero; StopEffects(); if (!_isLanded) { Player.Animation.SetAnimation("LANDING_BATTLE"); _isLanded = true; } } else { _isLanded = false; var duration = _parryDurations[out_pBlackboardStatus->Difficulty]; var force = _mass * _gravity; var accel = force / _mass; if (_parryTime <= duration) { var easeGravityFactor = Math.Min(_parryTime / duration, 1.0f); var easeGravityCubic = easeGravityFactor * easeGravityFactor * easeGravityFactor; PlayEffects(); out_pKinematics->Velocity = new Vector3(0.0f, easeGravityCubic * accel * deltaTime, 0.0f); } else { out_pKinematics->Velocity += new Vector3(0.0f, accel * deltaTime, 0.0f); StopEffects(); } out_pKinematics->Position += out_pKinematics->Velocity * deltaTime; } } Code "Increased Spin Charge Rotation Speed" in "Physics" by "Hyper" does "Increases the rotation speed for the direction the player is aiming whilst charging a Spin Dash to closely match your analog stick direction." // #include "Reflection" noemit #lib "Reflection" #lib "SonicParameters" #lib "AmyParameters" #lib "KnucklesParameters" #lib "TailsParameters" // { var SonicParametersInfo = Reflection.GetDataInfo("player_common"); if (SonicParametersInfo.pData != null) RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, spinBoost.chargeRotateForce, 500.0f); var AmyParametersInfo = Reflection.GetDataInfo("amy_common"); if (AmyParametersInfo.pData != null) RFL_SET_PARAM(AmyParametersInfo, forwardView.spinBoost.chargeRotateForce, 500.0f); var KnucklesParametersInfo = Reflection.GetDataInfo("knuckles_common"); if (KnucklesParametersInfo.pData != null) RFL_SET_PARAM(KnucklesParametersInfo, forwardView.spinBoost.chargeRotateForce, 500.0f); var TailsParametersInfo = Reflection.GetDataInfo("tails_common"); if (TailsParametersInfo.pData != null) RFL_SET_PARAM(TailsParametersInfo, forwardView.spinBoost.chargeRotateForce, 500.0f); } Code "Retain Velocity from Enemy Bounce" in "Physics" by "Weezley" does "Retains the current velocity when bouncing off of enemies." // #include "Reflection" noemit #lib "AmyParameters" #lib "KnucklesParameters" #lib "Reflection" #lib "SonicParameters" #lib "TailsParameters" // { var AmyParametersInfo = Reflection.GetDataInfo("amy_common"); var KnucklesParametersInfo = Reflection.GetDataInfo("knuckles_common"); var SonicParametersInfo = Reflection.GetDataInfo("player_common"); var TailsParametersInfo = Reflection.GetDataInfo("tails_common"); if (AmyParametersInfo.pData != null) { RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.spinAttack.jumpForce, 12.0f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.spinAttack.jumpAddForce, 22.0f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.spinAttack.deceleForce, 2.5f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.spinAttack.acceleForce, 2.5f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.spinAttack.brakeForce, 0.5f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.spinAttack.limitSpeedMax, 70.0f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.spinAttack.jumpForce, 12.0f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.spinAttack.jumpAddForce, 22.0f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.spinAttack.deceleForce, 2.5f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.spinAttack.acceleForce, 2.5f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.spinAttack.brakeForce, 0.5f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.spinAttack.limitSpeedMax, 70.0f); } if (KnucklesParametersInfo.pData != null) { RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.spinAttack.jumpForce, 12.0f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.spinAttack.jumpAddForce, 22.0f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.spinAttack.deceleForce, 2.5f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.spinAttack.acceleForce, 2.5f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.spinAttack.brakeForce, 0.5f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.spinAttack.limitSpeedMax, 70.0f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.spinAttack.jumpForce, 12.0f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.spinAttack.jumpAddForce, 22.0f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.spinAttack.deceleForce, 2.5f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.spinAttack.acceleForce, 2.5f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.spinAttack.brakeForce, 0.5f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.spinAttack.limitSpeedMax, 70.0f); } if (SonicParametersInfo.pData != null) { RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.spinAttack.jumpForce, 12.0f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.spinAttack.jumpAddForce, 22.0f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.spinAttack.deceleForce, 2.5f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.spinAttack.acceleForce, 2.5f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.spinAttack.brakeForce, 0.5f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.spinAttack.limitSpeedMax, 70.0f); } if (TailsParametersInfo.pData != null) { RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.spinAttack.jumpForce, 12.0f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.spinAttack.jumpAddForce, 22.0f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.spinAttack.deceleForce, 2.5f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.spinAttack.acceleForce, 2.5f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.spinAttack.brakeForce, 0.5f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.spinAttack.limitSpeedMax, 70.0f); RFL_SET_PARAM(TailsParametersInfo, cyberspaceSV.modePackage.spinAttack.jumpForce, 12.0f); RFL_SET_PARAM(TailsParametersInfo, cyberspaceSV.modePackage.spinAttack.jumpAddForce, 22.0f); RFL_SET_PARAM(TailsParametersInfo, cyberspaceSV.modePackage.spinAttack.deceleForce, 2.5f); RFL_SET_PARAM(TailsParametersInfo, cyberspaceSV.modePackage.spinAttack.acceleForce, 2.5f); RFL_SET_PARAM(TailsParametersInfo, cyberspaceSV.modePackage.spinAttack.brakeForce, 0.5f); RFL_SET_PARAM(TailsParametersInfo, cyberspaceSV.modePackage.spinAttack.limitSpeedMax, 70.0f); } } Code "Retain Horizontal Velocity from Stomp" by "WasifBoomz" in "Physics" does /* While holding down the stomp button, stomp partially retains your last horizontal velocity, rather than falling straight down. Notes; - This will remove the cooldown before bounce jumps. - This will remove the shockwave from performing consecutive stomps. - This does not affect the shockwave from the "Super Stomp" code. */ // #lib "Sonic" #lib "Time" #load "System.Numerics.dll" using System.Numerics; const float stompStopForce = 20.0f; const float stompReleaseStopForce = 80.0f; static Vector3 prevVelocity; // { var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; float yVel = kinematics->Velocity.Y; bool isStompDown = Player.Input.IsDown(Player.InputActionType.PlayerStomping); if (Player.State.GetCurrentStateID() == Sonic.StateID.StateStompingLand) { if (isStompDown) Player.State.SetState(Sonic.StateID.StateBounceJump); else Player.State.SetState(Sonic.StateID.StateRun); kinematics->Velocity = prevVelocity; kinematics->Velocity.Y = yVel; } if (Player.State.GetCurrentStateID() == Sonic.StateID.StateStompingDown) { if (new Vector3(prevVelocity.X,0,prevVelocity.Z).Length() < stompStopForce * Time.GetDeltaTime()) kinematics->Velocity = Vector3.Zero; else kinematics->Velocity = Vector3.Normalize(new Vector3(prevVelocity.X, 0, prevVelocity.Z)) * (new Vector3(prevVelocity.X, 0, prevVelocity.Z).Length() - ((isStompDown ? stompStopForce : stompReleaseStopForce) * Time.GetDeltaTime())); kinematics->Velocity.Y = yVel; } prevVelocity = kinematics->Velocity; } Code "Classic Jump Deceleration" by "WasifBoomz" in "Physics" does /* Forces jump deceleration to be based on your current speed, similar to Classic Sonic games. Notes; - The "Jump Deceleration" option affects how much effect this has on you. */ // #include "Reflection" noemit #lib "Reflection" #lib "SonicParameters" #lib "AmyParameters" #lib "KnucklesParameters" #lib "TailsParameters" #lib "Memory" #lib "Sonic" #lib "Time" #lib "MathHelpers" #load "System.Numerics.dll" #load "System.Linq.dll" using System.Linq; using System.Numerics; const float airDragPowerMin = 0.1f; const float airDragPowerMax = 1.1f; const float maxYSpeed = 50; const float minYSpeed = -50; static float jumpDecelerationSetting; static bool isInitialised = false; static Sonic.StateID[] allowStates = { Sonic.StateID.StateJump, Sonic.StateID.StateDoubleJump, Sonic.StateID.StateBounceJump, Sonic.StateID.StateDoubleJump, Sonic.StateID.StateFall, Sonic.StateID.StateGrindJump, Sonic.StateID.StateGrindDoubleJump, Sonic.StateID.StateSliding, Sonic.StateID.StateDropDash }; // { if (!isInitialised) { fixed (float* pJumpDecelerationSetting = &jumpDecelerationSetting) { // Writes to the Jump Deceleration setting value WriteAsmHook ( $@" mov dword ptr [rcx+3Ch], 0 mov r9, {(long)pJumpDecelerationSetting} movss dword ptr [r9], xmm1 ret ", /* 0x14054D0A4 */ Memory.ReadCall ( /* 0x1408A98C0 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\xE9\xE9\x01\x00\x00\x48\x8B\x89\x48\x02\x00\x00", "x????xxxxxxxxxxxx" ) ), HookBehavior.Replace ); } isInitialised = true; } var SonicParametersInfo = Reflection.GetDataInfo("player_common"); var AmyParametersInfo = Reflection.GetDataInfo("amy_common"); var KnucklesParametersInfo = Reflection.GetDataInfo("knuckles_common"); var TailsParametersInfo = Reflection.GetDataInfo("tails_common"); if (SonicParametersInfo.pData != null) { RFL_SET_PARAM(SonicParametersInfo, forwardView.modePackage.jumpSpeed.baseAirDragScaleMin, 0.0f); RFL_SET_PARAM(SonicParametersInfo, forwardView.modePackage.jumpSpeed.baseAirDragScaleMax, 0.0f); RFL_SET_PARAM(SonicParametersInfo, cyberspace.modePackage.jumpSpeed.baseAirDragScaleMin, 0.0f); RFL_SET_PARAM(SonicParametersInfo, cyberspace.modePackage.jumpSpeed.baseAirDragScaleMax, 0.0f); RFL_SET_PARAM(SonicParametersInfo, cyberspaceSV.modePackage.jumpSpeed.baseAirDragScaleMin, 0.0f); RFL_SET_PARAM(SonicParametersInfo, cyberspaceSV.modePackage.jumpSpeed.baseAirDragScaleMax, 0.0f); } if (AmyParametersInfo.pData != null) { RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.jumpSpeed.baseAirDragScaleMin, 0.0f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.jumpSpeed.baseAirDragScaleMax, 0.0f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.jumpSpeed.baseAirDragScaleMin, 0.0f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.jumpSpeed.baseAirDragScaleMax, 0.0f); } if (KnucklesParametersInfo.pData != null) { RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.jumpSpeed.baseAirDragScaleMin, 0.0f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.jumpSpeed.baseAirDragScaleMax, 0.0f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.jumpSpeed.baseAirDragScaleMin, 0.0f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.jumpSpeed.baseAirDragScaleMax, 0.0f); } if (TailsParametersInfo.pData != null) { RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.jumpSpeed.baseAirDragScaleMin, 0.0f); RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.jumpSpeed.baseAirDragScaleMax, 0.0f); RFL_SET_PARAM(TailsParametersInfo, cyberspaceSV.modePackage.jumpSpeed.baseAirDragScaleMin, 0.0f); RFL_SET_PARAM(TailsParametersInfo, cyberspaceSV.modePackage.jumpSpeed.baseAirDragScaleMax, 0.0f); } var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; if (Player.Status.IsGroundedSpecial()) return; float yVel = kinematics->Velocity.Y; if (yVel < minYSpeed || yVel > maxYSpeed) return; if (Player.Kinematics.GetHorizontalMagnitude() < 5) return; if (!allowStates.Contains(Player.State.GetCurrentStateID())) return; kinematics->Velocity = new Vector3(kinematics->Velocity.X, 0, kinematics->Velocity.Z); kinematics->Velocity -= (Vector3.Normalize(kinematics->Velocity)) * (Player.Kinematics.GetHorizontalMagnitude() * Time.GetDeltaTime() * MathHelpers.Lerp(airDragPowerMin, airDragPowerMax,jumpDecelerationSetting)); kinematics->Velocity.Y = yVel; } Code "Enhanced Homing Attack Rebound" in "Physics" by "Weezley" does /* Increases overall player control during a Homing Attack rebound and reduces Homing Attack hit stop. Notes; - It is recommended that you use this with Tighter Jump Rotation. - Sonic's combat skills immediately after a Homing Attack will use their default bindings, so keep that in mind when combined with combat mods. - Reduces homing delay. */ // #include "BlackboardStatus" noemit #include "Reflection" noemit #lib "AmyParameters" #lib "GameObject" #lib "HMM" #lib "KnucklesParameters" #lib "Lua" #lib "Player" #lib "SonicParameters" #lib "Time" #load "System.Numerics.dll" using System.Numerics; using System.Collections.Generic; static bool isHomingAttack = false; static bool isInitialized = false; static bool useTrickAnim = false; static bool isDive = false; static bool isEnemy = false; static float homingTime = 0.3f; static float currentTime = 0; static string[] animRand = new[] { "U", "D", "L", "R" }; static Random rand = new Random(); // { if (!isInitialized) { useTrickAnim = HMM.GetCodes().Contains("Animation/Sonic/Homing Attack Trick Animations"); isInitialized = true; } Lua.Init(); Time.GetDeltaTime(); string homingTrickAnim = $"JUMP_TRICK_{animRand[rand.Next(0, 4)]}{rand.Next(0, 3)}"; if (BlackboardStatus.IsSuper()) return; if (IS_STATE_FLAG(IsDiving)) { isDive = true; } else if (Player.Status.IsGroundedSpecial()) { isDive = false; } var lockonTarget = Player.Status.GetLockOnTarget(); if (lockonTarget != null) { if (GameObject.GetGOC(lockonTarget, "GOCHealth") != null) { isEnemy = true; } else { isEnemy = false; } } if (Player.State.GetCurrentStateID() == Sonic.StateID.StateHomingFinished && Player.State.GetPreviousStateID() != Sonic.StateID.StateHomingAttackInStorm && !isDive) { Player.State.SetState(Sonic.StateID.StateRecoveryJump); //Temporarily disable Homing Attack to prevent no delay spamming Lua.Call("SetPlayerAbilityEnabled", "HomingAttack", false); } if (Player.State.GetCurrentStateID() == Sonic.StateID.StateRecoveryJump && Player.State.GetPreviousStateID() == Sonic.StateID.StateHomingFinished) { if (!isHomingAttack) { var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; if (Player.GetPlayerType() != Player.PlayerType.Amy) { kinematics->Velocity += new Vector3(0, 3.5f, 0); } else { //Amy rebounds way too high so remove vertical speed from hers to be more in line with the others kinematics->Velocity -= new Vector3(0, 7, 0); } if (useTrickAnim && Player.GetPlayerType() == Player.PlayerType.Sonic) { Player.Animation.SetAnimation(homingTrickAnim); } else { Player.Animation.SetAnimation("ATTACK_BOUNCE"); } isHomingAttack = true; } } else { isHomingAttack = false; currentTime = 0; } if (isHomingAttack) { currentTime += Time.GetDeltaTime(); if (currentTime >= homingTime) { Lua.Call("SetPlayerAbilityEnabled", "HomingAttack", true); } } else { //Making sure that Homing Attack is restored if the player exits the state before the timer counts up //I was gonna check and see if there are any places where Homing Attack is forcibly disabled, but it should be fine to always have it enabled anyways Lua.Call("SetPlayerAbilityEnabled", "HomingAttack", true); } var SonicParametersInfo = Reflection.GetDataInfo("player_common"); var AmyParametersInfo = Reflection.GetDataInfo("amy_common"); var KnucklesParametersInfo = Reflection.GetDataInfo("knuckles_common"); if (SonicParametersInfo.pData != null) { //Restoring the ability to use combo skills out of Homing Attack only if the target is an enemy RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitExistTarget[0], (isHomingAttack && isEnemy ? SonicParameters.Action.AcceleCombo1 : SonicParameters.Action.HomingAttack)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitExistTarget[1], (isHomingAttack && isEnemy ? SonicParameters.Action.ChargeAttack : SonicParameters.Action.Root)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitExistTarget[2], (isHomingAttack && isEnemy ? SonicParameters.Action.QuickCyloop : SonicParameters.Action.Root)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitExistTarget[3], (isHomingAttack && isEnemy ? SonicParameters.Action.SpinSlash : SonicParameters.Action.Root)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitExistTarget[4], (isHomingAttack && isEnemy ? SonicParameters.Action.Stomping : SonicParameters.Action.Root)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitExistTarget[5], (isHomingAttack && isEnemy ? SonicParameters.Action.SonicBoom : SonicParameters.Action.Root)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitInAir[0], (isHomingAttack && isEnemy ? SonicParameters.Action.AerialAcceleCombo1 : SonicParameters.Action.AerialHomingAttack)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitInAir[1], (isHomingAttack && isEnemy ? SonicParameters.Action.ChargeAttack : SonicParameters.Action.Root)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitInAir[2], (isHomingAttack && isEnemy ? SonicParameters.Action.AerialQuickCyloop : SonicParameters.Action.Root)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitInAir[4], (isHomingAttack && isEnemy ? SonicParameters.Action.Stomping : SonicParameters.Action.Root)); RFL_SET_PARAM(SonicParametersInfo, common.combo.comboTable.root.transitInAir[5], (isHomingAttack && isEnemy ? SonicParameters.Action.SonicBoom : SonicParameters.Action.Root)); RFL_SET_PARAM(SonicParametersInfo, common.commonPackage.attack.homingAttack.hitStopNameDead.pValue, 0); RFL_SET_PARAM(SonicParametersInfo, common.commonPackage.attack.homingAttackAir.hitStopNameDead.pValue, 0); RFL_SET_PARAM(SonicParametersInfo, forwardView.modePackage.homingAttack.sonicBounce.bounceHorzSpeed, 2.5f); RFL_SET_PARAM(SonicParametersInfo, cyberspace.modePackage.homingAttack.sonicBounce.bounceHorzSpeed, 2.5f); RFL_SET_PARAM(SonicParametersInfo, cyberspaceSV.modePackage.homingAttack.sonicBounce.bounceHorzSpeed, -2.5f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.homingAttack.sonicBounce.bounceVertSpeed, 17.0f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.homingAttack.sonicBounceWeak.bounceVertSpeed, 12.0f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.homingAttack.sonicBounceWeak.bounceHorzSpeed, 10.0f); } if (AmyParametersInfo.pData != null) { RFL_SET_PARAM(AmyParametersInfo, common.combo.comboTable.root.transitExistTarget[0], (isHomingAttack && isEnemy ? AmyParameters.Action.AmyTarotAttack : AmyParameters.Action.HomingAttack)); RFL_SET_PARAM(AmyParametersInfo, common.combo.comboTable.root.transitInAir[0], (isHomingAttack && isEnemy ? AmyParameters.Action.AmyTarotAttack : AmyParameters.Action.HomingAttack)); RFL_SET_PARAM(AmyParametersInfo, common.commonPackage.attack.homingAttack.hitStopNameDead.pValue, 0); RFL_SET_PARAM(AmyParametersInfo, common.commonPackage.attack.homingAttackAir.hitStopNameDead.pValue, 0); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.homingAttack.sonicBounce.bounceVertSpeed, 17.0f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.homingAttack.sonicBounce.bounceHorzSpeed, 2.5f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.homingAttack.sonicBounceWeak.bounceVertSpeed, 12.0f); RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.homingAttack.sonicBounceWeak.bounceHorzSpeed, 10.0f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.homingAttack.sonicBounce.bounceVertSpeed, 17.0f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.homingAttack.sonicBounce.bounceHorzSpeed, -2.5f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.homingAttack.sonicBounceWeak.bounceVertSpeed, 12.0f); RFL_SET_PARAM(AmyParametersInfo, cyberspaceSV.modePackage.homingAttack.sonicBounceWeak.bounceHorzSpeed, 10.0f); } if (KnucklesParametersInfo.pData != null) { RFL_SET_PARAM(KnucklesParametersInfo, common.combo.comboTable.root.transitExistTarget[0], (isHomingAttack && isEnemy ? KnucklesParameters.Action.KnucklesPunch1 : KnucklesParameters.Action.HomingAttack)); RFL_SET_PARAM(KnucklesParametersInfo, common.combo.comboTable.root.transitExistTarget[4], (isHomingAttack && isEnemy ? KnucklesParameters.Action.Stomping : KnucklesParameters.Action.Root)); RFL_SET_PARAM(KnucklesParametersInfo, common.combo.comboTable.root.transitInAir[0], (isHomingAttack && isEnemy ? KnucklesParameters.Action.KnucklesPunch1 : KnucklesParameters.Action.HomingAttack)); RFL_SET_PARAM(KnucklesParametersInfo, common.combo.comboTable.root.transitInAir[4], (isHomingAttack && isEnemy ? KnucklesParameters.Action.Stomping : KnucklesParameters.Action.Root)); RFL_SET_PARAM(KnucklesParametersInfo, common.commonPackage.attack.homingAttack.hitStopNameDead.pValue, 0); RFL_SET_PARAM(KnucklesParametersInfo, common.commonPackage.attack.homingAttackAir.hitStopNameDead.pValue, 0); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.homingAttack.sonicBounce.bounceVertSpeed, 17.0f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.homingAttack.sonicBounce.bounceHorzSpeed, 2.5f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.homingAttack.sonicBounceWeak.bounceVertSpeed, 12.0f); RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.homingAttack.sonicBounceWeak.bounceHorzSpeed, 10.0f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.homingAttack.sonicBounce.bounceVertSpeed, 17.0f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.homingAttack.sonicBounce.bounceHorzSpeed, -2.5f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.homingAttack.sonicBounceWeak.bounceVertSpeed, 12.0f); RFL_SET_PARAM(KnucklesParametersInfo, cyberspaceSV.modePackage.homingAttack.sonicBounceWeak.bounceHorzSpeed, 10.0f); } } Patch "Retain Horizontal Velocity from Jump" in "Physics" by "Hyper" does /* Retains the player's horizontal velocity when jumping. Notes; - This will allow you to retain velocity when jumping out of a Drop Dash. - The "Jump Deceleration" and "Maintain boost during a jump" options can remain active without conflicting with this code. */ // #lib "Memory" #lib "Player" static bool _isStateJump = false; // { fixed (bool* p_isStateJump = &_isStateJump) { // Update posture to allow retaining ground velocity. WriteAsmHook ( $@" mov rdi, rcx mov rdx, {(long)p_isStateJump} cmp byte ptr [rdx], 0 je default mov al, 1 jmp exit default: xor edx, edx mov rcx, [rcx + 0x28] ; RCX = BlackboardStatus mov eax, edx and eax, 0x3F movzx r8d, al mov eax, edx shr rax, 6 mov rax, [rcx + rax * 8 + 0x38] bt rax, r8 setb al exit: ", /* 0x1408B4846 */ Memory.ReadCall ( /* 0x1408F1A2C */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\x43\x20\xBA\x20\x16\x1E\x71\x44\x0F\x28\xC0\x48\x8B\x88\x80\x00\x00\x00\xE8\xCC\xCC\xCC\xCC\x48\x8B\xC8\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCB\x0F\x28\xF8\xE8\xCC\xCC\xCC\xCC\x48\x8B\xC8\xE8\xCC\xCC\xCC\xCC\x48\x8D\x55\xE7", "x????xxxxxxxxxxxxxxxxxxxxx????xxxx????xxxxxxx????xxxx????xxxx" ) ) + 6, HookBehavior.Replace ); } Sonic.StateID NotifyStateJump(Sonic.StateID in_stateId, Sonic.StateID[] in_stateStackTrace) { _isStateJump = in_stateId is Sonic.StateID.StateJump or Sonic.StateID.StateGrindJump; return in_stateId; } Player.State.AddStateNotifyAction(NotifyStateJump); } Patch "Disable Spin Charge Air Deceleration" in "Physics" by "Hyper" does /* Disables the deceleration when charging a spin dash in the air. Notes; - It is recommended that you use this with Disable Spin Charge Camera. */ { WriteNop ( /* 0x1408FFBB5 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x0F\xB6\x5E\x28", "x????xxxx" ), 5 ); } Code "Retain Velocity When Jumping Up Slopes" in "Physics" by "Weezley" does "Retains the current ground velocity when jumping from a steep slope." // #include "Reflection" noemit #lib "AmyParameters" #lib "KnucklesParameters" #lib "Reflection" #lib "SonicParameters" #lib "TailsParameters" // { var AmyParametersInfo = Reflection.GetDataInfo("amy_common"); var KnucklesParametersInfo = Reflection.GetDataInfo("knuckles_common"); var SonicParametersInfo = Reflection.GetDataInfo("player_common"); var TailsParametersInfo = Reflection.GetDataInfo("tails_common"); if (AmyParametersInfo.pData != null) { RFL_SET_PARAM(AmyParametersInfo, forwardView.modePackage.jumpSpeed.limitUpSpeed, 40.0f); } if (KnucklesParametersInfo.pData != null) { RFL_SET_PARAM(KnucklesParametersInfo, forwardView.modePackage.jumpSpeed.limitUpSpeed, 40.0f); } if (SonicParametersInfo.pData != null) { RFL_SET_PARAM(SonicParametersInfo, forwardView.modePackage.jumpSpeed.limitUpSpeed, 40.0f); } if (TailsParametersInfo.pData != null) { RFL_SET_PARAM(TailsParametersInfo, forwardView.modePackage.jumpSpeed.limitUpSpeed, 40.0f); } } Code "Print Position" in "Debug" by "Hyper" does /* Prints the current player position to the debug console every frame. This code requires the debug console to be enabled in Hedge Mod Manager to have any effect. */ // #lib "Memory" #lib "Player" #import "GOComponents" // { if (!Memory.TryGetPointer(Player.Kinematics.Get(), out var out_pKinematics)) return; Console.WriteLine($"[Position] {out_pKinematics->Position}"); } Code "Print Rotation" in "Debug" by "Hyper" does /* Prints the current player rotation to the debug console every frame. This code requires the debug console to be enabled in Hedge Mod Manager to have any effect. */ // #lib "Memory" #lib "Player" #import "GOComponents" // { if (!Memory.TryGetPointer(Player.Kinematics.Get(), out var out_pKinematics)) return; Console.WriteLine($"[Rotation] {out_pKinematics->Rotation}"); } Code "Print State ID" in "Debug" by "Hyper" does /* Prints the current player state ID to the debug console every frame. This code requires the debug console to be enabled in Hedge Mod Manager to have any effect. */ // #lib "Player" // { var stateIdNo = (int)Player.State.GetCurrentStateID(); switch (Player.GetPlayerType()) { case Player.PlayerType.Sonic: Console.WriteLine($"[State ID] Sonic: {Player.State.GetCurrentStateID()} ({stateIdNo})"); break; case Player.PlayerType.Amy: Console.WriteLine($"[State ID] Amy: {Player.State.GetCurrentStateID()} ({stateIdNo})"); break; case Player.PlayerType.Knuckles: Console.WriteLine($"[State ID] Knuckles: {Player.State.GetCurrentStateID()} ({stateIdNo})"); break; case Player.PlayerType.Tails: Console.WriteLine($"[State ID] Tails: {Player.State.GetCurrentStateID()} ({stateIdNo})"); break; } } Code "Print Stage Info" in "Debug" by "Hyper" does /* Prints information about the stage currently being loaded once. This code requires the debug console to be enabled in Hedge Mod Manager to have any effect. */ // #lib "GameManager" #import "Collections" #import "Services" using System.Collections.Generic; static string _lastStageName = string.Empty; /* Anything not in this list can get away with just being made lowercase instead. */ static Dictionary _flagNames = new() { { "DeleteFallDeadCollision", "deleteFalldeadCol" }, { "DeleteAirWallCollision", "deleteAirwallCol" }, { "DeleteGrindRail", "deleteGrindrail" }, { "ChangeNewCollision", "changeNewCol" }, { "LowGravity", "low-gravity" }, { "TimeExtend", "time-extend" }, { "SpeedScale", "speed-scale" }, { "MaxSpeedChallenge", "maxspeed-challenge" } }; static void PrintFlags(long in_flags, Type in_enumType) { var result = string.Empty; foreach (var @enum in Enum.GetValues(in_enumType)) { if ((in_flags & (1L << (int)@enum)) != 0) { if (!string.IsNullOrEmpty(result)) result += " | "; var name = @enum.ToString(); if (_flagNames.ContainsKey(name)) { result += _flagNames[name]; } else { result += name.ToLower(); } } } if (string.IsNullOrEmpty(result)) { Console.Write("N/A"); } else { Console.Write(result); } Console.Write("\r\n"); } static string GetCyberModeName(byte in_flags) { if (in_flags == 0) return "N/A"; var result = ((StageInfo.CyberModes)in_flags).ToString(); if (_flagNames.ContainsKey(result)) return _flagNames[result]; return result.ToLower(); } static void PrintSectors(ObjectMoveArray in_sectors) { foreach (var sector in in_sectors) Console.Write($"{sector:X2} "); Console.Write("\r\n"); } static void PrintRanks(StageInfo.StageData.RankTimes in_ranks) { Console.Write($"S = {in_ranks.S}, A = {in_ranks.A}, B = {in_ranks.B}, C = {in_ranks.C}\r\n"); } // { if (!Memory.TryGetPointer(GameManager.GetService(), out var out_pLevelInfo)) return; if (!Memory.TryGetPointer(out_pLevelInfo->pStageData, out var out_pStageData)) return; var stageName = out_pStageData->Name.ToString(); if (stageName == _lastStageName) return; Console.WriteLine($"[Stage] name ------------------- : {stageName}"); Console.WriteLine($"[Stage] scene_param_name ------- : {out_pStageData->SceneParamName.ToString()}"); Console.WriteLine($"[Stage] stage ------------------ : {out_pStageData->Location.ToString()}"); Console.WriteLine($"[Stage] cyber_name ------------- : {out_pStageData->CyberName.ToString()}"); Console.WriteLine($"[Stage] stage_no --------------- : {out_pStageData->StageIndex}"); Console.WriteLine($"[Stage] cyber_stage_no --------- : {out_pStageData->CyberStageIndex}"); Console.WriteLine($"[Stage] world_no --------------- : {out_pStageData->WorldIndex}"); Console.WriteLine($"[Stage] default_scene_param_no - : {out_pStageData->DefaultSceneParamIndex}"); Console.Write($"[Stage] attrs ------------------ : "); PrintFlags(out_pStageData->AttributeFlags, typeof(StageInfo.Attributes)); Console.Write($"[Stage] mission ---------------- : "); PrintFlags(out_pStageData->MissionFlags, typeof(StageInfo.Missions)); Console.Write($"[Stage] static_sectors --------- : "); PrintSectors(out_pStageData->StaticSectors); Console.Write($"[Stage] dynamic_sectors -------- : "); PrintSectors(out_pStageData->DynamicSectors); Console.WriteLine($"[Stage] timelimit -------------- : {out_pStageData->TimeLimit}"); Console.WriteLine($"[Stage] deadheight ------------- : {out_pStageData->DeadHeight}"); Console.WriteLine($"[Stage] noisetime -------------- : {out_pStageData->NoiseTime}"); Console.WriteLine($"[Stage] ring_mission ----------- : {out_pStageData->RingMissionThreshold}"); Console.WriteLine($"[Stage] cyber_mode ------------- : {GetCyberModeName((byte)out_pStageData->CyberMode)}"); Console.Write($"[Stage] rank ------------------- : "); PrintRanks(out_pStageData->Ranks); Console.Write($"[Stage] rank_veryhard ---------- : "); PrintRanks(out_pStageData->RanksVeryHard); Console.Write($"[Stage] rank_challenge --------- : "); PrintRanks(out_pStageData->RanksChallenge); Console.Write($"[Stage] rank_challenge_all ----- : "); PrintRanks(out_pStageData->RanksChallengeAll); _lastStageName = stageName; } Code "Print Velocity" in "Debug" by "Hyper" does /* Prints the current player velocity to the debug console every frame. This code requires the debug console to be enabled in Hedge Mod Manager to have any effect. */ // #lib "Memory" #lib "Player" #import "GOComponents" // { if (!Memory.TryGetPointer(Player.Kinematics.Get(), out var out_pKinematics)) return; Console.WriteLine($"[Velocity] {out_pKinematics->Velocity.Length():000.000000} m/s ({out_pKinematics->Velocity})"); } Patch "Boot Directly to Title" in "System" by "Hyper" { WriteNop ( /* 0x140AC0D9F */ ScanSignature ( "\x75\x08\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x48\x81\xC4\x98\x00\x00\x00", "xxxxxx????xxxxxxx" ), 2 ); } Patch "Disable Telemetry" in "System" by "RagdollClash & Still" does /* Prevents the game from sending telemetry and crash data to SEGA. Notes; - Crash dumps are moved to ''%LOCALAPPDATA%/CrashDumps'' - The data that's sent can include, but is not limited to; - motherboard information - HWID - OS product version - Steam user ID - CPU name - RAM - game open time - game close time */ { /* 0x14007A440 [SGAAS: Open] */ long sgaasOpen = ScanSignature ( "\x40\x55\x53\x56\x57\x48\x8D\xAC\x24\x00\x00\x00\x00\x48\x81\xEC\x00\x00\x00\x00\x48\x8B\xD9\xC6\x05\x00\x00\x00\x00\x00\x48\x8D\x0D\x00\x00\x00\x00\x49\x8B\xF0\x48\x8B\xFA\xFF\x15\x00\x00\x00\x00\xB9\x00\x00\x00\x00\x48\x89\x1D\x00\x00\x00\x00\x48\x89\x3D\x00\x00\x00\x00\x48\x89\x35\x00\x00\x00\x00", "xxxxxxxxx????xxx????xxxxx?????xxx????xxxxxxxx????x????xxx????xxx????xxx????" ); if (sgaasOpen != 0) // To prevent conflict with Quick Boot. WriteProtected(sgaasOpen, 0xC3); /* 0x140079F20 [SGAAS: Heartbeat] */ WriteProtected ( ScanSignature ( "\x48\x89\x5C\x24\x00\x48\x89\x7C\x24\x00\x55\x48\x8D\xAC\x24\x00\x00\x00\x00\x48\x81\xEC\x00\x00\x00\x00\x66\x0F\x6F\x05\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x66\x0F\x6F\xC8\x66\x0F\x7F\x45\x00\x41\xB8\x00\x00\x00\x00\xC6\x44\x24\x00\x00", "xxxx?xxxx?xxxxx????xxx????xxxx????xxx????xxxxxxxx?xx????xxx??" ), 0xC3 ); /* 0x14007B7E0 [SGAAS: Close] */ WriteProtected ( ScanSignature ( "\x48\x8B\xC4\x55\x48\x8D\xA8\x00\x00\x00\x00\x48\x81\xEC\x00\x00\x00\x00\x80\x3D\x00\x00\x00\x00\x00\x0F\x84\x00\x00\x00\x00\x66\x0F\x6F\x05\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x89\x58\x10\x48\x8D\x4C\x24\x00\x66\x0F\x6F\xC8\x48\x89\x78\x18\x41\xB8\x00\x00\x00\x00", "xxxxxxx????xxx????xx?????xx????xxxx????xxx????xxxxxxxx?xxxxxxxxxx????" ), 0xC3 ); /* 0x14007DFC0 [Crashpad: Folder] */ WriteProtected ( ScanSignature ( "\x40\x53\x48\x81\xEC\x00\x00\x00\x00\x48\x8B\xD9\xE8\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8D\x4C\x24\x00\xC7\x44\x24\x00\x00\x00\x00\x00\x48\x89\x4C\x24\x00\x48\x8D\x54\x24\x00", "xxxxx????xxxx????xxxx????xxxx?xxx?????xxxx?xxxx?" ), 0xC3 ); /* 0x14007EA30 [Crashpad: Data] */ WriteProtected ( ScanSignature ( "\x40\x55\x53\x56\x57\x41\x55\x48\x8D\xAC\x24\x00\x00\x00\x00\xB8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x2B\xE0\x45\x33\xED\x4C\x89\xA4\x24\x00\x00\x00\x00\x4C\x89\x6D\xA0\x41\x8D\x4D\x60\xE8\x00\x00\x00\x00\x66\x0F\x6F\x05\x00\x00\x00\x00\x48\x89\x00", "xxxxxxxxxxx????x????x????xxxxxxxxxx????xxxxxxxxx????xxxx????xxx" ), 0xC3 ); } Patch "Always Run in the Background" in "System" by "NM" does "Stops the game from pausing when the window is unfocused." { WriteProtected ( /* 0x140BB8884 */ ScanSignature ( "\x74\x2D\xC6\x02\x01\x41\xB0\x01\xEB\x1C\x84\xC0\x74\x21\x48\x8B\x53\x08\x48\x85\xD2\x74\x18\x48\x8B\x52\x28\x48\x85\xD2\x74\x0F\xC6\x02\x00\x45\x33\xC0\x48\x8D\x4A\x58\xE8\xFD\x60\x00\x00\x0F\xB7\x8B\x68\x01\x00\x00\xBA\xDF\xFF\x00\x00\x0F\xB7\xC1\x66\x83\xC9\x20\x66\x23\xC2\x83\xFF\x07\x66\x0F\x44\xC8\x33\xC0\x66\x89\x8B\x68\x01\x00\x00\x48\x8B\x5C\x24\x40\x48\x83\xC4\x30\x5F\xC3", "x?xxxxxxx?xxx?xxx?xxxx?xxx?xxxx?xxxxxxxxx?x???????????xxxxxxxxxxxxxxxxxxxxxxxxxxx????xxxx?xxxxxx" ), 0xEB ); } Patch "Centre Game Window on Launch" in "System" by "Hyper" // #load "System.Drawing.dll" #load "System.Xml.dll" using System.Drawing; using System.IO; using System.Xml.Serialization; [XmlRoot(ElementName = "ScreenSetting")] public class ScreenSetting { [XmlAttribute(AttributeName = "left")] public int Left { get; set; } [XmlAttribute(AttributeName = "top")] public int Top { get; set; } [XmlAttribute(AttributeName = "width")] public int Width { get; set; } [XmlAttribute(AttributeName = "height")] public int Height { get; set; } [XmlAttribute(AttributeName = "resolutionWidth")] public int ResolutionWidth { get; set; } [XmlAttribute(AttributeName = "resolutionHeight")] public int ResolutionHeight { get; set; } [XmlAttribute(AttributeName = "fullscreenStyle")] public int FullscreenStyle { get; set; } [XmlAttribute(AttributeName = "fullscreenState")] public int FullscreenState { get; set; } } [System.Runtime.InteropServices.DllImport("user32.dll")] static extern int GetSystemMetrics(int nIndex); static Size GetScreenSize() => new Size(GetSystemMetrics(0), GetSystemMetrics(1)); static int GetTitleBarHeight() => GetSystemMetrics(31); // { string xml = Path.Combine ( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"SEGA\SonicFrontiers\steam\x64\screen_setting.xml" ); if (!File.Exists(xml)) { Console.WriteLine($"[Centre Game Window on Launch] Code halted, file not found: {xml}"); return; } try { using (StringReader reader = new StringReader(File.ReadAllText(xml))) { var screenSetting = (ScreenSetting)new XmlSerializer(typeof(ScreenSetting)).Deserialize(reader); Size screen = GetScreenSize(); int left = (screen.Width / 2) - (screenSetting.Width / 2); int top = ((screen.Height / 2) - (screenSetting.Height / 2)) - GetTitleBarHeight(); if (left < 0) { Console.WriteLine("[Centre Game Window on Launch] Invalid X position! Defaulting to zero..."); left = 0; } if (top < 0) { Console.WriteLine("[Centre Game Window on Launch] Invalid Y position! Defaulting to zero..."); top = 0; } // Force new left value as default value. WriteAsmHook ( $"mov dword ptr [rbx], 0x{left:X}", /* 0x150B29868 */ ScanSignature ( "\x4D\x85\xFF\x74\x3A\x48\x85\xF6", "xxxxxxxx" ), HookBehavior.Replace ); // Force new top value as default value. WriteAsmHook ( $"mov dword ptr [rbx + 4], 0x{top:X}", /* 0x150B29877 */ ScanSignature ( "\x48\x85\xC0\x74\x2B\x4C\x89\xF9", "xxxxxxxx" ), HookBehavior.Replace ); } } catch (Exception ex) { Console.WriteLine($"[Centre Game Window on Launch] {ex}"); return; } // Kill XML value reading for left. WriteNop ( /* 0x150B29887 */ ScanSignature ( "\x89\x03\xE8\xCC\xCC\xCC\xCC\x48\x89\xE9", "xxx????xxx" ), 7 ); // Kill XML value reading for top. WriteNop ( /* 0x150B29891 */ ScanSignature ( "\x89\x43\x04\xE8\xCC\xCC\xCC\xCC\x4C\x89\xF1", "xxxx????xxx" ), 3 ); } Code "Disable Mouse Input" in "System" by "Hyper" does /* Disables input from the mouse and unhooks the cursor from the game window. Notes; - This is mainly useful for debugging, to prevent the game stealing focus from debuggers (e.g. Cheat Engine) when modal windows are opened. - This code is incompatible with Always Hide Mouse Cursor, but the cursor will no longer be in inconvenient locations whilst visible. */ // [System.Runtime.InteropServices.DllImport("user32.dll")] static extern int ShowCursor(bool bShow); static bool IsInitialised = false; // { /* There's way too many calls to this in the game, I'm just gonna force ShowCursor() every frame. */ ShowCursor(true); if (IsInitialised) return; // Disable pointing for menus. WriteProtected ( /* 0x140E37536 */ ScanSignature ( "\x74\x6C\x48\x8D\x4C\x24\x48", "xxxxxxx" ), 0xEB ); // Disable mouse axis mapping. WriteProtected ( /* 0x140E36EB0 */ ScanSignature ( "\x81\xC2\x00\x00\xFC\xFF\x83\xFA\x0C", "xxxxxxxxx" ), Assemble("xorps xmm0, xmm0\n ret") ); // Disable mouse cursor hook. WriteProtected ( /* 0x140E2B6D9 */ ScanSignature ( "\x0F\x28\xF1\x48\x85\xDB\x74\x6C", "xxxxxxxx" ), 0xE9, 0x8D, 0x00, 0x00, 0x00 ); // Disable mouse cursor clipping. WriteProtected ( /* 0x140C7D7F0 */ ScanSignature ( "\x0F\x84\x63\xFF\xFF\xFF\x48\x8D\x55\xC8", "xxxxxxxxxx" ), 0xE9, 0x64, 0xFF, 0xFF, 0xFF ); // Disable mouse cursor position override on focus change. WriteProtected ( /* 0x140C7D725 */ ScanSignature ( "\x74\x24\x48\x8B\x08\x48\x8D\x55\xC8", "xxxxxxxxx" ), 0xEB ); /* 0x140C7D725 */ long sig = ScanSignature ( "\x48\x85\xC9\x74\x1B\x48\x8D\x54\x24\x20", "xxxxxxxxxx" ); // Disable mouse cursor position override on foreground window change. WriteProtected(sig, Assemble("xor rcx, rcx")); WriteProtected(sig + 0x03, 0xEB); IsInitialised = true; } Patch "Disable Keyboard Input" in "System" by "Hyper" does "Disables input from the keyboard." { WriteProtected ( /* 0x140E11CC6 */ ScanSignature ( "\x0F\x84\x9C\x00\x00\x00\x48\x8B\xB7\xB8\x01\x00\x00", "xxxxxxxxxxxxx" ), 0xE9, 0x9D, 0x00, 0x00, 0x00 ); } Patch "Disable FPS Limit (experimental)" in "Graphics/Display" by "NM & RagdollClash" does /* Disables the framerate limiter, allowing the game to run above its targeted 30/60 FPS limit. Known issues; - The game speed can fluctuate. - The final QTE for Wyvern takes a long time to show up. - The falling platforms in Cyber Space levels 2-5, 2-7, and 3-3 will activate more quickly. - The spawn point in Cyber Space 4-3 will throw you into an invisible wall. - The light dash may disconnect from the path in some cases. */ // #lib "Memory" // { /* At the moment, this is the best method I have found for uncapping FPS. There are **most likely** much better ways of removing the FPS cap, and there is definitely room for improvement within this script. This script utilizes two steps to eliminate the cap, all of which will be outlined below. */ /* Frontiers seemingly utilizes a sleep function when limiting FPS, and so we must first prevent that function from being called. By NOPing these opcodes and not changing anything else, however, the game will speed up. */ WriteNop ( /* v1.41: 0x140D64D50 */ ScanSignature ( "\xE8\x00\x00\x00\x00\x48\x8D\x4C\x24\x00\xE8\x00\x00\x00\x00\x48\x8B\x4C\x24\x00\x48\x8B\x43\x20", "x????xxxx?x????xxxx?xxxx" ), 5 ); /* The change in speed is seemingly caused by the cap not being in sync with the current FPS. To fix this, we must first uncap the value of a current FPS address. The cap is controlled by the opcode "cmova rax, rdi," where RAX is the calculated current FPS and RDI is the user's set FPS cap. To remove this, we will be scanning for the opcode before it. From 0x140D622E1 to 0x140D622EA, there are 15 bytes. This will allow us to successfully write the hook, which is 14 bytes long. */ WriteAsmHook ( /* To get rid of the opcode which enforces the cap, we simply do not include it. We can also remove "comiss xmm1, dword ptr [rdi]," which invokes the comparison. With the current FPS address' value uncapped (EAX), we can now write it to the FPS cap address, which is stored in RDI. This will sync the FPS cap with the actual FPS, fixing the speedup issue. */ @" mov eax, dword ptr [rax] mov dword ptr [rbx+00000144h], eax mov dword ptr [rdi], eax ", /* v1.41: 0x140D64E21 */ ScanSignature ( "\x0F\x2F\x0F\x48\x0F\x47\xC7\x8B\x00\x89\x83\x00\x00\x00\x00", "xxxxxxxxxxx????" ), HookBehavior.Replace ); /* This removes the framerate limiting code for cutscenes. */ /* v1.41: 0x140146A1C */ long instrAddr = ScanSignature ( "\x74\x23\x48\x8B\x05\xCC\xCC\xCC\xCC\xF3\x0F\x10\x0D", "xxxxx????xxxx" ); if (instrAddr != 0) Memory.WriteForceJump(instrAddr); /* Frontiers limits the monitor refresh rate to 60hz and forces VSync when in fullscreen. To prevent the game from doing this, we set both of these bytes to 0. */ /* v1.41: 0x1410EC6CE */ instrAddr = ScanSignature ( "\xC7\x45\x00\x3C\x00\x00\x00\xC7\x45\x00\x01\x00\x00\x00", "xx?x???xx?x???" ); WriteProtected(instrAddr + 3, 0); WriteProtected(instrAddr + 10, 0); } Patch "Disable FPS Limit in Cutscenes (experimental)" in "Graphics/Display" by "RagdollClash" does /* Disables the framerate limiter for (most) cutscenes, allowing them to run at 60 FPS. Known issues; - Certain cutscenes will still operate at 30 FPS due to how this game syncs cutscene audio. */ // #lib "Memory" // { /* v1.41: 0x140146A1C */ long jmpAddr = ScanSignature ( "\x74\x23\x48\x8B\x05\xCC\xCC\xCC\xCC\xF3\x0F\x10\x0D", "xxxxx????xxxx" ); if (jmpAddr == 0) return; Memory.WriteForceJump(jmpAddr); } Code "Adjust Aspect Ratio to Resolution (experimental)" in "Graphics/Display" by "RagdollClash & Hyper" does /* Dynamically adjusts the aspect ratio to match the game resolution (recommended for non-16:9 resolutions). Notes; - This code will still function at 16:9 resolutions, but will only fix minor aspect ratio issues (such as improper cutscene aspect ratio). - The UI will be stretched automatically for square or portrait resolutions. Known issues; - Certain UI effects are rendered at the correct aspect ratio, but will misalign due to the main UI still being 16:9. - Certain UI elements are still rendered at 16:9 and will misalign or stretch. - Certain UI elements will be cut off incorrectly at wider aspect ratios (e.g. Juke Box). - Pre-rendered cutscenes will stretch to your aspect ratio. - The letterboxing during cutscenes will end up blocking the view at wider aspect ratios, it is highly recommended to use the Disable In-Game Letterboxing code to remove it. - The expected aspect ratio will only apply to a newly set resolution when you re-enter the resolution list and select the same resolution again. - Vignette (the circular shadowing effect on the screen) is still rendered at 16:9, it is highly recommended to use the Disable Vignette code to remove it. */ // #lib "Win32" #load "System.Drawing.dll" using System.Diagnostics; using System.Drawing; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] struct RECT { public int Left; public int Top; public int Right; public int Bottom; } [DllImport("user32.dll")] static extern bool GetClientRect(IntPtr hWnd, ref RECT lpRect); [DllImport("kernel32.dll")] static extern IntPtr GetConsoleWindow(); static bool _isInitialised = false; static float _aspectRatio = 1920.0f / 1080.0f; static float _eventFieldOfView = 0.0f; static long _mainAspectRatioAddr = 0; static long _surfRideAspectRatioAddr = 0; static long _surfRideAspectRatioJumpAddr = 0; static long _dvSceneAspectRatioAddr = 0; // { if (!_isInitialised) { long mainAspectRatioInstrAddr = ScanSignature ( /* 0x14014BD46 */ "\xF3\x0F\x59\x0D\x00\x00\x00\x00\x44\x8B\x84\x24\x00\x00\x00\x00\xF3\x0F\x2C\xD1\xEB\x0C\x8B\x94\x24\x00\x00\x00\x00\xF3\x44\x0F\x2C\xC0\x3B\x54\x24\x34\x75\x07\x44\x3B\x44\x24\x00\x74\x0C\x48\x8B\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\xCF", "xxxx????xxxx????xxxxxxxxx????xxxxxxxxxxxxxxx?xxxxx????x????xxx" ); /* 0x14126A22C */ _mainAspectRatioAddr = mainAspectRatioInstrAddr + Read(mainAspectRatioInstrAddr + 4) + 8; /* 0x140A4166B */ _surfRideAspectRatioAddr = ScanSignature ( "\x0F\x84\x98\x00\x00\x00\x48\x8B\x4E\x48", "xxxxxxxxxx" ); /* 0x140A41709 */ _surfRideAspectRatioJumpAddr = _surfRideAspectRatioAddr + Read(_surfRideAspectRatioAddr + 2) + 6; /* 0x140C33A2C */ _dvSceneAspectRatioAddr = ScanSignature ( "\xC7\x81\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x28\x05\x00\x00\x00\x00\x0F\x29\x81\x00\x00\x00\x00\x0F\x28\x0D\x00\x00\x00\x00", "xx????????xxx????xxx????xxx????" ); fixed (float* p_aspectRatio = &_aspectRatio) fixed (float* p_eventFieldOfView = &_eventFieldOfView) { WriteAsmHook ( $@" push r9 ; check if current event aspect ratio has been modified mov r9, {(long)p_aspectRatio} movss xmm0, dword ptr [r9] movss xmm1, dword ptr [rbx + 0x58] comiss xmm0, xmm1 je exit ; multiply original aspect ratio by new aspect ratio movss xmm0, dword ptr [rbx + 0x58] mov r9, {(long)p_aspectRatio} movss xmm1, dword ptr [r9] divps xmm0, xmm1 movss xmm1, xmm0 ; compute new field of view from aspect ratio difference movss xmm0, dword ptr [rbx + 0x54] mulps xmm0, xmm1 movss dword ptr [rbx + 0x54], xmm0 mov r9, {(long)p_eventFieldOfView} movss dword ptr [r9], xmm0 ; set new aspect ratio mov r9, {(long)p_aspectRatio} mov r9d, dword ptr [r9] mov dword ptr [rbx + 0x58], r9d exit: pop r9 movups xmm0, xmmword ptr [rbx + 0x4C] movups xmmword ptr [r13], xmm0 movups xmm1, xmmword ptr [rbx + 0x5C] movups xmmword ptr [r13 + 0x10], xmm1 ", /* 0x140FB1CF0 */ ScanSignature ( "\x0F\x10\x43\x4C\x41\x0F\x11\x45\x00", "xxxxxxxxx" ), HookBehavior.Replace ); } // Disable letterboxing for square/portrait resolutions. WriteNop ( /* 0x14014BD44 */ ScanSignature ( "\x76\x16\xF3\x0F\x59\x0D", "xxxxxx" ), 2 ); _isInitialised = true; } if (_mainAspectRatioAddr == 0) return; RECT clientRect = new RECT(); if (!GetClientRect(Win32.GetGameWindowHandle(), ref clientRect)) return; float width = (float)(clientRect.Right - clientRect.Left); float height = (float)(clientRect.Bottom - clientRect.Top); _aspectRatio = width / height; // Set UI stretch mode based on current aspect ratio. if (_surfRideAspectRatioAddr != 0 && _surfRideAspectRatioJumpAddr != 0) { if (_aspectRatio < (16.0f / 9.0f)) { WriteNop(_surfRideAspectRatioAddr, 6); } else { WriteProtected(_surfRideAspectRatioAddr, 0x0F, 0x84); WriteProtected(_surfRideAspectRatioAddr + 2, (int)(_surfRideAspectRatioJumpAddr - _surfRideAspectRatioAddr) - 6); } } WriteProtected(_mainAspectRatioAddr, _aspectRatio); if (_dvSceneAspectRatioAddr != 0) WriteProtected(_dvSceneAspectRatioAddr + 6, _aspectRatio); } Patch "Enable Dynamic Resolution" in "Graphics/Display" by "angryzor" does "Re-enables the built-in dynamic resolution system. This system continuously measures your FPS and lowers the game's rendering resolution when it drops below the FPS you configured in the options." // #lib "Memory" // { /* 0x1410F6F82 in 1.42 */ long startOfStrings = ScanSignature( "\xc7\x44\x24\x48\x3e\x00\x46\x00\x4c\x8b\xc3\xc7\x44\x24\x4c\x72\x00\x61\x00\xc7\x44\x24\x50\x6d\x00\x65\x00\x48\x8d\x44\x24\x48\xc7\x44\x24\x54\x53\x00\x74\x00\xc7\x44\x24\x58\x61\x00\x72\x00\xc7\x44\x24\x5c\x74\x00\x00\x00\xc7\x44\x24\x30\x3e\x00\x46\x00\xc7\x44\x24\x34\x72\x00\x61\x00\xc7\x44\x24\x38\x6d\x00\x65\x00\xc7\x44\x24\x3c\x45\x00\x6e\x00\xc7\x44\x24\x40\x64\x00\x00\x00", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ); /* 0x14101BA8E in 1.42 */ long supportFXFrameStart = ScanSignature( "\x48\x8b\x8b\xa0\x24\x00\x00\x33\xd2\x48\x8b\x01\xff\x90\xa8\x00\x00\x00\x84\xc0", "xxxxxxxxxxxxxxxxxxxx" ); /* 0x14101C324 in 1.42 */ long supportFXRenderEnd = ScanSignature( "\x48\x8d\x15\x45\x4e\x72\x00\x48\x8b\xc8\x4c\x8b\x00\x41\xff\x90\x18\x03\x00\x00\x49\x8b\xbd\xc8\x24\x00\x00\x49\x8b\x85\xd0\x24\x00\x00\x4c\x8b\xb4\x24\xe0\x02\x00\x00\x4c\x8b\xa4\x24\xe8\x02\x00\x00\x48\x8d\x34\xc7\x48\x3b\xfe", "xxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ); /* 0x140240857 in 1.42 */ long fxParamGraphicsOptionExtensionOnAdd = ScanSignature( "\x0f\x28\x05\xf2\xdc\x1f\x01\x0f\x11\x44\x24\x58\xc7\x44\x24\x68\xcd\xcc\xcc\x3d\xc7\x44\x24\x6c\xcd\xcc\xcc\x3d\xc7\x44\x24\x70\xcd\xcc\xcc\x3d\xc6\x44\x24\x74\x00\xc6\x44\x24\x50\x02\xc7\x44\x24\x54\x00\x00\x80\x3f", "xxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ); /* 0x1402401B3 in 1.42 */ long fxParamGraphicsOptionExtensionOnReloadSettings = ScanSignature( "\x0f\xbe\x0a\x0f\x28\x05\x93\xe3\x1f\x01\xc7\x44\x24\x58\xcd\xcc\xcc\x3d\xc7\x44\x24\x5c\xcd\xcc\xcc\x3d\xc7\x44\x24\x60\xcd\xcc\xcc\x3d\xc6\x44\x24\x64\x00\xc6\x44\x24\x40\x02\x0f\x11\x44\x24\x48\x85\xc9", "xxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ); long frameStartString = Memory.ReadEffectiveAddress(supportFXFrameStart + 0x38); long frameEndString = Memory.ReadEffectiveAddress(supportFXRenderEnd); // The game captures GPU profiling info when SetMarker is called in needle with the strings `>FrameStart` and `>FrameEnd`, // but by default the strings that SetMarker is called with are instead `>>FrameStart` and `>>FrameEnd`. Fix those. Memory.WriteString(frameStartString, ">FrameStart"); WriteProtected(frameStartString + 0xB, 0); Memory.WriteString(frameEndString, ">FrameEnd"); WriteProtected(frameEndString + 0x9, 0); // The game completely skips SetMarker logic when a certain pointer in DeviceObjectDX11 is null. // This is the case in the release version of the game (presumably debug system there). // Skip these checks, but also disable the call to the vfunc in this debug system. WriteNop(startOfStrings - 0x4C, 6); WriteNop(startOfStrings - 0x16, 15); // The graphics options extension of FxParamManager always sets the dynamic resolution option to `FIXED_RESOLUTION`, // which overrides the stage's NeedleFxSceneData file. Instead set it to `ENABLE`. WriteProtected(fxParamGraphicsOptionExtensionOnAdd + 0x2D, 1); WriteProtected(fxParamGraphicsOptionExtensionOnReloadSettings + 0x2B, 1); } Patch "Force Light Scattering" in "Graphics/Quality" by "WasifBoomz & Robowil" does "Forces Light Scattering to render." { // FxDOFParameter WriteAsmHook ( $@" ; Enable Light Scattering mov byte ptr [r8], 1 ; Set Color to (0.015, 0.013, 0.023) mov dword ptr [r8+16], 0x3C75C28F mov dword ptr [r8+20], 0x3C54FDF4 mov dword ptr [r8+24], 0x3CBC6A7F ; Set Scattering Scale to 15 mov dword ptr [r8+32], 0x41700000 ; Set Beta Mie to 0.6 mov dword ptr [r8+64], 0x3F19999A ; Set Gamma to 0.08 mov dword ptr [r8+68], 0x3DA3D70A ; Set ZNear and Far to 300 and 55000 mov dword ptr [r8+72], 0x43960000 ", /* 0x14828BC8C */ ScanSignature ( "\x45\x0F\x10\x00\x44\x0F\x29\x8C\x24\xE0\x00\x00\x00", "xxxxxxxxxxxxx" ), HookBehavior.After ); } Patch "Force Higher Detail Reflections" in "Graphics/Quality" by "Hyper" does "Forces real-time local reflections to render at a higher resolution and reduces artefacting around Sonic and other nearby objects." { WriteAsmHook ( $@" mov byte ptr [r14 + 0x269], 1 ; enable traceSky to fix reflections for near objects (e.g. Sonic) mov byte ptr [r14 + 0x26C], 0 ; disable useQuat for full resolution reflections mov byte ptr [r14 + 0x26D], 1 ; enable useNormal to apply normal maps to reflections mov dword ptr [r14 + 0x270], 0x44000000 ; set rayMarchingCount to 512.0f to improve reflection quality mov dword ptr [r14 + 0x280], 0x3FC00000 ; set overrideRatio to 1.5f to reduce artefacting mov dword ptr [r14 + 0x28C], 0x3E800000 ; set uvOffsetScale to 0.25f to improve reflection quality whilst retaining normal map detail ; Restore original code. movups xmm0, xmmword ptr [r14 + 0x268] mov rcx, rsi movups xmmword ptr [rbx + 0x0C], xmm0 ", /* 0x140B83CF1 */ ScanSignature ( "\x41\x0F\x10\x86\x68\x02\x00\x00\x48\x8B\xCE", "xxxxxxxxxxx" ), HookBehavior.Replace ); } Patch "Disable Subsurface Scattering" in "Graphics/Quality" by "Hyper" { WriteAsmHook ( $@" mov dword ptr [rbx + 4], 0x461C4000 ; okay well it's not really disabled otherwise we get some messy colour banding, so lets just make the width gigantic so it's practically gone movups xmm0, xmmword ptr [rbx] lea rbx, [rbx + 0x80] movups xmmword ptr [rax - 0x80], xmm0 ", /* 0x140B84139 */ ScanSignature ( "\x0F\x10\x03\x48\x8D\x9B\x80\x00\x00\x00\x0F\x11\x40\x80\x0F\x10\x4B\x90\x0F\x11\x48\x90\x0F\x10\x43\xA0\x0F\x11\x40\xA0\x0F\x10\x4B\xB0\x0F\x11\x48\xB0\x0F\x10\x43\xC0\x0F\x11\x40\xC0\x0F\x10\x4B\xD0\x0F\x11\x48\xD0\x0F\x10\x43\xE0\x0F\x11\x40\xE0\x0F\x10\x4B\xF0\x0F\x11\x48\xF0\x48\x83\xE9\x01\x75\xAD\x0F\x10\x03\x48\x8B\xCE", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); } Patch "2x Extended Foliage Draw Distance" in "Graphics/Quality" by "Hyper" does "Extends the draw distance of foliage (trees, bushes, etc.) past the visible horizon." // static float Range = 3.0f; // { /* 0x140F16DB7 */ var sig = ScanSignature ( "\xF3\x41\x0F\x10\x87\xB8\x02\x00\x00\xF3\x0F\x11\x95\x98\x00\x00\x00", "xxxxxxxxxxxxxxxxx" ); if (sig == 0) return; fixed (float* pRange = &Range) { WriteAsmHook ( $@" push rax mov rax, {(long)pRange} movss xmm0, dword ptr [rax] movss dword ptr [rbp + 0x290 + 0xFFFFFFFFFFFFFE00 + 0x08], xmm2 pop rax ", sig, HookBehavior.Replace ); } } Patch "Force Maximum Geometry Detail" in "Graphics/Quality" by "Hyper" does /* Forces terrain, object and rail geometry to always render at the highest detail. This does not address pop-in issues. */ // using System.Runtime.InteropServices; static float Range = 10000.0f; /* This array is actually 32 in length, but the game accesses an array with tons of padding at the start. */ static float[] LayerRange = new float[36]; // { // Geometry LODs IntPtr pLayerRange = Marshal.AllocHGlobal(LayerRange.Length * sizeof(float)); { for (int i = 0; i < LayerRange.Length; i++) LayerRange[i] = Range; Marshal.Copy(LayerRange, 0, pLayerRange, LayerRange.Length); WriteAsmHook ( $@" mov rcx, {(long)pLayerRange} ; Restore original code. movups xmm0, xmmword ptr [rcx + 0x0C] lea rdx, qword ptr [rbp + 0xB0 + 0xFFFFFFFFFFFFFF34] movaps xmmword ptr [rbp - 0x20], xmm0 movups xmm1, xmmword ptr [rcx + 0x1C] ", /* 0x140EDEAAE */ ScanSignature ( "\x0F\x10\x41\x0C\x48\x8D\x55\xE4", "xxxxxxxx" ), HookBehavior.Replace ); } // Rail LODs fixed (float* pRange = &Range) { /* 0x140B840F1 */ var trrBlendRangeAddr = ScanSignature ( "\x0F\x10\x00\x48\x8B\xCE\x0F\x11\x43\x0C\xE8", "xxxxxxxxxxx" ); // Terrain Material Blending Range WriteAsmHook ( $@" push rcx mov rcx, {(long)pRange} mov ecx, dword ptr [rcx] mov dword ptr [rax + 0x0C], ecx pop rcx movups xmm0, xmmword ptr [rax] mov rcx, rsi movups xmmword ptr [rbx + 0x0C], xmm0 mov rax, {((trrBlendRangeAddr + 10) + Read(trrBlendRangeAddr + 11) + 0x05)} ; 0x140B81190 call rax ", trrBlendRangeAddr, HookBehavior.Replace ); // Rail LODs WriteAsmHook ( $@" push rax mov rax, {(long)pRange} movss xmm0, dword ptr [rax] mulss xmm0, xmm0 pop rax ", /* 0x140160930 */ ScanSignature ( "\x81\xF9\xFF\xFF\xFF\x7F\x74\x1C", "xxxxxxxx" ), HookBehavior.Replace ); } } Patch "2x Extended Grass Draw Distance" in "Graphics/Quality" by "Hyper" does "Extends the draw distance of the grass past the visible horizon." // static float Range = 3.0f; // { fixed (float* pRange = &Range) { WriteAsmHook ( $@" push rax mov rax, {(long)pRange} movss xmm0, dword ptr [rax] movss dword ptr [rbp + 0x290 + 0xFFFFFFFFFFFFFDD0 + 0x08], xmm2 pop rax ", /* 0x140F1A885 */ ScanSignature ( "\xF3\x41\x0F\x10\x87\xB8\x02\x00\x00\xF3\x0F\x11\x55\x68", "xxxxxxxxxxxxxx" ), HookBehavior.Replace ); } } Patch "Disable Grass" in "Graphics/Quality" by "Hyper" { WriteProtected ( /* 0x140F1A7C0 */ ScanSignature ( "\x0F\x84\xE4\x12\x00\x00", "xxxxxx" ), 0xE9, 0xE5, 0x12, 0x00, 0x00 ); } Patch "4x Extended Foliage Draw Distance" in "Graphics/Quality" by "Hyper" does /* Extends the draw distance of foliage (trees, bushes, etc.) past the visible horizon. WARNING: this will almost definitely cause performance issues, especially if you're already extending the grass draw distance. */ // static float Range = 5.0f; // { /* 0x140F16DB7 */ var sig = ScanSignature ( "\xF3\x41\x0F\x10\x87\xB8\x02\x00\x00\xF3\x0F\x11\x95\x98\x00\x00\x00", "xxxxxxxxxxxxxxxxx" ); if (sig == 0) return; fixed (float* pRange = &Range) { WriteAsmHook ( $@" push rax mov rax, {(long)pRange} movss xmm0, dword ptr [rax] movss dword ptr [rbp + 0x290 + 0xFFFFFFFFFFFFFE00 + 0x08], xmm2 pop rax ", sig, HookBehavior.Replace ); } } Patch "Force Depth of Field" in "Graphics/Quality" by "WasifBoomz & Dicey" does "Forces Depth of Field to render, blurring near and distant geometry." { // FxDOFParameter WriteAsmHook ( $@" ; Enable DOF mov byte ptr [r8], 1 ; Set foreground bokeh depth to end at 3 and start at 0 mov dword ptr [r8+4], 0x40400000 mov dword ptr [r8+8], 0x00000000 ; Set background bokeh depth to start at 4000 and end at 50 mov dword ptr [r8+12], 0x42480000 mov dword ptr [r8+16], 0x457A0000 ; Increase sample count to 20 mov dword ptr [r8+32], 20 ; Set render target size to full mov byte ptr [r8+48], 0 ", /* 0x1482689B8 */ ScanSignature ( "\x45\x0F\x10\x08\x89\x84\x24\x90\x00\x00\x00", "xxxxxxxxxxx" ), HookBehavior.After ); // FxRenderTargetSetting WriteAsmHook ( $@" ; Original code lea rbp, [rsp-400h] sub rsp, 500h mov r15, rcx ; Set render target size to full mov dword ptr [rdx], 0 ", /* 0x140B83134 */ ScanSignature ( "\x48\x8D\xAC\x24\x00\xFC\xFF\xFF\x48\x81\xEC\x00\x05\x00\x00\x4C\x8B\xF9", "xxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); } Patch "Disable Shadow Angle Limit" by "Hyper & GamingLeroy" in "Graphics/Quality" does /* Disables the limit that prevents long shadows from being drawn against parallel global light. In simpler terms, shadows will line up correctly with the sun and moon. This will be particularly noticeable during sunrise and sunset hours. RFL research by GamingLeroy. */ { /* The game has a strange optimisation that loads the RFL struct we're modifying into the FPU as xmmwords, so 16 bytes at a time. This hook is a *hack* that checks the last entry in the xmmword before it gets written to the xmm0 register, which we then replace with zero if equal to 50.0f. The value in RAX is different per cycle of this function (it is run every frame), so we must check this value first to verify we're modifying the right struct before writing to it. All islands use a value of 50.0f for "minLightElevationAngle", so checking for this is not an issue (other than when people change this value for their own use, but it's better not to force this change for user values anyway). */ WriteAsmHook ( $@" cmp dword ptr [rax + 0x0C], 0x42480000 jne exit mov dword ptr [rax + 0x0C], 0 exit: ; Restore original code. movups xmm0, xmmword ptr [rax] movups xmm1, xmmword ptr [rax + 0x10] lea rax, [rax + 0x80] ", /* 0x140B83937 */ ScanSignature ( "\x0F\x10\x00\x0F\x10\x48\x10\x48\x8D\x80\x80\x00\x00\x00\x0F\x11\x41\x80\x0F\x10\x40\xA0\x0F\x11\x49\x90\x0F\x10\x48\xB0\x0F\x11\x41\xA0\x0F\x10\x40\xC0\x0F\x11\x49\xB0\x0F\x10\x48\xD0\x0F\x11\x41\xC0\x0F\x10\x40\xE0\x0F\x11\x49\xD0\x0F\x10\x48\xF0\x0F\x11\x41\xE0\x0F\x11\x49\xF0\x48\x83\xEA\x01\x75\xAD\x0F\x10\x00\x0F\x10\x48\x10\x0F\x11\x01\x0F\x10\x40\x20\x0F\x11\x49\x10\x0F\x10\x48\x30\x0F\x11\x41\x20\x0F\x10\x40\x40\x0F\x11\x49\x30\x0F\x11\x41\x40", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); } Patch "Force 4K Video Playback" in "Graphics/Quality" by "Hyper" does "Forces the game to use the pre-rendered cutscenes encoded at 4K, regardless of game resolution." { WriteNop ( /* v1.20: 0x14012405B */ ScanSignature ( "\x0F\x85\x00\x00\x00\x00\x48\x85\xC9\x74\x05\xE8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x45\x33\xC9\x48\x89\x44\x24\x00\x48\x8D\x55\x37\x48\xC7\x44\x24\x00\x00\x00\x00\x00\x48\x8D\x4D\x17\x45\x8D\x41\x20\xE8\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x4C\x89\x7D\x17\x48\x8D\x4D\x17\xE8\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8D\x4D\x17\xE8\x00\x00\x00\x00\x48\x8D\x77\x70\x4C\x8B\xC6\x48\x8D\x15\x00\x00\x00\x00\x48\x8D\x4D\x17\xE8\x00\x00\x00\x00\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x55\x17\x48\x8B\x01\xFF\x90\x00\x00\x00\x00\x48\x8D\x4D\x17\x0F\xB6\xD8\xE8\x00\x00\x00\x00\x84\xDB\x74\x1A\x81\x8F\x00\x00\x00\x00\x00\x00\x00\x00\xEB\x0E", "xx????xxxxxx????x????xxxxxxx?xxxxxxxx?????xxxxxxxxx????xxx????xxxxxxxxx????xxx????xxxxx????xxxxxxxxxx????xxxxx????xxx????xxxxxxxxx????xxxxxxxx????xxxxxx????????xx" ), 6 ); WriteProtected ( /* v1.20: 0x140967E09 */ ScanSignature ( "\x48\x0F\x45\xD9\xE8\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8D\x4D\xD8\xC7\x45\x00\x00\x00\x00\x00\x48\x89\x4D\xC0\x48\x8D\x15\x00\x00\x00\x00\x45\x33\xF6\x48\x89\x45\xD0\x48\x8D\x4D\xC0\x44\x89\x75\xC8\x4C\x8B\xC3\xE8\x00\x00\x00\x00\xF3\x0F\x10\x0D\x00\x00\x00\x00\x4C\x8D\x05\x00\x00\x00\x00\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x00\x48\xC7\x44\x24\x00\x00\x00\x00\x00\x48\x89\x44\x24\x00\x4C\x8D\x4C\x24\x00\x89\x44\x24\x78\x48\x8D\x95\x00\x00\x00\x00\xB8\x00\x00\x00\x00\x44\x89\x74\x24\x00\x66\x89\x45\x98\x0F\x57\xC0\xB8\x00\x00\x00\x00\xC6\x44\x24\x00\x00\x66\x44\x23\xF0\xF3\x0F\x11\x4D\x00\x48\x8B\x47\x08\x66\x41\x83\xCE\x00\x83\x7D\xC8\x00\x49\x8B\xCF\x66\x0F\x7F\x45\x00\x4C\x0F\x45\x45\x00\xC7\x45\x00\x00\x00\x00\x00\x48\xC7\x45\x00\x00\x00\x00\x00\xC7\x45\x00\x00\x00\x00\x00\xC7\x45\x00\x00\x00\x00\x00\x66\x44\x89\x75\x00\x48\x89\x44\x24\x00\xE8\x00\x00\x00\x00\x48\x8D\x8F\x00\x00\x00\x00\x48\x8B\xD0\xE8\x00\x00\x00\x00", "xxxxx????xxxx????xxxxxx?????xxxxxxx????xxxxxxxxxxxxxxxxxxx????xxxx????xxx????xx????????xxxx?????xxxx?xxxx?xxxxxxx????x????xxxx?xxxxxxxx????xxx??xxxxxxxx?xxxxxxxx?xxxxxxxxxxx?xxxx?xx?????xxx?????xx?????xx?????xxxx?xxxx?x????xxx????xxxx????" ), 0x48, 0x89, 0xCB, 0x90 ); } Patch "Disable Shadows" in "Graphics/Quality" by "Luig & Hyper" { WriteProtected ( /* 0x148236DF5 */ ScanSignature ( "\x0F\xB6\x42\x01\x88\x41\x01\x0F\xB6\x42\x02\x88\x41\x02\x0F\xB6\x42\x03\x88\x41\x03\x0F\xB6\x42\x04\x88\x41\x04\x0F\xB6\x42\x05\x88\x41\x05\x0F\xB6\x42\x06\x88\x41\x06\x8B\x42\x08\x89\x41\x08\x8B\x42\x0C\x89\x41\x0C\x8B\x42\x10\x89\x41\x10\x8B\x42\x14\x89\x41\x14\x8B\x42\x18\x89\x41\x18\x8B\x42\x1C\x89\x41\x1C\x8B\x42\x20\x89\x41\x20\x8B\x42\x24\x89\x41\x24\x8B\x42\x28\x89\x41\x28\x8B\x42\x2C\x89\x41\x2C\x8B\x42\x30\x89\x41\x30\x8B\x42\x34\x89\x41\x34\x8B\x42\x38\x89\x41\x38\x8B\x42\x3C\x89\x41\x3C\x8B\x42\x40\x89\x41\x40\x8B\x42\x44\x89\x41\x44\x8B\x42\x48\x89\x41\x48\x8B\x42\x4C\x89\x41\x4C\x8B\x42\x50\x89\x41\x50\x8B\x42\x54\x89\x41\x54\x8B\x42\x58\x89\x41\x58\x8B\x42\x5C\x89\x41\x5C\x8B\x42\x60\x89\x41\x60\x8B\x42\x64\x89\x41\x64\x8B\x42\x68\x89\x41\x68\x8B\x42\x6C\x89\x41\x6C\x8B\x42\x70\x89\x41\x70", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), 0xC6, 0x41, 0x01, 0x00, 0x90, 0x90, 0x90 ); } Patch "Disable Chromatic Aberration" in "Graphics/Post-processing" by "Luig & Hyper" does "Disables the RGB separation effect at edges of the screen in certain scenarios." { WriteNop ( /* 0x140B428ED */ ScanSignature ( "\x0F\x11\x43\x0C\x41\x0F\x10\x8E\x00\x00\x00\x00\x0F\x11\x4B\x1C\x41\x8B\x86\x00\x00\x00\x00\x89\x43\x2C\xE8\x00\x00\x00\x00\x48\x8B\xD8\x4D\x8D\xA6\x00\x00\x00\x00\x48\x8B\x08\x48\x85\xC9\x74\x0E\x4C\x8B\x09\x4C\x8D\x40\x10\x49\x8B\xD4\x41\xFF\x51\x08\x41\x0F\x28\x04\x24\x49\x8B\xCD\x0F\x29\x43\x10\x41\x0F\x28\x4C\x24\x00\x0F\x29\x4B\x20\x41\x0F\x28\x44\x24\x00\x0F\x29\x43\x30\x41\x0F\x28\x4C\x24\x00\x0F\x29\x4B\x40\x41\x0F\x28\x44\x24\x00\x0F\x29\x43\x50\x41\x0F\x28\x4C\x24\x00\x0F\x29\x4B\x60\x41\x0F\x28\x44\x24\x00\x0F\x29\x43\x70\x41\x0F\x28\x4C\x24\x00\x0F\x29\x8B\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x84\xC0\x0F\x85\x00\x00\x00\x00\xB9\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\xD8\x48\x85\xC0\x0F\x84\x00\x00\x00\x00\x0F\x28\x05\x00\x00\x00\x00\x49\x8B\xCD\x0F\x28\x0D\x00\x00\x00\x00", "xxxxxxxx????xxxxxxx????xxxx????xxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxx????x????xxxx????x????x????xxxxxxxx????xxx????xxxxxx????" ), 4 ); } Patch "Disable Vignette" in "Graphics/Post-processing" by "Hyper" { WriteNop ( /* 0x140B42934 */ ScanSignature ( "\x0F\x29\x43\x10\x41\x0F\x28\x4C\x24\x00\x0F\x29\x4B\x20\x41\x0F\x28\x44\x24\x00\x0F\x29\x43\x30\x41\x0F\x28\x4C\x24\x00\x0F\x29\x4B\x40\x41\x0F\x28\x44\x24\x00\x0F\x29\x43\x50\x41\x0F\x28\x4C\x24\x00\x0F\x29\x4B\x60\x41\x0F\x28\x44\x24\x00\x0F\x29\x43\x70\x41\x0F\x28\x4C\x24\x00\x0F\x29\x8B\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x84\xC0\x0F\x85\x00\x00\x00\x00\xB9\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\xD8\x48\x85\xC0\x0F\x84\x00\x00\x00\x00\x0F\x28\x05\x00\x00\x00\x00\x49\x8B\xCD\x0F\x28\x0D\x00\x00\x00\x00", "xxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxxxxxxxx?xxx????x????xxxx????x????x????xxxxxxxx????xxx????xxxxxx????" ), 4 ); } Patch "Disable FidelityFX Super Resolution (experimental)" in "Graphics/Post-processing" by "Hyper" does /* Disables the upsampling post-processing applied to the game. This will reduce sharpening artefacts like subtle haloing around geometry. Known issues; - The game will be blurry when anything other than TAA is used. */ { WriteProtected ( /* 0x140EFCEB7 */ ScanSignature ( "\x41\x0F\xBE\x56\x0D", "xxxxx" ), Assemble("mov edx, 0") ); } Code "Disable Cyber Space Noise" in "Graphics/Post-processing" by "jav.wav" does "Disables the distortion and noise effects when starting and finishing a stage in Cyber Space." // #include "Reflection" noemit #lib "Reflection" #lib "NoisePresetParameters" // { var NoisePresetParametersInfo = Reflection.GetDataInfo("gfx_noise_preset"); if (NoisePresetParametersInfo.pData == null) return; RFL_SET_PARAM(NoisePresetParametersInfo, presets[0].enable, false); } Patch "Disable TAA Sharpness" in "Graphics/Post-processing" by "Hyper" does "Disables the sharpening filter applied when TAA is enabled." { WriteProtected ( /* 0x140F2B602 */ ScanSignature ( "\x0F\x83\x86\x02\x00\x00", "xxxxxx" ), 0xE9, 0x87, 0x02, 0x00, 0x00 ); } Code "Disable In-Game Letterboxing" in "Graphics/Post-processing" by "Hyper" does /* Disables letterboxing for in-game cutscenes and Training Simulator. Notes; - This does not work for pre-rendered cutscenes. */ // #lib "GameManager" #lib "PhotoMode" #import "GOComponents" // { var pUILetterBox = GameManager.GetGameObject("UILetterBox"); if (pUILetterBox == null) return; var pGOCSprite = GameObject.GetGOC(pUILetterBox); if (pGOCSprite == null) return; pGOCSprite->Flags = (byte)(PhotoMode.IsEnabled() ? 3 : 0); } Patch "Disable Bullet Time Filter" in "Graphics/Post-processing" by "Hyper" does "Disables the greyscale filter applied when entering bullet time from a parry." { WriteNop ( /* 0x140219623 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCB\xFF\x15\xCC\xCC\xCC\xCC\x4C\x8D\x9C\x24\xB0\x00\x00\x00", "x????xxxxx????xxxxxxxx" ), 5 ); } Patch "Disable Stage Specific LUTs" in "Graphics/Post-processing" by "RagdollClash" does "Prevents the game from using the colour corrected LUTs stored in each stage's trr_cmn archive." { WriteProtected ( ScanSignature ( "%s_rgb_table%d", "xxxxxxxxxxxxxx" ), System.Text.Encoding.UTF8.GetBytes("ColorGradingLUT_default\0") ); } Patch "Disable Cyber Space CRT Effects" in "Graphics/Post-processing" by "Hyper & PTKay" does "Disables the CRT scanline effect on distant terrain models in Cyber Space." { WriteProtected ( /* 0x1401DDC5E */ ScanSignature ( "\x0F\x84\x00\x00\x00\x00\x41\x0F\x29\x73\x00\x48\xBF\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x57\xF6\x66\x66\x0F\x1F\x84\x00\x00\x00\x00\x00\xF3\x0F\x10\x4B\x00\x32\xC9\x0F\x28\xC1\x41\x0F\x54\xC1\x41\x0F\x2F\xC0\x0F\x86\x00\x00\x00\x00\xF3\x41\x0F\x59\xCA\xC7\x84\x24\x00\x00\x00\x00\x00\x00\x00\x00\x44\x89\xA4\x24\x00\x00\x00\x00\xF3\x0F\x58\x4B\x00\x0F\x2F\xCF\xF3\x0F\x11\x8C\x24\x00\x00\x00\x00\x76\x05\x0F\x28\xC7\xEB\x1B\x0F\x2F\xCE\x48\x8D\x84\x24\x00\x00\x00\x00\x48\x8D\x94\x24\x00\x00\x00\x00\x48\x0F\x43\xC2\xF3\x0F\x10\x00\xF3\x0F\x11\x43\x00\xC7\x86\x00\x00\x00\x00\x00\x00\x00\x00\xF3\x0F\x10\x43\x00\x0F\x2F\xC6\x73\x0A\x44\x0F\x2F\x43\x00\x0F\x93\xC1\xEB\x1D\x76\x1B\xF3\x0F\x10\x43\x00\xF3\x0F\x5C\xC7\x41\x0F\x54\xC1\x41\x0F\x2F\xC0\x77\x08\x48\xC7\x43\x00\x00\x00\x00\x00\x8B\x43\x58\x85\xC0\x78\x14\x83\xE8\x01\x89\x43\x58\x79\x0C\xC7\x86\x00\x00\x00\x00\x00\x00\x00\x00\xEB\x04\x84\xC9\x74\x45\x48\xFF\x4E\x30", "xx????xxxx?xx????????xxxxxxxxx????xxxx?xxxxxxxxxxxxxxx????xxxxxxxx????????xxxx????xxxx?xxxxxxxx????xxxxxxxxxxxxxx????xxxx????xxxxxxxxxxxx?xx????????xxxx?xxxxxxxxx?xxxxxxxxxxx?xxxxxxxxxxxxxxxxx?????xxxxxxxxxxxxxxxxx????????xxxxxxxxxx" ), 0xE9, 0xDA, 0x02, 0x00, 0x00 ); } Patch "Hide Sixth Sense Effects" in "Graphics/Effects" by "Hyper" does "Hides the particle effect when Sonic senses an enemy attack." { WriteProtected ( /* 0x1407E98CC */ ScanSignature ( "\x74\x79\xE8\xCC\xCC\xCC\xCC\x48\x8D\x4B\x6C", "xxx????xxxx" ), 0xEB ); } Patch "Hide Super Combat Effects" in "Graphics/Effects" by "Hyper" does "Hides the giant fist and foot particles during combat as Super Sonic." { WriteProtected ( /* 0x1407B5BF2 */ ScanSignature ( "\x0F\x84\x00\x00\x00\x00\x0F\x1F\x84\x00\x00\x00\x00\x00\x48\x8D\x4B\x48\xE8\x00\x00\x00\x00\x84\xC0\x75\x0D\x48\x8D\x4B\x50\xE8\x00\x00\x00\x00\x84\xC0\x74\x0E\x48\x83\xC3\x60\x48\x3B\xDF\x75\xDD\xE9\x00\x00\x00\x00\x0F\x28\x45\x10\x48\x8D\x4B\x48\xF3\x0F\x10\x4D\x00\xF3\x0F\x10\x65\x00\xF3\x0F\x10\x5D\x00\x0F\x29\xB4\x24\x00\x00\x00\x00\xF3\x0F\x10\x75\x00\x66\x0F\x7F\x43\x00\x0F\x28\x55\x20\x66\x0F\x7F\x53\x00\xF3\x0F\x11\x5B\x00\xF3\x0F\x11\x63\x00\xE8\x00\x00\x00\x00\x48\x8D\x4B\x50\x0F\x28\xCE\xE8\x00\x00\x00\x00\xF3\x0F\x10\x05\x00\x00\x00\x00", "xx????xxxx????xxxxx????xxxxxxxxx????xxxxxxxxxxxxxx????xxxxxxxxxxxx?xxxx?xxxx?xxxx????xxxx?xxxx?xxxxxxxx?xxxx?xxxx?x????xxxxxxxx????xxxx????" ), 0xE9, 0x3C, 0x01, 0x00, 0x00 ); } Patch "Hide Air Trick Hint Effects" in "Graphics/Effects" by "Hyper" does "Hides the particles that hint at dash rings, jump boards and springs being air trickable." // #lib "Memory" // { // Dash Rings WriteProtected ( /* 0x1403D545F */ ScanSignature ( "\x74\x7C\xE8\x00\x00\x00\x00\x48\x8B\xD0\x48\x8B\xCF\xE8\x00\x00\x00\x00\x33\xD2\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8D\x8F\x00\x00\x00\x00\x0F\xB6\x98\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x84\xDB\x74\x39\x84\xC0\x75\x47\xE8\x00\x00\x00\x00\x48\x8B\xD0\x48\x8B\xCF\xE8\x00\x00\x00\x00\x4C\x8D\x87\x00\x00\x00\x00\x48\x8B\xC8\x48\x8D\x15\x00\x00\x00\x00\x48\x8B\x5C\x24\x00\x48\x8B\x74\x24\x00\x48\x83\xC4\x20\x5F\xE9\x00\x00\x00\x00\x84\xC0\x74\x0E\x33\xD2\x48\x8D\x8F\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x5C\x24\x00\x48\x8B\x74\x24\x00\x48\x83\xC4\x20\x5F\xC3\xCC\xCC\xCC\x48\x89\x5C\x24\x00", "xxx????xxxxxxx????xxxxxx????xxx????xxx????x????xxxxxxxxx????xxxxxxx????xxx????xxxxxx????xxxx?xxxx?xxxxxx????xxxxxxxxx????x????xxxx?xxxx?xxxxxxxxxxxxx?" ), 0xEB ); // Jump Boards Memory.WriteForceJump ( /* 0x14041E357 */ ScanSignature ( "\x0F\x84\x83\x00\x00\x00\x48\x89\x5C\x24\x30\x48\x89\x74\x24\x38", "xxxxxxxxxxxxxxxx" ) ); // Springs Memory.WriteForceJump ( /* v1.41: 0x149771AB7 */ ScanSignature ( "\x0F\x85\xE0\x02\x00\x00\xE8", "xxxxxxx" ) ); } Patch "Hide Cyloop Aura" in "Graphics/Effects" by "Hyper" { WriteProtected ( /* 0x14080F16D */ ScanSignature ( "\x74\x16\x3C\x08\x74\x12", "xxxxxx" ), 0xEB ); } Patch "Hide Star Beacons" in "Graphics/Effects" by "Hyper" does "Hides the beacons that emit from the stars during Starfall." { WriteProtected ( ScanSignature ( "cmnisl_obj_slotstarpillar", "xxxxxxxxxxxxxxxxxxxxxxxxx" ), 0x00 ); } Patch "Hide Power Boost Effects" in "Graphics/Effects" by "NM & Hyper" // #lib "Memory" // { /* Activation FX (Sonic) */ WriteNop ( /* 0x1409950BC */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x83\x7D\x98\x00\x4C\x8D\x05\xCC\xCC\xCC\xCC\x41\xB9\x11\x00\x00\x00", "x????xxxxxxx????xxxxxx" ), 5 ); /* Activation FX (Another Story characters) */ WriteNop ( /* 0x140994B5F */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\x54\x24\x50\x48\x85\xD2\x74\x15\xF7\x44\x24\x5C\x00\x00\x00\x80\x75\x0B\x48\x8B\x4C\x24\x60\x48\x8B\x01\xFF\x50\xCC\x48\x8D\x4C\x24\x30", "x????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx?xxxxx" ), 5 ); /* Boost Activation FX */ Memory.WriteForceJump ( /* 0x140995A21 */ ScanSignature ( "\x74\x19\xE8\xCC\xCC\xCC\xCC\x84\xC0\x0F\x85\x9A\x00\x00\x00", "xxx????xxxxxxxx" ) ); /* Trail FX (Boost) */ WriteProtected ( /* 0x14089011D */ ScanSignature ( "\xB2\x02\xEB\x02\x32\xD2", "xxxxxx" ), Assemble("mov dl, 1") ); /* Trail FX (Spin Boost) */ WriteProtected ( /* 0x1408900CB */ ScanSignature ( "\xB2\x04\xEB\x54\x33\xD2", "xxxxxx" ), Assemble("mov dl, 1") ); } Patch "Disable Caterpillar (experimental)" in "Enemy/Guardian" by "Hyper" does /* Disables the Caterpillar guardian on Ouranos Island. Known issues; - This also affects Battle Rush and causes a softlock. */ { WriteNop ( /* 0x1405AEE3B */ ScanSignature ( "\x75\x2A\x45\x33\xC0\x33\xD2\x48\x8B\xCE\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCE", "xxxxxxxxxxx????xxx" ), 2 ); } Patch "Disable Guardian Introductions" in "Enemy/Guardian" by "Hyper" does "Disables the sequence that zooms the camera into guardians and displays their name." // #lib "Memory" // { // Asura WriteProtected ( /* 0x14060918E */ ScanSignature ( "\xBA\x03\x00\x00\x00\xE9\xD9\x00\x00\x00", "xxxxxxxxxx" ), Assemble("mov edx, 7") ); // Ninja WriteProtected ( /* 0x14062E308 */ ScanSignature ( "\xBA\x02\x00\x00\x00\x48\x8B\xC8\xE8\xCC\xCC\xCC\xCC\x48\x8B\x5F\x18\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x48\x8B\xC8", "xxxxxxxxx????xxxxx????xxxxxxx????xxx" ), Assemble("mov edx, 3") ); // Caterpillar WriteProtected ( /* 0x14065145B */ ScanSignature ( "\xBA\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\x5E\x18\xE8\x00\x00\x00\x00\x48\x8B\xD0\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\x9C\x24\x00\x00\x00\x00\x84\xC0\x75\x12\x48\x8B\xCE\xE8\x00\x00\x00\x00\x33\xD2\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\xB4\x24\x00\x00\x00\x00\x32\xC0\x48\x83\xC4\x78\xC3\x32\xC0\x48\x83\xC4\x78\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x48\x8B\xC4", "x????xxxx????xxxxx????xxxxxxx????xxxx????xxxx????xxxxxxxx????xxxxxx????xxxx????xxxxxxxxxxxxxxxxxxxxxxxxx" ), Assemble("mov edx, 7") ); // Tower Memory.WriteForceJump ( /* 0x14067C537 */ ScanSignature ( "\x0F\x84\x00\x00\x00\x00\x48\x8B\x5E\x18\x0F\x29\x74\x24\x00\xE8\x00\x00\x00\x00\x48\x8B\xD0\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\x88\x00\x00\x00\x00", "xx????xxxxxxxx?x????xxxxxxx????xxx????" ) ); // Squid WriteProtected ( /* 0x14068FBDC */ ScanSignature ( "\xBA\x00\x00\x00\x00\xEB\x2A\x48\x8B\x5E\x18", "x????xxxxxx" ), Assemble("mov edx, 3") ); // Shark WriteProtected ( /* 0x1406A9398 */ ScanSignature ( "\x0F\x85\x94\x01\x00\x00\x48\x89\x58\x08", "xxxxxxxxxx" ), 0xE9, 0x80, 0x01, 0x00, 0x00 ); // Spider WriteProtected ( /* 0x1406C6106 */ ScanSignature ( "\xBA\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\x5E\x18\xE8\x00\x00\x00\x00\x48\x8B\xD0\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x84\xC0\x75\x12\x48\x8B\xCE\xE8\x00\x00\x00\x00\x33\xD2\x48\x8B\xC8\xE8\x00\x00\x00\x00\x0F\x28\x74\x24\x00\x4C\x8D\x5C\x24\x00\x49\x8B\x5B\x10\x32\xC0\x49\x8B\x73\x18\x49\x8B\xE3\x5F\xC3\xCC\xCC\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00", "x????xxxx????xxxxx????xxxxxxx????xxxx????xxxxxxxx????xxxxxx????xxxx?xxxx?xxxxxxxxxxxxxxxxxxxxx?xxxx?" ), Assemble("mov edx, 3") ); // Strider WriteProtected ( /* 0x1406E0476 */ ScanSignature ( "\xBA\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\x5E\x18\xE8\x00\x00\x00\x00\x48\x8B\xD0\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x84\xC0\x75\x15", "x????xxxx????xxxxx????xxxxxxx????xxxx????xxxx" ), Assemble("mov edx, 2") ); // Sumo WriteProtected ( /* 0x1406FA136 */ ScanSignature ( "\x74\x15\x48\x8B\xCE\xE8\x00\x00\x00\x00\xBA\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\x5E\x18\xE8\x00\x00\x00\x00\x48\x8B\xD0\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x84\xC0\x75\x12\x48\x8B\xCE\xE8\x00\x00\x00\x00\x33\xD2\x48\x8B\xC8\xE8\x00\x00\x00\x00\x0F\x28\x74\x24\x00\x4C\x8D\x5C\x24\x00\x49\x8B\x5B\x10\x32\xC0\x49\x8B\x73\x18\x49\x8B\xE3\x5F\xC3\xCC\xCC\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00", "xxxxxx????x????xxxx????xxxxx????xxxxxxx????xxxx????xxxxxxxx????xxxxxx????xxxx?xxxx?xxxxxxxxxxxxxxxxxxxxx?xxxx?" ) + 0x0A, Assemble("mov edx, 8") ); // Tank WriteProtected ( /* 0x14074048B */ ScanSignature ( "\xBA\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\x5E\x18\xE8\x00\x00\x00\x00\x48\x8B\xD0\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\x9C\x24\x00\x00\x00\x00\x84\xC0\x75\x12\x48\x8B\xCE\xE8\x00\x00\x00\x00\x33\xD2\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x8B\xB4\x24\x00\x00\x00\x00\x32\xC0\x48\x83\xC4\x78\xC3\x32\xC0\x48\x83\xC4\x78\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x40\x56", "x????xxxx????xxxxx????xxxxxxx????xxxx????xxxx????xxxxxxxx????xxxxxx????xxxx????xxxxxxxxxxxxxxxxxxxxxxxx" ), Assemble("mov edx, 4") ); } Patch "Disable Wolf (experimental)" in "Enemy/Guardian" by "Hyper" does /* Disables the Wolf enemy on Ouranos Island. Known issues; - This also affects Battle Rush and causes a softlock. */ { WriteNop ( /* 0x140540E0E */ ScanSignature ( "\x75\x28\x45\x33\xC0\x33\xD2\x48\x8B\xCF\xE8\xCC\xCC\xCC\xCC\x45\x33\xC0\x48\x8B\xCF\x41\x8D\x50\x01\x48\x81\xC4\x88\x01\x00\x00", "xxxxxxxxxxx????xxxxxxxxxxxxxxxxx" ), 2 ); } Patch "Disable Fortress (experimental)" in "Enemy/Guardian" by "Hyper" does /* Disables the Fortress guardian on Chaos Island. Known issues; - This also affects Battle Rush and causes a softlock. */ { WriteNop ( /* 0x140677B6D */ ScanSignature ( "\x75\x2B\x45\x33\xC0\x33\xD2\x48\x8B\xCB", "xxxxxxxxxx" ), 2 ); } Patch "Disable Starfall Cutscene" in "Gameplay/Open Zone" by "Hyper" does "Disables the cutscene that occurs before Starfall." { /* 0x1403A5330 */ var addr = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x33\xC9\xC6\x84\x24\x10\x01\x00\x00\x02", "x????xxxxxxxxxx" ); WriteNop(addr, 5); WriteNop(addr + 0x38, 5); } Code "Tutorial Skip" in "Gameplay/Open Zone" by "Gordon Ramsay & Hyper" does "Displays a prompt asking if you want to skip the tutorial section on a new save." // #lib "Converse" #lib "Lua" // { Converse.Redirect("skip_tutorial_caption", "Skip the tutorial?"); Converse.Redirect("skip_tutorial_body", "Would you like to skip the tutorial? This will place you by\nthe 1-2 Portal with some rings and experience points.\nAll major tutorial flags will be marked as complete."); Lua.CreateLineHook ( """ end -- we're replacing code here and our query removes this from a previous function if GetValue("Tutorial", 0) == 0 then ShowYesNoWindowUI("skip_tutorial_caption", "skip_tutorial_body") if GetSelectResult() == 0 then SetValue("Tutorial", 0, 15) SetObjStatus("Gate", 2, 0) SetObjStatus("SequenceCollider", 3, 0) SetObjStatus("SequenceCollider", 0, 0) SetObjStatus("Gate", 0, 0) SetObjStatus("SequenceCollider", 1, 0) SetValue("EggmanTalkEventStatus", 0, 1) SetObjStatus("ChaosEmeraldStorage", 1, 1) SetObjStatus("ChaosEmeraldStorage", 2, 1) SetObjStatus("ChaosEmeraldStorage", 3, 1) SetObjStatus("ChaosEmeraldStorage", 4, 1) SetObjStatus("SequenceCollider", 4, 0) SetObjStatus("SequenceCollider", 5, 0) SetObjStatus("SequenceCollider", 6, 0) SetObjStatus("GiantBridge", 0, 0) SetObjStatus("SequenceCollider", 2, 0) SetHUDEnabled("MainMenu", true) SetHUDEnabled("MapMenu", true) SetPlayerAbilityEnabled("WallAction", true) SetPlayerAbilityEnabled("Lockon", true) SetPlayerAbilityEnabled("Cyloop", true) SetPlayerAbilityEnabled("ControlMove", true) SetPlayerAbilityEnabled("ControlCamera", true) SetPlayerAbilityEnabled("Parry", true) SetPlayerAbilityEnabled("ComboAttack", true) SetPlayerAbilityEnabled("Jump", true) SetPlayerAbilityEnabled("Boost", true) SetPlayerAbilityEnabled("HomingAttack", true) PlayerGetItem("Ring", 100) PlayerGetItem("ExpPoint", 600) MovedPlayer("Locator_PortalSage1_Sonic", "CONTINUE") SetValue("PortalBitInputNum", 13, 1) WaitTime(1) NotifyAction("MiniBossSpawner0", "on") else TutorialInitialize() end end """, "w1r03_sequence05.lua", "end\n TutorialInitialize()", HookBehavior.Replace ); } Code "Character Swapper" in "Gameplay/Open Zone" by "Hyper, Skyth & Gordon Ramsay" does /* Allows switching between Sonic, Amy, Knuckles and Tails using hotkeys. Controller Layout; - RS + D-Pad Up - switch to Sonic - RS + D-Pad Right - switch to Amy - RS + D-Pad Down - switch to Knuckles - RS + D-Pad Left - switch to Tails Keyboard Layout; - 1 - switch to Sonic - 2 - switch to Amy - 3 - switch to Knuckles - 4 - switch to Tails Notes; - Whilst the other characters may share states with Sonic, there is still opportunity for the game to crash when using some of Sonic's gimmicks as the other characters. - Keep your expectations within reason; don't expect guardians outside of Another Story to work 100% correctly as the other characters, especially event-driven ones like Shark. */ // #include "BlackboardStatus" noemit #lib "BlackboardItem" #lib "MathHelpers" #lib "PhotoMode" #lib "Player" #lib "Win32" #lib "XInput" static bool _isCharacterUpdate = false; static bool _isAwaitPlayerInit = false; static Player.PlayerType _currentPlayer = Player.PlayerType.Unknown; static int _lastRingCount = 0; static bool IsKeyDown(Keys in_keys) { return (GetAsyncKeyState(in_keys) & 0x8000) != 0; } static bool IsButtonDownSpecial(XInput.Buttons buttons) { if (!XInput.IsButtonDown(XInput.Buttons.RIGHT_THUMB)) return false; return XInput.IsButtonDown(buttons); } // { if (!Win32.IsGameForegroundWindow()) return; if (IS_WORLD_FLAG(IsCyberSpace)) return; if (PhotoMode.IsEnabled()) return; if (_currentPlayer != Player.GetPlayerType()) _currentPlayer = Player.GetPlayerType(); var pBlackboardItem = BlackboardItem.Get(); if (pBlackboardItem == null) return; if (_isAwaitPlayerInit) { pBlackboardItem->RingCount = MathHelpers.Clamp(_lastRingCount, 0, pBlackboardItem->RingCapacity); if (Player.Sound.PlaySound("sn_sonic_boom") != 0) { Player.Effect.PlayEffect("SwapEffect", "ef_ob_portalgate_out01"); _isAwaitPlayerInit = false; } } if (_isCharacterUpdate) { if (IsKeyDown(Keys.D1) || IsKeyDown(Keys.D2) || IsKeyDown(Keys.D3) || IsKeyDown(Keys.D4)) { return; } if (IsButtonDownSpecial(XInput.Buttons.DPAD_UP) || IsButtonDownSpecial(XInput.Buttons.DPAD_RIGHT) || IsButtonDownSpecial(XInput.Buttons.DPAD_DOWN) || IsButtonDownSpecial(XInput.Buttons.DPAD_LEFT)) { return; } _isCharacterUpdate = false; } if (IsKeyDown(Keys.D1) || IsButtonDownSpecial(XInput.Buttons.DPAD_UP)) { if (_currentPlayer == Player.PlayerType.Sonic) return; _currentPlayer = Player.PlayerType.Sonic; _isCharacterUpdate = true; } if (IsKeyDown(Keys.D2) || IsButtonDownSpecial(XInput.Buttons.DPAD_RIGHT)) { if (_currentPlayer == Player.PlayerType.Amy) return; _currentPlayer = Player.PlayerType.Amy; _isCharacterUpdate = true; } if (IsKeyDown(Keys.D3) || IsButtonDownSpecial(XInput.Buttons.DPAD_DOWN)) { if (_currentPlayer == Player.PlayerType.Knuckles) return; _currentPlayer = Player.PlayerType.Knuckles; _isCharacterUpdate = true; } if (IsKeyDown(Keys.D4) || IsButtonDownSpecial(XInput.Buttons.DPAD_LEFT)) { if (_currentPlayer == Player.PlayerType.Tails) return; _currentPlayer = Player.PlayerType.Tails; _isCharacterUpdate = true; } if (_isCharacterUpdate) { Player.SetPlayerType(_currentPlayer); _lastRingCount = pBlackboardItem->RingCount; _isAwaitPlayerInit = true; } } Code "Always Dodge in Stick Direction" in "Gameplay/Skills" by "Hyper" does /* Allows the player to dodge in the direction of the analog stick. When the analog stick is neutral, the player will dodge in the default left and right directions relative to the camera plane. */ // #lib "Player" #lib "XInput" #import "States" static bool _isInitialised = false; static bool _isRightShoulderDown = false; // { if (!_isInitialised) { WriteNop ( /* 0x1409CDD9D */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\xBA\x8C\x00\x00\x00\xE9\x1D\x01\x00\x00", "x????xxxxxxxxxx" ), 5 ); WriteNop ( /* 0x1409D0509 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\xBA\x8C\x00\x00\x00\xE9\x0E\x01\x00\x00", "x????xxxxxxxxxx" ), 5 ); Sonic.StateID NotifyStateAvoid(Sonic.StateID in_stateId, Sonic.StateID[] in_stateStackTrace) { if (in_stateId == Sonic.StateID.StateAvoid && XInput.IsAnalogNeutral(0)) { var dir = StateAvoidParameter.GetDirectionRelativeToCameraPlane(_isRightShoulderDown); Player.State.AddStateParameter(new StateAvoidParameter(dir)); } return in_stateId; } Player.State.AddStateNotifyAction(NotifyStateAvoid); _isInitialised = true; } _isRightShoulderDown = Player.Input.IsDown(Player.InputActionType.PlayerRightStep); } Patch "Disable Parry Targeting" in "Gameplay/Skills" by "Hyper" does "Disables the player automatically targeting the nearest enemy when parrying." { WriteNop ( /* 0x14093965E */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCE\x45\x32\xFF", "x????xxxxxx" ), 5 ); } Patch "Dynamic Parry" in "Gameplay/Skills" by "NM" does /* Gradually reduces the player's parry window based on combo count and the active difficulty. Notes; - Each difficulty is given a combo threshold; the smaller the threshold, the faster the window decreases. These are defined as follows; - Easy: 100 - Normal: 75 - Hard: 40 - Extreme: 20 - If a combo is not active, the parry window will be set to zero, meaning an infinite duration. - Perfect Parry is not affected. - You may customize the base window per difficulty by editing "maxRecieveTimes" in the character's RFL. */ // #include "Helpers" noemit #import "SonicParameters" #lib "BlackboardBattle" #lib "BlackboardStatus" // TODO: Move unmanaged implementation into code once compiler issue is addressed static class GetParryWindow { private static float[] ComboThresholds = new float[] { 100.0f /* Easy */, 75.0f /* Normal */, 40.0f /* Hard */, 20.0f /* Extreme */, }; // PlayerParamParry has a definition for each character, but the implementation is the same // Use the one from SonicParameters UNMANAGED_FUNCTION(float, Impl, PlayerParamParry *inParamParry) { // The BlackboardContent we use here will never be null in this case var battle = BlackboardBattle.Get(); var status = BlackboardStatus.Get(); var combo = (float)(battle->ComboCount); if (combo == 0) return 0.0f; var difficulty = (int)(status->Difficulty); var threshold = ComboThresholds[difficulty]; // By default, we use values from the RFL as our base window var result = inParamParry->maxRecieveTimes[difficulty]; result *= Math.Max((1.0f - (combo / threshold)), (0.3f / result)); return result; } public static long Address() => GET_UNMANAGED_FUNCTION_PTR(Impl); } // { /* 0x140939B61 */ long address = ScanSignature("\x84\xC0\x74\x08\xF3\x0F\x10\x74\xBB\x14", "xxxxxxxxxx"); string instructions = @$" push rax sub rsp, 0x28 movaps [rsp], xmm0 test al, al jnz PerfectParry NormalParry: push rcx sub rsp, 0x08 mov rcx, rbx mov rax, {GetParryWindow.Address()} call rax add rsp, 0x08 pop rcx jmp End PerfectParry: movss xmm0, [rbx + rdi * 4 + 14h] End: movss xmm6, xmm0 movaps xmm0, [rsp] add rsp, 0x28 pop rax "; // Just for some added efficiency, we'll use an asm hook that retrieves the parry window WriteAsmHook(instructions, address, HookBehavior.Replace); } Code "Always Allow Jumping Off Rails" in "Gameplay/Skills" by "Hyper" does "Allows the player to jump off of grind rails at any angle." // #include "BlackboardStatus" noemit #lib "Player" #lib "Time" #lib "VectorHelpers" #load "System.Numerics.dll" using System.Numerics; static bool _isInitialised = false; // { if (!_isInitialised) { WriteNop ( /* 0x14BEFFDA4 */ ScanSignature ( "\x76\x0D\xB0\x01\x48\x8B\x5C\x24\x50", "xxxxxxxxx" ), 2 ); _isInitialised = true; } var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; Time.CreateTimer("AlwaysAllowJumpingOffRails_RestoreStates", false); if (Player.State.GetCurrentStateID() == Sonic.StateID.StateGrindJump) { if (Vector3.Dot(Vector3.Transform(Vector3.UnitY, kinematics->Rotation), Vector3.UnitY) < 0.7f) { var up = Vector3.Transform(Vector3.UnitY, Quaternion.Normalize(kinematics->Rotation)); kinematics->Position += up * 1.125f; kinematics->Rotation = VectorHelpers.LookRotation(up); /* Discard StateFall to prevent the player from instantly double jumping out of StateGrindJump. */ Player.State.Discard(Sonic.StateID.StateFall); Time.SetTimer("AlwaysAllowJumpingOffRails_RestoreStates", 0.0f, true); } } else if (Time.GetTimer("AlwaysAllowJumpingOffRails_RestoreStates") > 0.2f) { Player.State.Restore(Sonic.StateID.StateFall); } } Patch "Disable Boost Replenishment from Rings" in "Gameplay/Skills" by "Hyper" does "Prevents the boost gauge from refilling when collecting rings." { WriteAsmHook ( $@" xorps xmm1, xmm1 xor r8d, r8d cvtsi2ss xmm1, rcx mov rcx, rbx mov dword ptr [rax + 0x14], 0 mulss xmm1, dword ptr [rax + 0x14] ", /* 0x140863E19 */ ScanSignature ( "\x41\x8B\x4E\x24\x0F\x57\xC9\x45\x33\xC0\xF3\x48\x0F\x2A\xC9", "xxxxxxxxxxxxxxx" ), HookBehavior.Replace ); } Patch "Disable Boost Replenishment from Timer" in "Gameplay/Skills" by "Hyper" does "Prevents the boost gauge from refilling over time." { WriteNop ( /* 0x140998680 */ ScanSignature ( "\xF3\x0F\x11\x4F\x40\x80\xBF\xD5\x00\x00\x00\x02", "xxxxxxxxxxxx" ), 5 ); } Code "Always Dodge with Side Step" in "Gameplay/Skills" by "Hyper" does "Always makes Sonic dodge left or right instead of side stepping whilst not running." // #include "BlackboardStatus" noemit #lib "HMM" #lib "Player" #lib "StringMapOperation" #lib "Time" #lib "XInput" #import "States" static bool _isInitialised = false; static bool _isReflexPanel = false; static bool _isDodgeAnalog = false; static bool _isDodgeInCyberSpace = false; static bool _isInputBuffered = false; static bool _isParried = false; static float _dodgeTimer = 0.0f; static float _dodgeTimerThreshold = 0.08f; static float _sideStepThreshold = 15.0f; static void AddStateAvoidParameter(bool in_isRight) { // Use stick direction. if (_isDodgeAnalog && !XInput.IsAnalogNeutral(0)) return; var dir = StateAvoidParameter.GetDirectionRelativeToCameraPlane(in_isRight); Player.State.AddStateParameter(new StateAvoidParameter(dir)); } Sonic.StateID NotifyStateAvoidRedirectFromSideStep(Sonic.StateID in_stateId, Sonic.StateID[] in_stateStackTrace) { if (!_isReflexPanel && in_stateId is Sonic.StateID.StateLeftStep or Sonic.StateID.StateRightStep) { AddStateAvoidParameter(in_stateId == Sonic.StateID.StateRightStep); return Sonic.StateID.StateAvoid; } return in_stateId; } static void PerformBumperActions(bool in_isRight = false) { // Don't dodge if the player is doing the reflex panel challenges. if (_isReflexPanel) return; // Don't dodge if the player's magnitude is above the threshold. if (Player.Kinematics.GetHorizontalMagnitude() >= _sideStepThreshold) return; if (!Player.Status.IsGrounded() || IS_WORLD_FLAG(IsOutOfControl) || IS_WORLD_FLAG(IsAutoRun)) { return; } if (Player.Input.IsDown(Player.InputActionType.PlayerLeftStep) && Player.Input.IsDown(Player.InputActionType.PlayerRightStep)) { if (!_isInputBuffered) { Player.State.SetState(Sonic.StateID.StateParry); _isInputBuffered = true; _isParried = true; } return; } else if (Player.State.GetCurrentStateID() != Sonic.StateID.StateParry) { _isInputBuffered = false; } // Prevent dodging immediately after parrying. if (_isParried && (Player.Input.IsDown(Player.InputActionType.PlayerLeftStep) || Player.Input.IsDown(Player.InputActionType.PlayerRightStep))) { return; } else { _isParried = false; } if (Player.Input.IsDown(in_isRight ? Player.InputActionType.PlayerRightStep : Player.InputActionType.PlayerLeftStep)) { _dodgeTimer += Time.GetDeltaTime(); if (_dodgeTimer >= _dodgeTimerThreshold) { if (!_isDodgeAnalog) AddStateAvoidParameter(in_isRight); Player.State.SetState(Sonic.StateID.StateAvoid); _dodgeTimer = 0.0f; } } } // { if (!_isInitialised) { foreach (var code in HMM.GetCodes()) { switch (code) { case "Gameplay/Skills/Always Dodge in Stick Direction": _isDodgeAnalog = true; break; case "Gameplay/Cyber Space/Skills/Enable Dodge and Parry": _isDodgeInCyberSpace = true; break; } } Player.State.AddStateNotifyAction(NotifyStateAvoidRedirectFromSideStep); _isInitialised = true; } if (IS_WORLD_FLAG(IsCyberSpace) && !_isDodgeInCyberSpace) return; _isReflexPanel = Player.State.GetStatePlugin("StatePluginReflexesPanel") != null; PerformBumperActions(); PerformBumperActions(true); } Code "Rail Crouch" in "Gameplay/Skills" by "WasifBoomz" does /* Allows Sonic to crouch on grind rails to gain or lose speed based on the angle of the rail. Notes; - The speed cap is increased while grinding. - The boost has been modified to become an accelerator while grinding. */ // #include "Reflection" noemit #lib "Memory" #lib "Player" #lib "Reflection" #lib "SonicParameters" #lib "AmyParameters" #lib "KnucklesParameters" #lib "TailsParameters" #load "System.Numerics.dll" using System.Numerics; static bool _isInitialised = false; static bool _isRailCrouching = false; const float _grindCrouchSpeed = 40.0f; const float _boostGrindSpeedMin = 3.0f; const float _boostGrindSpeed = 45.0f; static Reflection.ReflectionInfo _sonicParametersInfo; static Reflection.ReflectionInfo _amyParametersInfo; static Reflection.ReflectionInfo _knucklesParametersInfo; static Reflection.ReflectionInfo _tailsParametersInfo; // TODO (Hyper): reduce boilerplate with library features. static float GetAcceleration() { switch (Player.GetPlayerType()) { case Player.PlayerType.Sonic: { if (_sonicParametersInfo != null && _sonicParametersInfo.pData != null) return RFL_GET_CONTEXTUAL_PLAYER_PARAM(_sonicParametersInfo, modePackage.grind.acceleForce); break; } case Player.PlayerType.Amy: { if (_amyParametersInfo != null && _amyParametersInfo.pData != null) return RFL_GET_PARAM(_amyParametersInfo, forwardView.modePackage.grind.acceleForce, in_acceleForce); break; } case Player.PlayerType.Knuckles: { if (_knucklesParametersInfo != null && _knucklesParametersInfo.pData != null) return RFL_GET_PARAM(_knucklesParametersInfo, forwardView.modePackage.grind.acceleForce, in_acceleForce); break; } case Player.PlayerType.Tails: { if (_tailsParametersInfo != null && _tailsParametersInfo.pData != null) return RFL_GET_PARAM(_tailsParametersInfo, forwardView.modePackage.grind.acceleForce, in_acceleForce); break; } } return 0.0f; } // TODO (Hyper): reduce boilerplate with library features. static void SetAcceleration(float in_acceleForce) { if (_sonicParametersInfo != null && _sonicParametersInfo.pData != null) RFL_SET_CONTEXTUAL_PLAYER_PARAM(_sonicParametersInfo, modePackage.grind.acceleForce, in_acceleForce); if (_amyParametersInfo != null && _amyParametersInfo.pData != null) RFL_SET_PARAM(_amyParametersInfo, forwardView.modePackage.grind.acceleForce, in_acceleForce); if (_knucklesParametersInfo != null && _knucklesParametersInfo.pData != null) RFL_SET_PARAM(_knucklesParametersInfo, forwardView.modePackage.grind.acceleForce, in_acceleForce); if (_tailsParametersInfo != null && _tailsParametersInfo.pData != null) RFL_SET_PARAM(_tailsParametersInfo, forwardView.modePackage.grind.acceleForce, in_acceleForce); } // { if (!_isInitialised) { fixed (bool* p_isRailCrouching = &_isRailCrouching) { // Modify animation when crouching on rails. WriteAsmHook ( $@" ; Check if the Grind Land animation is playing cmp byte ptr [r15 - 0x2], 0x52 jnz end mov rcx, {(long)p_isRailCrouching} ; Check if the player is crouching cmp byte ptr [rcx], 1 jnz reset ; Set Transition Time and Next State mov byte ptr [r15 + 0x2], 0x52 mov dword ptr [r15 + 0x4], 0x3F800000 jmp end reset: ; Reset Transition Time and Next State mov byte ptr [r15 + 0x2], 0x51 mov dword ptr [r15 + 0x4], 0x3E4CCCCD end: ", /* 0x140E8B4DC */ ScanSignature ( "\x41\x8B\x47\x08\xF2\x41\x0F\x10\x07", "xxxxxxxxx" ), HookBehavior.After ); } // Jump over the grind boost code. Memory.WriteForceJump ( /* v1.41: 0x14B06DEAA */ ScanSignature ( "\x74\x0F\xBA\x01\x00\x00\x00\x48\x83\xC4\x20\x5B\xE9\xC5\xA3\x86\xF5", "xxxxxxxxxxxxxxxxx" ) ); _isInitialised = true; } _sonicParametersInfo = Reflection.GetDataInfo("player_common"); if (_sonicParametersInfo.pData != null) { RFL_SET_CONTEXTUAL_PLAYER_PARAM(_sonicParametersInfo, modePackage.grind.maxSpeed, 100.0f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(_sonicParametersInfo, modePackage.grind.maxBoostSpeed, 0.0f); } _amyParametersInfo = Reflection.GetDataInfo("amy_common"); if (_amyParametersInfo.pData != null) { RFL_SET_PARAM(_amyParametersInfo, forwardView.modePackage.grind.maxSpeed, 100.0f); RFL_SET_PARAM(_amyParametersInfo, forwardView.modePackage.grind.maxBoostSpeed, 0.0f); } _knucklesParametersInfo = Reflection.GetDataInfo("knuckles_common"); if (_knucklesParametersInfo.pData != null) { RFL_SET_PARAM(_knucklesParametersInfo, forwardView.modePackage.grind.maxSpeed, 100.0f); RFL_SET_PARAM(_knucklesParametersInfo, forwardView.modePackage.grind.maxBoostSpeed, 0.0f); } _tailsParametersInfo = Reflection.GetDataInfo("tails_common"); if (_tailsParametersInfo.pData != null) { RFL_SET_PARAM(_tailsParametersInfo, forwardView.modePackage.grind.maxSpeed, 100.0f); RFL_SET_PARAM(_tailsParametersInfo, forwardView.modePackage.grind.maxBoostSpeed, 0.0f); } var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; SetAcceleration(0.0f); _isRailCrouching = false; if (Player.Input.IsDown(Player.InputActionType.PlayerStomping)) { if (Player.State.GetCurrentStateID() == Sonic.StateID.StateGrind) { Player.Animation.SetAnimation("GRIND_LAND"); _isRailCrouching = true; } // Increase speed based on gravity. SetAcceleration(GetAcceleration() - (Vector3.Normalize(kinematics->Velocity).Y) * _grindCrouchSpeed); } // Increase acceleration when boosting. if (IS_STATE_FLAG(IsBoost)) { SetAcceleration(GetAcceleration() + (Vector3.Normalize(kinematics->Velocity).Y) * _boostGrindSpeed); SetAcceleration(Math.Max(GetAcceleration(), _boostGrindSpeedMin)); } } Code "Rail Dash" in "Gameplay/Skills" by "Hyper" does /* Allows the player to perform a Drop Dash or hold a Spin Dash on grind rails. Notes; - It is recommended to use this with the "Retain Horizontal Velocity from Jump" code. - The longer you hold a Drop Dash or the more you charge a Spin Dash before landing on a grind rail, the more initial boost speed and time you will be rewarded once you start grinding. - This is affected by gravity, allowing the player to get a slight increase in speed when a grind rail is going down. */ // #include "BlackboardStatus" noemit #lib "DeltaTime" #lib "GameMode" #lib "Globals" #lib "HMM" #lib "Lua" #lib "MathHelpers" #lib "Memory" #lib "Player" #lib "VectorHelpers" #import "GOComponents" #import "States" #load "System.Numerics.dll" using System.Numerics; static bool _isInitialised = false; static bool _isPowerBoostEffectsHidden = false; static bool _isHomingFromGrind = false; static bool _isDashCharged = false; static bool _isSpinBoostAnimThresholdReached = false; static bool _isLandAnimThresholdReached = false; static int _boostSfxHandle = 0; static int _spinBoostSfxHandle = 0; static int _chargeCount = 1; static float _chargeTimer = 0.0f; static float _chargeTimerThreshold = 0.25f; static float _dashSpeed = 5.0f; static float _dashMagnitudeMax = 85.0f; static float _dashMultiplier = 1.0f; static float _dashChargeMultiplier = 0.05f; static float _releaseTimer = 0.0f; static float _releaseTimerSpinBoostAnimThreshold = 0.4f; static float _releaseTimerLandAnimThreshold = 0.6f; static float _releaseTimerThreshold = 1.2f; static float _releaseTimerThresholdMultiplier = 1.0f; static float GetDashSpeed() { return _dashSpeed * (_dashMultiplier + _dashChargeMultiplier * _chargeCount); } static float GetReleaseTimerThreshold() { return _releaseTimerThreshold * (_releaseTimerThresholdMultiplier + _dashChargeMultiplier * _chargeCount) } static void IncrementChargeCountByTime() { _chargeTimer += DeltaTime.GetDeltaTime(); if (_chargeTimer > _chargeTimerThreshold) { _chargeCount++; _chargeTimer = 0.0f; } } static void StopEffects() { if (_boostSfxHandle != 0) { fixed (int* p_boostSfxHandle = &_boostSfxHandle) Player.Sound.StopSound(p_boostSfxHandle); } if (_spinBoostSfxHandle != 0) { fixed (int* p_spinBoostSfxHandle = &_spinBoostSfxHandle) Player.Sound.StopSound(p_spinBoostSfxHandle); Player.Effect.StopAnimationEffects(); Player.Effect.StopEffect("RailDashBoostImpact"); Player.Effect.StopEffect("RailDashGrindSparks"); Player.Effect.StopEffect("RailDashTrail01"); Player.Effect.StopEffect("RailDashTrail02"); } _boostSfxHandle = 0; _spinBoostSfxHandle = 0; _isSpinBoostAnimThresholdReached = false; _isLandAnimThresholdReached = false; } static void ResetMembers() { StopEffects(); _chargeCount = 1; _chargeTimer = 0.0f; _releaseTimer = 0.0f; } // { if (!_isInitialised) { Globals.Add("Rail Dash", true); _isPowerBoostEffectsHidden = HMM.GetCodes().Contains("Graphics/Effects/Hide Power Boost Effects"); _isInitialised = true; } if (!Globals.GetFlag("Rail Dash")) return; Lua.Call("LoadLevel", "warship01"); var state = Player.State.GetCurrentStateID(); var statePrev = Player.State.GetPreviousStateID(); var isGrind = state == Sonic.StateID.StateGrind; var isGrindStep = state == Sonic.StateID.StateGrindStep; var isSpinDashPressed = Player.Input.IsPressed(Player.InputActionType.PlayerSonicboom); var isSpinDashDown = Player.Input.IsDown(Player.InputActionType.PlayerSonicboom); if (Memory.TryGetPointer(Player.State.GetState(), out var out_pStateDoubleJump)) { _isDashCharged = out_pStateDoubleJump->DropDashChargeTimer > 0.0f; IncrementChargeCountByTime(); } else if (Memory.TryGetPointer(Player.State.GetState(), out var out_pStateRecoveryJump)) { _isDashCharged = out_pStateRecoveryJump->IsDropDashCharge; IncrementChargeCountByTime(); } else if (state is Sonic.StateID.StateSpinBoost or Sonic.StateID.StateSpinBoostCharge or Sonic.StateID.StateDropDash) { _isDashCharged = true; if (isSpinDashPressed) _chargeCount++; } else if (!(state is Sonic.StateID.StateGrind or Sonic.StateID.StateGrindStep)) { _isDashCharged = false; } if (state == Sonic.StateID.StateHomingAttack && statePrev == Sonic.StateID.StateGrind) { Player.Effect.PlayAnimationEffect("SPIN"); _isHomingFromGrind = true; return; } else if (_isHomingFromGrind && state != Sonic.StateID.StateHomingAttack) { Player.Effect.StopAnimationEffects(); _isHomingFromGrind = false; } // Allow spin dashing on rails. if (!_isDashCharged && isGrind && isSpinDashPressed) _isDashCharged = true; if (_isDashCharged) { if (isGrind) { if (_spinBoostSfxHandle == 0) { _spinBoostSfxHandle = Player.Sound.PlaySound("sn_spinboost"); /* Play intro effects only when the timer is at zero to prevent rail switching from using them. */ if (_releaseTimer <= 0.0f) { _boostSfxHandle = Player.Sound.PlaySound("sn_boost_run"); Player.Effect.PlayAnimationEffect("SPINBOOST"); Player.Effect.PlayEffect("RailDashBoostImpact", "ef_so_boost_impact_fv01"); var isPowerBoost = IS_WORLD_FLAG(IsPowerBoost) || IS_WORLD_FLAG(IsCyberSpacePowerBoost); if (!_isPowerBoostEffectsHidden && isPowerBoost && Player.GetPlayerType() == Player.PlayerType.Sonic) { Player.Effect.PlayEffect("RailDashTrail01", "ec_ft_pow_dash_ge01_blue_line01"); Player.Effect.PlayEffect("RailDashTrail02", "ec_ft_pow_dash_ge01_lightning_line01"); } } Player.Effect.PlayEffect("RailDashGrindSparks", "ef_mbo_warship01_accelplayer02"); } if (!isSpinDashDown) { _releaseTimer += DeltaTime.GetDeltaTime(); // End spin boost effects. if (_releaseTimer > _releaseTimerSpinBoostAnimThreshold) { if (!_isSpinBoostAnimThresholdReached) { Player.Effect.StopAnimationEffects(); Player.Animation.SetAnimation("BALL_MOVE"); Player.Animation.SetAnimationParameter("SPEED", 1.25f); _isSpinBoostAnimThresholdReached = true; } } // Restore grinding animation. if (_releaseTimer > _releaseTimerLandAnimThreshold) { if (!_isLandAnimThresholdReached) { Player.Animation.SetAnimation("GRIND_LAND"); _isLandAnimThresholdReached = true; } } } else if (isSpinDashPressed) { // Player tried spin dashing during exit animation, so re-enter spin dash. if (_releaseTimer >= _releaseTimerSpinBoostAnimThreshold) { ResetMembers(); return; } } if (_releaseTimer < GetReleaseTimerThreshold()) { if (Memory.TryGetPointer(Player.Kinematics.Get(), out var out_pKinematics)) { var magnitude = Player.Kinematics.GetMagnitude(); var slopeFactor = Vector3.Dot(Player.Kinematics.GetForward(), Vector3.UnitY); var speedMultiplier = MathHelpers.Lerp(1.0f, slopeFactor > 0.0f ? 0.25f : 1.25f, Math.Abs(slopeFactor)); out_pKinematics->Velocity += Player.Kinematics.GetForward() * (GetDashSpeed() * speedMultiplier); // Limit velocity since grind boosters cause this to go haywire. if (magnitude > _dashMagnitudeMax) out_pKinematics->Velocity *= _dashMagnitudeMax / magnitude; } } else { StopEffects(); _isDashCharged = false; } } else if (isGrindStep) { StopEffects(); if (isSpinDashDown) { ResetMembers(); } else { /* Set release timer to the land anim threshold, so the grind step state doesn't activate the animations. This comes with a slight penalty to the bonus boost time when switching rails, but that's fine. */ if (_releaseTimer < _releaseTimerLandAnimThreshold) _releaseTimer = _releaseTimerLandAnimThreshold; } } } else { ResetMembers(); } } Code "Super Stomp" in "Gameplay/Skills" by "Hyper & Yosho" does /* Sends a powerful shockwave when landing a stomp from a great height. Idea by Yosho. */ // #include "Reflection" noemit #lib "MathHelpers" #lib "Player" #lib "Reflection" #lib "SonicParameters" #import "States" #load "System.Numerics.dll" using System.Numerics; static bool _isStompBeginPositionPreserved = false; static Vector3 _stompBeginPosition; static float _heightFallen = 0.0f; static float _heightThreshold = 15.0f; static float _radius = 11.0f; // { Sonic.StateID NotifySuperStompLand(Sonic.StateID in_stateId, Sonic.StateID[] in_stateStackTrace) { if (in_stateId == Sonic.StateID.StateStompingLand) { if (_heightFallen >= _heightThreshold) Player.State.AddStateParameter(new StateStompingLandParameter(3)); } return in_stateId; } Player.State.AddStateNotifyAction(NotifySuperStompLand); var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; if (Player.State.GetCurrentStateID() == Sonic.StateID.StateStompingDown) { if (!_isStompBeginPositionPreserved) { _stompBeginPosition = kinematics->Position; _isStompBeginPositionPreserved = true; } _heightFallen = _stompBeginPosition.Y - kinematics->Position.Y; // 11.0f is the default value for boundStompingCollisionScale. _radius = MathHelpers.Clamp(_heightFallen - _heightThreshold, 11.0f, 33.0f); var SonicParametersInfo = Reflection.GetDataInfo("player_common"); if (SonicParametersInfo.pData == null) return; RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, modePackage.stomping.boundStompingCollisionScale, _radius); } else { _isStompBeginPositionPreserved = false; _heightFallen = 0.0f; } } Patch "Allow Spin Dash on Dash Panels" in "Gameplay/Skills" by "Hyper" does "Allows Sonic to Spin Dash through dash panels without interruptions." { WriteProtected ( /* 0x140916A78 */ ScanSignature ( "\x41\x0F\x94\xC7\xD0\xE9", "xxxxxx" ), Assemble("mov r15b, 0\n nop") ); } Code "Allow Spin Dash During Auto Run" in "Gameplay/Skills" by "Hyper" does "Allows the player to perform a Spin Dash whilst in auto run sections." // #include "BlackboardStatus" noemit #lib "Player" #lib "XInput" #import "Plugins" const float _stepThreshold = 0.75f; // { if (!IS_WORLD_FLAG(IsAutoRun)) return; var pStatePluginBoost = Player.State.GetStatePlugin(); if (pStatePluginBoost == null) return; if (pStatePluginBoost->BoostAmount <= 0.0f) return; if (Player.Input.IsPressed(Player.InputActionType.PlayerSonicboom)) Player.State.SetState(Player.Status.IsGrounded() ? Sonic.StateID.StateSpinBoost : Sonic.StateID.StateSpinBoostCharge); if (Player.State.GetCurrentStateID() != Sonic.StateID.StateSpinBoost) return; var ls = XInput.GetAnalog(0); if ((Player.Input.IsPressed(Player.InputActionType.PlayerLeftStep) || ls.X <= -_stepThreshold) && StatePluginQuickStep.IsQuickStepLegal()) Player.State.SetState(Sonic.StateID.StateQuickStepLeft); if ((Player.Input.IsPressed(Player.InputActionType.PlayerRightStep) || ls.X >= _stepThreshold) && StatePluginQuickStep.IsQuickStepLegal(true)) Player.State.SetState(Sonic.StateID.StateQuickStepRight); } Code "Always Stay on Climbable Walls" in "Gameplay/Skills" by "WasifBoomz" does "Prevents Sonic and Knuckles from detaching or sliding down climbable walls when hitting other walls and ceilings." // #lib "Player" #lib "Time" #load "System.Numerics.dll" using System.Numerics; const float fallOffWallTime = 0.3f; static Vector3 previousPosition; static float currentFallOffTime; // { var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; currentFallOffTime -= Time.GetDeltaTime(); switch (Player.GetPlayerType()) { case Player.PlayerType.Sonic: { if (Player.State.GetCurrentStateID() == Sonic.StateID.StateWallLeave) Player.State.SetState(Sonic.StateID.StateJump); else if (Player.State.GetCurrentStateID() == Sonic.StateID.StateWallSlideDown) Player.State.SetState(Sonic.StateID.StateFall); else break; currentFallOffTime = fallOffWallTime; break; } case Player.PlayerType.Knuckles: { if (Player.State.GetCurrentStateID() == Knuckles.StateID.StateWallLeave) Player.State.SetState(Knuckles.StateID.StateJump); else if (Player.State.GetCurrentStateID() == Knuckles.StateID.StateWallSlideDown) Player.State.SetState(Knuckles.StateID.StateFall); else break; currentFallOffTime = fallOffWallTime; break; } } if (currentFallOffTime + Time.GetDeltaTime() == fallOffWallTime) kinematics->Position = previousPosition; if (currentFallOffTime > 0) kinematics->Velocity = Vector3.Zero; else previousPosition = kinematics->Position; } Patch "Always Have All Abilities" in "Gameplay/Skills" by "Hyper" does /* Always grants Sonic his abilities (not skills), even when scripted not to have them. Abilities; - Boost - Combos - Camera Control - Cyloop - Homing Attack - Jump - Lock-on - Parry - Wall Climbing */ { WriteProtected ( /* 0x14BF81B71 */ ScanSignature ( "\x40\x0F\x95\xD5\x84\xD2", "xxxxxx" ), Assemble("mov bpl, 1\n nop") ); } Code "Allow Boost to Damage Objects" in "Gameplay/Skills" by "Hyper, NM & aleprime2007" does "Allows the player to damage enemies and harder physics objects by boosting through them." // #include "BlackboardStatus" noemit #lib "Player" using System.Collections.Generic; static bool _isDamageEnabled = false; static bool _isDamageOverride = false; static List _damageStates = new() { Sonic.StateID.StateJump, Sonic.StateID.StateDoubleJump, Sonic.StateID.StateSpinAttack, Sonic.StateID.StateSpinDash, Sonic.StateID.StateSpinBoostCharge, Sonic.StateID.StateSpinBoost, Sonic.StateID.StateHomingAttack, Sonic.StateID.StateStompingDown, Sonic.StateID.StateStompingLand, Sonic.StateID.StateBounceJump, Sonic.StateID.StateDropDash, Sonic.StateID.StateSliding }; static List _overrideStates = new() { Sonic.StateID.StateRun, Sonic.StateID.StateAirBoost }; // { void SetDamage(bool in_isEnabled) { var col = in_isEnabled ? Player.CollisionType.Damage : Player.CollisionType.Default; Player.Collision.SetCollisionSphere(col, 1.0f); Player.Collision.SetEntityCollision(!in_isEnabled); _isDamageEnabled = in_isEnabled; } Sonic.StateID stateId = Player.State.GetCurrentStateID(); if (IS_STATE_FLAG(IsBoost)) { if (_overrideStates.Contains(stateId)) { if (!_isDamageOverride) { SetDamage(true); _isDamageOverride = true; } } else { if (!_isDamageEnabled) SetDamage(true); _isDamageOverride = false; } } else { if (_isDamageEnabled && !_damageStates.Contains(stateId)) SetDamage(false); _isDamageOverride = false; } } Patch "Disable Dropped Rings" in "Gameplay/Objects" by "Hyper" does "Removes the bouncing rings when taking damage." { WriteNop ( /* 0x14089024B */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x4C\x8D\x05\xCC\xCC\xCC\xCC\x48\x8B\xD7\x48\x8D\x4D\x77", "x????xxx????xxxxxxx" ), 5 ); } Code "Additive Spring Trajectory with Boost" in "Gameplay/Objects" by "WasifBoomz & Hyper" does "Keeps your velocity upon hitting a vertical spring while boosting." // #include "BlackboardStatus" noemit #include "Helpers" noemit #lib "Player" #load "System.Numerics.dll" using System.Collections.Generic; using System.Numerics; static bool _isInitialised = false; static bool _isBoosting = false; static int _state = 0; static Vector3 _previousVelocity; // { if (!_isInitialised) { /* 0x1408B9F20 */ long sigSetAnimation = ScanSignature ( "\x40\x53\x48\x83\xEC\x20\xF6\x81\x78\x01\x00\x00\x10\x48\x8B", "xxxxxxxxxxxxxxx" ); fixed (bool* p_isBoosting = &_isBoosting) fixed (int* p_state = &_state) { WriteAsmHook ( $@" movaps xmm1, xmm2 shufps xmm1, xmm2, 0x99 addss xmm2, xmm1 movaps xmm0, xmm1 mov eax, dword ptr [rsi + 0x50] shr eax, 0x0A test al, 1 jnz exit mov rax, {(long)p_isBoosting} cmp byte ptr [rax], 0 jz exit mov rax, {(long)p_state} mov byte ptr [rax], 1 exit: ", /* 0x1409814F8 */ ScanSignature ( "\x0F\x28\xCA\x0F\xC6\xCA\x99\xF3\x0F\x58\xD1\x0F\x28\xC1\x0F\xC6\xC1\x55\xF3\x0F\x58\xD0\x0F\x28\xC2\x0F\xC6\xC0\x00\x0F\x59\x44\x24\x30\x0F\x5C\xE0\x0F\x29\x64\x24\x20\xE8\xCC\xCC\xCC\xCC\x84\xC0\x75\x5A", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx????xxxx" ), HookBehavior.Replace ); } _isInitialised = true; } var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; _isBoosting = IS_STATE_FLAG(IsBoost) && !(IS_STATE_FLAG(IsGrind) || IS_STATE_FLAG(IsWallClimb)); switch (_state) { case 0: _previousVelocity = kinematics->Velocity; break; case 1: Player.State.SetState(Sonic.StateID.StateBumpJump); _state++; break; case 2: { if (Player.Kinematics.GetHorizontalMagnitude() < Math.Abs(kinematics->Velocity.Y)) kinematics->Velocity += new Vector3(_previousVelocity.X, 0, _previousVelocity.Z); _state = 0; break; } default: _state = 1; break; } } Patch "Disable Thorn Cylinders" in "Gameplay/Objects" by "Hyper" does "Disables the cylindrical thorn objects placed at the most inconvenient locations." { WriteProtected ( /* 0x1404119C4 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCF\xE8\xCC\xCC\xCC\xCC\x48\x8D\x15\xCC\xCC\xCC\xCC\x48\x8B\xCB\x4C\x8B\xF0\xE8\xCC\xCC\xCC\xCC\x49\x0F\xBE\x16", "x????xxxxxxx????xxx????xxxxxxx????xxxx" ), 0xE9, 0x4A, 0x04, 0x00, 0x00 ); } Code "Always Use Extreme Rank Times" in "Gameplay/Cyber Space" by "Hyper" does "Always uses the rank times for Extreme difficulty for Cyber Space." // #lib "GameManager" #import "Services" // { var pStageInfo = GameManager.GetService(); if (pStageInfo == null) return; foreach (var pStageData in pStageInfo->Stages) pStageData.pData->Ranks = pStageData.pData->RanksVeryHard; } Code "Retain Upgraded Boost Gauge" in "Gameplay/Cyber Space" by "Hyper" does "Retains the upgraded boost gauge from the last save file in Cyber Space." // #include "BlackboardStatus" noemit #lib "Player" #import "Plugins" // { if (!IS_WORLD_FLAG(IsCyberSpace)) return; var pStatePluginBoost = Player.State.GetStatePlugin(); if (pStatePluginBoost == null) return; pStatePluginBoost->BoostCapacity = pStatePluginBoost->GetBoostCapacityFromLevel(); } Code "Enable Terrain Flinging" in "Gameplay/Cyber Space" by "Hyper" does /* Allows Sonic to fling off of terrain in Cyber Space. Notes; - This does not allow Sonic to perform air tricks from terrain, use the 'Enable Air Tricks from Terrain' code to do so. */ // #include "BlackboardStatus" noemit #include "Reflection" noemit #lib "Reflection" #lib "SonicParameters" // { if (!IS_WORLD_FLAG(IsCyberSpace)) return; var SonicParametersInfo = Reflection.GetDataInfo("player_common"); if (SonicParametersInfo.pData == null) return; SonicParametersInfo.pData->cyberspace.modePackage.tumble = SonicParametersInfo.pData->forwardView.modePackage.tumble; bool isNitroBoost = IS_WORLD_FLAG(IsNitroBoost); RFL_SET_PARAM(SonicParametersInfo, cyberspace.modePackage.tumble.enabled, !isNitroBoost); } Patch "Fix RenderDoc Captures (v1.42)" in "Fixes/Graphics" by "Skyth" does "Fixes RenderDoc being unable to hook to the game for capturing the graphics device." { WriteProtected(0x141210B40, Read(0x1560DE168)); WriteProtected(0x141210B50, Read(0x1560DE188)); } Patch "Fix Shadow Stutter" in "Fixes/Graphics" by "Hyper" does "Fixes shadows not interpolating smoothly when time passes." { WriteProtected ( /* 0x1480F8D71 */ ScanSignature ( "\x0F\xB6\x42\x74\x88\x41\x74\x8B\x42\x78", "xxxxxxxxxx" ), Assemble("mov byte ptr [rcx + 0x74], 0\n nop\n nop\n nop") ); } Patch "Fix Resolution Resetting on Launch" in "Fixes/Graphics" by "Hyper" does "Fixes a bug that causes the internal resolution to reset to 1280x720 if the game is unfocused during boot." // #load "System.Xml.dll" using System.IO; using System.Xml.Serialization; [XmlRoot(ElementName = "ScreenSetting")] public class ScreenSetting { [XmlAttribute(AttributeName = "left")] public int Left { get; set; } [XmlAttribute(AttributeName = "top")] public int Top { get; set; } [XmlAttribute(AttributeName = "width")] public int Width { get; set; } [XmlAttribute(AttributeName = "height")] public int Height { get; set; } [XmlAttribute(AttributeName = "resolutionWidth")] public int ResolutionWidth { get; set; } [XmlAttribute(AttributeName = "resolutionHeight")] public int ResolutionHeight { get; set; } [XmlAttribute(AttributeName = "fullscreenStyle")] public int FullscreenStyle { get; set; } [XmlAttribute(AttributeName = "fullscreenState")] public int FullscreenState { get; set; } } // { string xml = Path.Combine ( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"SEGA\SonicFrontiers\steam\x64\screen_setting.xml" ); if (!File.Exists(xml)) { Console.WriteLine($"[Fix Resolution Resetting on Launch] Code halted, file not found: {xml}"); return; } try { using (StringReader reader = new StringReader(File.ReadAllText(xml))) { var screenSetting = (ScreenSetting)new XmlSerializer(typeof(ScreenSetting)).Deserialize(reader); if (screenSetting.ResolutionWidth <= 0 || screenSetting.ResolutionHeight <= 0) { Console.WriteLine("[Fix Resolution Resetting on Launch] Invalid screen parameters! Defaulting to 1280x720..."); screenSetting.ResolutionWidth = 1280; screenSetting.ResolutionHeight = 720; } // Force resolutionWidth from XML as default value. WriteProtected ( /* 0x140BB66B4 */ ScanSignature ( "\xC7\x81\x00\x00\x00\x00\x00\x00\x00\x00\x48\x8B\x4B\x20\x41\xB7\x01\x83\xB9\x00\x00\x00\x00\x00\x75\x41\x41\xB8\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x4B\x20\x89\x81\x00\x00\x00\x00\x48\x8B\x4B\x20\x83\xB9\x00\x00\x00\x00\x00\x75\x0E\xC7\x81\x00\x00\x00\x00\x00\x00\x00\x00\x48\x8B\x4B\x20\x41\xB7\x01", "xx????????xxxxxxxxx?????xxxx????xxx????xxx????x????xxxxxx????xxxxxx?????xxxx????????xxxxxxx" ), Assemble($"mov dword ptr [rcx + 0xF0], 0x{screenSetting.ResolutionWidth:X}") ); // Force resolutionHeight from XML as default value. WriteProtected ( /* 0x140BB66FE */ ScanSignature ( "\xC7\x81\x00\x00\x00\x00\x00\x00\x00\x00\x48\x8B\x4B\x20\x41\xB7\x01\x41\x0F\xB6\xC7\x34\x01\x88\x81\x00\x00\x00\x00\x48\x8B\x4B\x20\x83\xB9\x00\x00\x00\x00\x00\x75\x40\x41\xB8\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x4B\x20\x89\x81\x00\x00\x00\x00\x48\x8B\x4B\x20\x83\xB9\x00\x00\x00\x00\x00\x75\x10\x8B\x81\x00\x00\x00\x00\x89\x81\x00\x00\x00\x00\x48\x8B\x4B\x20", "xx????????xxxxxxxxxxxxxxx????xxxxxx?????xxxx????xxx????xxx????x????xxxxxx????xxxxxx?????xxxx????xx????xxxx" ), Assemble($"mov dword ptr [rcx + 0xF4], 0x{screenSetting.ResolutionHeight:X}") ); } } catch (Exception ex) { Console.WriteLine($"[Fix Resolution Resetting on Launch] {ex}"); return; } // Kill XML value reading for resolutionWidth and resolutionHeight. WriteProtected ( /* 0x150A0F5C2 */ ScanSignature ( "\x74\x1B\x48\x85\xC0\x74\x16\x48\x89\xE9\xE8\x00\x00\x00\x00\x48\x89\xF1\x89\x43\x10\xE8\x00\x00\x00\x00\x89\x43\x14\x45\x31\xC0\x48\x8D\x15\x00\x00\x00\x00\x48\x89\xF9\xE8\x00\x00\x00\x00\x48\x8B\xB4\x24\x00\x00\x00\x00\x48\x8B\xAC\x24\x00\x00\x00\x00\x48\x85\xC0\x74\x0B\x48\x89\xC1\xE8\x00\x00\x00\x00\x89\x43\x20\x45\x31\xC0\x48\x8D\x15\x00\x00\x00\x00\x48\x89\xF9\xE8\x00\x00\x00\x00\x48\x85\xC0\x74\x0B\x48\x89\xC1\xE8\x00\x00\x00\x00\x89\x43\x24\x48\x8D\x4C\x24\x00\xB3\x01\xE8\x00\x00\x00\x00\x0F\xB6\xC3\x48\x81\xC4\x00\x00\x00\x00\x5F\x5B\xC3", "xxxxxxxxxxx????xxxxxxx????xxxxxxxxx????xxxx????xxxx????xxxx????xxxxxxxxx????xxxxxxxxx????xxxx????xxxxxxxxx????xxxxxxx?xxx????xxxxxx????xxx" ), 0xEB ); // Always pass resolutionWidth -1 check so we can force new value. WriteProtected ( /* 0x140BB6682 */ ScanSignature ( "\x75\x41\x41\xB8\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x4B\x20\x89\x81\x00\x00\x00\x00\x48\x8B\x4B\x20\x83\xB9\x00\x00\x00\x00\x00\x75\x0E\xC7\x81\x00\x00\x00\x00\x00\x00\x00\x00\x48\x8B\x4B\x20\x41\xB7\x01\x83\xB9\x00\x00\x00\x00\x00\x75\x41\x41\xB8\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x4B\x20\x89\x81\x00\x00\x00\x00\x48\x8B\x4B\x20\x83\xB9\x00\x00\x00\x00\x00\x75\x0E\xC7\x81\x00\x00\x00\x00\x00\x00\x00\x00\x48\x8B\x4B\x20\x41\xB7\x01", "xxxx????xxx????xxx????x????xxxxxx????xxxxxx?????xxxx????????xxxxxxxxx?????xxxx????xxx????xxx????x????xxxxxx????xxxxxx?????xxxx????????xxxxxxx" ), 0xEB, 0x30 ); // Always pass resolutionHeight -1 check so we can force new value. WriteProtected ( /* 0x140BB66CC */ ScanSignature ( "\x75\x41\x41\xB8\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x4B\x20\x89\x81\x00\x00\x00\x00\x48\x8B\x4B\x20\x83\xB9\x00\x00\x00\x00\x00\x75\x0E\xC7\x81\x00\x00\x00\x00\x00\x00\x00\x00\x48\x8B\x4B\x20\x41\xB7\x01\x41\x0F\xB6\xC7\x34\x01\x88\x81\x00\x00\x00\x00\x48\x8B\x4B\x20\x83\xB9\x00\x00\x00\x00\x00\x75\x40\x41\xB8\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x4B\x20\x89\x81\x00\x00\x00\x00\x48\x8B\x4B\x20\x83\xB9\x00\x00\x00\x00\x00\x75\x10\x8B\x81\x00\x00\x00\x00\x89\x81\x00\x00\x00\x00\x48\x8B\x4B\x20", "xxxx????xxx????xxx????x????xxxxxx????xxxxxx?????xxxx????????xxxxxxxxxxxxxxx????xxxxxx?????xxxx????xxx????xxx????x????xxxxxx????xxxxxx?????xxxx????xx????xxxx" ), 0xEB, 0x30 ); } Code "Fix Rail Landing Direction (experimental)" in "Fixes/Gameplay" by "Hyper" does /* Fixes the player landing in the opposite direction that was being faced prior to landing on a rail. Known issues; - Some rails in sequences from dash rings and springs may land the player in the wrong direction. */ // #include "BlackboardStatus" noemit #lib "BlackboardStatus" #lib "Player" #lib "VectorHelpers" #load "System.Numerics.dll" using System.Numerics; static bool _isGrindLand = false; static Vector3 _preGrindForward = Vector3.Zero; // { var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; if (IS_STATE_FLAG(IsGrind)) { if (!_isGrindLand) { // Check if player is sideways before applying look rotation. if (Vector3.Dot(Vector3.Transform(Vector3.UnitY, kinematics->Rotation), Vector3.UnitY) > 0.01f) kinematics->Rotation = VectorHelpers.LookRotation(_preGrindForward); _isGrindLand = true; } } else { _preGrindForward = Player.Kinematics.GetForward(); _isGrindLand = false; } } Code "Fix Wall Walking" in "Fixes/Gameplay" by "Hyper & Ahremic" does "Prevents the player from being able to walk vertically up walls at low speeds." // #lib "Player" #load "System.Numerics.dll" using System.Numerics; // { if (Player.State.GetCurrentStateID() != Sonic.StateID.StateRun) return; var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; if (Vector3.Transform(Vector3.UnitY, kinematics->Rotation).Y < 0.05f && Player.Kinematics.GetMagnitude() < 14.0f) { Player.State.SetState(Sonic.StateID.StateFall); } } Code "Fix Rolling in 2D" in "Fixes/Gameplay" by "Hyper" does /* Fixes the Drop Dash and Spin states getting stuck in 2D sections where the guide spline crosses paths with another. Notes; - It is highly recommended that you use this with the "Fix Drop Dash Transitions" and "Fix Spin Transitions" codes. */ // #include "Helpers" noemit #lib "DeltaTime" #lib "Globals" #lib "HMM" #lib "Memory" #lib "Player" #lib "VectorHelpers" #import "GOComponents" #load "System.Numerics.dll" using System.Numerics; static bool _isInitialised = false; static bool _isDropDashCameraDelay = true; static bool _isSideView = false; static int _sfxHandle = 0; static long _sigDropDashCameraDelay = 0; static long _sigPostureHook = 0; static long _sigSfxPlayer = 0; static long _sigSfxHandleAssignment = 0; static float _timeInCurrentPosition = 0.0f; static float _ceilingDetectionRadius = 0.01f; static float _ceilingDetectionTime = 0.1f; static float _lastYPosition = 0.0f; static float _airInfluenceMagnitude = 10.0f; static void SetDropDashCameraDelay(bool in_isEnabled) { if (_sigDropDashCameraDelay == 0) { // v1.41: 0x140956C32 _sigDropDashCameraDelay = ScanSignature ( "\x73\x2A\xF3\x0F\x10\x05\xCC\xCC\xCC\xCC\x45\x33\xC9", "xxxxxx????xxx" ); if (_sigDropDashCameraDelay == 0) return; } if (in_isEnabled && _isDropDashCameraDelay) { WriteProtected(_sigDropDashCameraDelay, 0x73); } else { WriteProtected(_sigDropDashCameraDelay, 0xEB); } } // { Globals.Add("Fix Rolling in 2D", true); if (Globals.GetFlag("Fix Rolling in 2D")) { if (!_isInitialised) { _isDropDashCameraDelay = !HMM.GetCodes().Contains("Camera/Disable Drop Dash Camera Delay"); fixed (bool* p_isSideView = &_isSideView) { // v1.41: 0x1408EA2CA var sigDropDashAirPosture = ScanSignature ( "\x0F\x29\xB4\x24\x80\x00\x00\x00\x48\x8D\x54\x24\x20\x0F\x10\xB7\x00\x01\x00\x00", "xxxxxxxxxxxxxxxxxxxx" ); // v1.41: 0x1408EA540 var sigDropDashGroundPosture = ScanSignature ( "\x48\x8B\xC4\x48\x89\x58\x08\x48\x89\x70\x10\x48\x89\x78\x18\x55\x41\x56\x41\x57\x48\x8D\x68\xA1\x48\x81\xEC\xD0\x00\x00\x00\x4C", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ); /* v1.41: 0x1408EA2B6 */ _sigPostureHook = ScanSignature ( "\x84\xC0\x74\x10\x0F\x28\xCF", "xxxxxxx" ); Memory.Preserve(_sigPostureHook, 15); WriteAsmHook ( $@" test al, al jnz doGroundPosture mov rax, {sigDropDashAirPosture} jmp rax doGroundPosture: mov rcx, {(long)p_isSideView} cmp byte ptr [rcx], 0 jnz exit movaps xmm1, xmm7 mov rcx, rbx mov rax, {sigDropDashGroundPosture} call rax exit: ", _sigPostureHook, HookBehavior.Replace ); } /* v1.41: 0x140956BC7 */ _sigSfxPlayer = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8D\x8D\xB0\x00\x00\x00\x48\x8B\xD0\xE8\xCC\xCC\xCC\xCC\xB2\x01", "x????xxxxxxxxxxx????xx" ); /* v1.41: 0x140956BD6 */ _sigSfxHandleAssignment = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\xB2\x01\x48\x8B\xCE\xE8\xCC\xCC\xCC\xCC\x33\xD2\x48\x8B\xCE\xE8\xCC\xCC\xCC\xCC\x48\x8B\x7E\x48", "x????xxxxxx????xxxxxx????xxxx" ); Memory.Preserve(_sigSfxPlayer, 5); Memory.Preserve(_sigSfxHandleAssignment, 5); WriteNop(_sigSfxPlayer, 5); WriteNop(_sigSfxHandleAssignment, 5); _isInitialised = true; } } else { Memory.Restore(_sigPostureHook); Memory.Restore(_sigSfxPlayer); Memory.Restore(_sigSfxHandleAssignment); SetDropDashCameraDelay(true); _isInitialised = false; return; } /* Check if we're grounded as well as in side view to allow the drop dash to work after using ramps. */ _isSideView = Player.Status.IsSideView() && Player.Status.IsGrounded(); ////////////////////////////////////////////////////////////////////////////////////////////////////////// // We have to do our own physics implementation here, since the mid-asm hook is effectively killing it. // ////////////////////////////////////////////////////////////////////////////////////////////////////////// if (!Memory.TryGetPointer(Player.Kinematics.Get(), out var out_pKinematics)) { SetDropDashCameraDelay(true); return; } var state = Player.State.GetCurrentStateID(); var deltaTime = DeltaTime.GetDeltaTime(); var isGrounded = Player.Status.IsGrounded(); if (state == Sonic.StateID.StateDropDash) { if (_sfxHandle == 0) _sfxHandle = Player.Sound.PlaySound("sn_spindash"); if (Player.Status.IsSideView() && !isGrounded) { _timeInCurrentPosition = 0.0f; Player.State.SetState(Sonic.StateID.StateSpin); return; } if (!_isSideView) return; var worldInput = out_pKinematics->WorldInput; if (worldInput.Length() <= 0.0f) return; var forward = VectorHelpers.GetForward(out_pKinematics->Rotation); var dot = Vector3.Dot(forward, worldInput); // Decelerate if the player is holding back in the opposite direction. if (1.0f - (float)-Math.Min(dot, 0) < 0.15f) out_pKinematics->Velocity -= Vector3.Normalize(out_pKinematics->Velocity) * Player.Kinematics.GetHorizontalMagnitude() * deltaTime; } else if (state == Sonic.StateID.StateSpin) { if (isGrounded) { SetDropDashCameraDelay(false); Player.State.SetState(Sonic.StateID.StateDropDash); return; } // Ceiling detection to escape into StateFall. { if (Math.Abs(_lastYPosition - out_pKinematics->Position.Y) <= _ceilingDetectionRadius) _timeInCurrentPosition += deltaTime; if (_timeInCurrentPosition >= _ceilingDetectionTime) { // Reset Y velocity to prevent Sonic from floating in place. out_pKinematics->Velocity.Y = 0.0f; // Switch to StateFall to prevent lingering on a ceiling in StateSpin. Player.State.SetState(Sonic.StateID.StateFall); _timeInCurrentPosition = 0.0f; } _lastYPosition = out_pKinematics->Position.Y; } // Don't run code if stick is neutral. if (out_pKinematics->WorldInput.Length() <= 0.0f) return; var horzMag = Player.Kinematics.GetHorizontalMagnitude(); var vertMag = Player.Kinematics.GetVerticalMagnitude(); // Don't run code if we're rolling horizontally. if (Math.Abs(vertMag) + _airInfluenceMagnitude < Math.Abs(horzMag)) return; var worldInputDirection = VectorHelpers.LookRotation(Vector3.Normalize(out_pKinematics->WorldInput)); out_pKinematics->Rotation = Quaternion.Slerp(out_pKinematics->Rotation, worldInputDirection, 0.25f); out_pKinematics->Velocity += VectorHelpers.GetForward(out_pKinematics->Rotation); // Limit magnitude horizontally. if (horzMag > _airInfluenceMagnitude) { var newVelocity = out_pKinematics->Velocity * (_airInfluenceMagnitude / horzMag); out_pKinematics->Velocity.X = newVelocity.X; out_pKinematics->Velocity.Z = newVelocity.Z; } } else { SetDropDashCameraDelay(true); if (_sfxHandle != 0) { fixed (int* p_sfxHandle = &_sfxHandle) Player.Sound.StopSound(p_sfxHandle); _sfxHandle = 0; } } } Patch "Fix Quick Cyloop Lock-On" in "Fixes/Gameplay" by "WasifBoomz & The Duck Dealer" does "Fixes the lock-on target changing whenever Sonic performs a Quick Cyloop, allowing for consistent attacks during combat." // #lib "Memory" // { Memory.WriteForceJump ( /* 0x1409C672F */ ScanSignature ( "\x76\x11\x8B\x06\x48\x8D\x55\x97\x48\x8B\xCB\x89\x45\x97\xE8\xCC\xCC\xCC\xCC\xB8\x03\x00\x00\x00", "xxxxxxxxxxxxxxx????xxxxx" ) ); } Patch "Fix Damage from Jumping into Enemies" in "Fixes/Gameplay" by "Hyper" does "Fixes Sonic taking damage when jumping into enemies within a small frame window." // #lib "Player" static bool IsJumpPrevious = false; // { Sonic.StateID NotifyJumpDamageCollision(Sonic.StateID in_stateId, Sonic.StateID[] in_stateStackTrace) { bool isJump = in_stateId == Sonic.StateID.StateJump || in_stateId == Sonic.StateID.StateDoubleJump || in_stateId == Sonic.StateID.StateGrindDoubleJump; if (isJump) { Player.Collision.SetCollisionSphere(Player.CollisionType.Damage, 1.0f); Player.Collision.SetEntityCollision(false); IsJumpPrevious = true; } else if (IsJumpPrevious) { Player.Collision.SetCollisionSphere(Player.CollisionType.Default, 1.0f); Player.Collision.SetEntityCollision(true); IsJumpPrevious = false; } return in_stateId; } Player.State.AddStateNotifyAction(NotifyJumpDamageCollision); } Patch "Fix Rail Switching Animation" in "Fixes/Animation" by "WasifBoomz & Sails" does "Stops the rail switching animation from ending abruptly." { WriteAsmHook ( $@" ; Check if (unknown float) is equal to 40 cmp dword ptr [r15+14h], 0x42200000 jz setSpeed jmp originalCode setSpeed: mov dword ptr [r15+18h], 0x3F266666 originalCode: movss xmm1, dword ptr [r15+18h] subss xmm0, dword ptr [rbx+r12*8] andps xmm1, xmm9 ", /* 0x140DA61A5 */ ScanSignature ( "\xF3\x41\x0F\x10\x4F\x18\xF3\x42\x0F\x5C\x04\xE3", "xxxxxxxxxxxx" ), HookBehavior.Replace ); } Patch "Fix Grind Leaning" in "Fixes/Animation" by "Hyper" does "Fixes the grind leaning animations always leaning left and ending prematurely when leaning right." // static float Bias = 1.0f; // { fixed (float* pBias = &Bias) { WriteAsmHook ( $@" mov rdx, {(long)pBias} movss xmm2, dword ptr [rdx] movss dword ptr [rsi + 0xD8], xmm0 mov rdx, {(long)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi("SPEED_RATIO")} ", /* 0x14084AD71 */ ScanSignature ( "\x0F\x28\xD0\xF3\x0F\x11\x86\xD8\x00\x00\x00", "xxxxxxxxxxx" ), HookBehavior.Replace ); } } Patch "Fix Squatting Animation" in "Fixes/Animation" by "angryzor" does "Plays the squat start animation when squatting from a standing pose." { WriteProtected ( /* v1.42: 0x14B6E10FA */ ScanSignature ( "\x83\xFD\x01\x48\x8D\x05\xCC\xCC\xCC\xCC\x48\x8D\x1D", "xxxxxx????xxx" ), Assemble("cmp ebp, 2") ); } Patch "Fix Upreel Grip Position" in "Fixes/Animation" by "ĐeäTh" does /* Adjusts Sonic's grip position on the Upreel object's handle so that it lines up with the actual object. */ { IntPtr gripOffsetPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(16); *((float*)gripOffsetPtr + 0) = 0.0f; *((float*)gripOffsetPtr + 1) = -1.025f; *((float*)gripOffsetPtr + 2) = 0.0f; *((float*)gripOffsetPtr + 3) = 0.0f; WriteAsmHook ( $@" mov rax, {(long)gripOffsetPtr} movups xmm15, [rax] mulps xmm0, xmm15 lea rdx, [rsp + 0x60] lea rcx, [rsp + 0x30] ", /* v1.10: 0x1498C86A7 */ /* v1.30: 0x14983C900 */ ScanSignature ( "\x0F\x59\x05\xCC\xCC\xCC\xCC\x48\x8D\x54\x24\x60\x48\x8D\x4C\x24\x30", "xxx????xxxxxxxxxx" ), HookBehavior.Replace ); WriteAsmHook ( $@" mov rax, {(long)gripOffsetPtr} movups xmm15, [rax] mulps xmm0, xmm15 lea rdx, [rbp - 0x10] lea rcx, [rbp - 0x30] ", /* v1.20: 0x1403973ED */ /* v1.30: 0x1403C7A3C */ ScanSignature ( "\x0F\x59\x05\xCC\xCC\xCC\xCC\x48\x8D\x55\xF0\x48\x8D\x4D\xD0", "xxx????xxxxxxxx" ), HookBehavior.Replace ); } Patch "Disable DLC Messages on New Game" in "UI/Messages" by "Hyper" does "Disables the intrusive DLC-related messages when playing on a new save." // #lib "Bridge.DisableMessages" // { Bridge.DisableMessages.IsDisabledDLCMessages = true; } Patch "Disable Tutorial Messages" in "UI/Messages" by "Hyper" does /* Disables all intrusive tutorial messages that appear under certain conditions for the first time. Notes; - This also disables Hint Rings. */ // #lib "Bridge.DisableMessages" // { // Hide hint rings. WriteProtected ( /* 0x14954A9EF */ ScanSignature ( "\x48\x89\xCF\xB2\x01\x48\x8D\x0D\xCC\xCC\xCC\xCC\xE8\xCC\xCC\xCC\xCC\xB2\x01\x48\x89\x47\x38\x48\x8D\x0D\xCC\xCC\xCC\xCC\xE8\xCC\xCC\xCC\xCC\x48\x89\x47\x40", "xxxxxxxx????x????xxxxxxxxx????x????xxxx" ), 0xEB, 0x63 ); Bridge.DisableMessages.IsDisabledTutorialMessages = true; } Patch "Hide Oxygen Gauge" in "UI/Display" by "Hyper" { WriteProtected ( /* 0x140A5A580 */ ScanSignature ( "\x74\x1C\xE8\xCC\xCC\xCC\xCC\x48\x8D\x0D\xCC\xCC\xCC\xCC\x48\x89\x4D\xF0\x48\x8D\x0D\xCC\xCC\xCC\xCC\xE9\x85\x00\x00\x00\xE8\xCC\xCC\xCC\xCC\x48\x8D\x0D\xCC\xCC\xCC\xCC\x48\x89\x4D\xF0\x48\x8D\x0D\xCC\xCC\xCC\xCC\xEB\x6C\x3D\x06\x24\x00\x00\x0F\x85\x98\x00\x00\x00\x0F\xB6\x42\x20", "xxx????xxx????xxxxxxx????xxxxxx????xxx????xxxxxxx????xxxxxxxxxxxxxxxxx" ), 0xEB ); } Patch "Hide Boost Gauge" in "UI/Display" by "Hyper" { WriteProtected ( /* 0x140A6C65A */ ScanSignature ( "\x74\x1C\xE8\xCC\xCC\xCC\xCC\x48\x8D\x0D\xCC\xCC\xCC\xCC\x48\x89\x4D\x87\x48\x8D\x0D\xCC\xCC\xCC\xCC\xE9\x93\x00\x00\x00", "xxx????xxx????xxxxxxx????xxxxx" ), 0xEB ); } Patch "Hide Homing Reticle" in "UI/Display" by "Hyper" // #lib "Memory" // { // Disable sound and main reticle. Memory.WriteForceJump ( /* 0x140A28C8C */ ScanSignature ( "\x0F\x84\xED\x00\x00\x00\x4D\x8D\xB5\x60\x01\x00\x00", "xxxxxxxxxxxxx" ) ); // Disable lock-on triangle. Memory.WriteForceJump ( /* 0x14C97ECA2 */ ScanSignature ( "\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x48\x89\x7C\x24\x18\x55\x48\x8D\x6C\x24\xA9\x48\x81\xEC\x90\x00\x00\x00\x48\x89\xCB\x48\xC7\x45\xFF\x02\x00\x00\x00", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ) + 0x232 ); } Patch "Hide Cyber Space Timer" in "UI/Display" by "Hyper" // #lib "Memory" // { Memory.WriteForceJump ( /* 0x140A6E5B1 */ ScanSignature ( "\x74\x1C\xE8\xCC\xCC\xCC\xCC\x48\x8D\x0D\xCC\xCC\xCC\xCC\x48\x89\x4D\xF0\x48\x8D\x0D\xCC\xCC\xCC\xCC\xE9\x86\x00\x00\x00\xE8\xCC\xCC\xCC\xCC\x48\x8D\x0D\xCC\xCC\xCC\xCC\x48\x89\x4D\xF0\x48\x8D\x0D\xCC\xCC\xCC\xCC\xEB\x6D\x3D\x06\x24\x00\x00\x0F\x85\x99\x00\x00\x00\x48\x8B\x42\x20\x48\xC1\xE8\x20\xA8\x01\x74\x72\x0F\xB6\x49\x3C", "xxx????xxx????xxxxxxx????xxxxxx????xxx????xxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ) ); } Patch "Hide Enemy Health Gauge" in "UI/Display" by "Hyper & Gordon Ramsay" does "Hides the health gauge for standard enemies and guardians." // #lib "Memory" // { Memory.WriteForceJump ( /* 0x1405CA39B */ ScanSignature ( "\x0F\x84\xF7\x00\x00\x00\xBA\xC6\x23\x00\x00", "xxxxxxxxxxx" ) ); } Patch "Hide Skill Piece Transition" in "UI/Display" by "Hyper" does "Removes the transition when picking up skill pieces to put them into the skill points display." { WriteNop ( /* 0x14091857E */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8D\x4D\x40\xE8\xCC\xCC\xCC\xCC\x48\x8D\x4D\x10", "x????xxxxx????xxxx" ), 5 ); WriteNop ( /* 0x14098D862 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8D\x4D\xD7\xE8\xCC\xCC\xCC\xCC\x48\x8D\x4D\xA7", "x????xxxxx????xxxx" ), 5 ); } Patch "Hide Fixed Camera Notifications" in "UI/Display" by "Hyper" does "Hides the fixed camera icon at the top-right of the screen, as well as the tutorial about it at the beginning of the game." // #lib "Memory" // { // Disable fixed camera UI element. WriteProtected ( /* 0x1408FA3DB */ ScanSignature ( "\x0F\x84\xEB\x00\x00\x00\x83\xF8\xFD\x0F\x84\x89\x00\x00\x00", "xxxxxxxxxxxxxxx" ), 0xEB, 0x0D ); // Disable guide regarding fixed camera. Memory.WriteForceJump ( /* v1.41: 0x14036FFE1 */ ScanSignature ( "\x0F\x84\x57\x01\x00\x00\x4C\x89\xB4\x24\x88\x00\x00\x00", "xxxxxxxxxxxxxx" ) ); } Patch "Hide Titan Health Gauge" in "UI/Display" by "Hyper" { WriteProtected ( /* v1.01: 0x14C76211A */ /* v1.10: 0x14C6036DB */ ScanSignature ( "\x74\x18\x48\x8D\x54\x24\x70\x48\x89\xC1\xE8\xCC\xCC\xCC\xCC\x48\x89\xFA", "xxxxxxxxxxx????xxx" ), 0xEB ); } Patch "Hide Skip Button in Cutscenes" in "UI/Display" by "Hyper" does "Hides the button prompt at the bottom-right to skip cutscenes. This does not disable the ability to skip cutscenes." { WriteProtected ( /* 0x1408BE1E8 */ ScanSignature ( "\x74\x71\x48\x8D\x5C\x24\x00\xBF\x00\x00\x00\x00\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x83\xC3\x18\x48\x83\xEF\x01\x75\xEE\x0F\x57\xC0\xC7\x84\x24\x00\x00\x00\x00\x00\x00\x00\x00\x4C\x8D\x05\x00\x00\x00\x00\x0F\x29\x84\x24\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x40\x88\xBC\x24\x00\x00\x00\x00\x48\x8D\x4C\x24\x00\xE8\x00\x00\x00\x00\x48\x8D\x54\x24\x00\x66\xC7\x84\x24\x00\x00\x00\x00\x00\x00\x48\x8B\xCD\xC6\x84\x24\x00\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\xAC\x24\x00\x00\x00\x00\xC6\x86\x00\x00\x00\x00\x00\x48\x81\xC4\x00\x00\x00\x00\x5F\x5E\x5B\xC3", "xxxxxx?x????xxxx????xxxxxxxxxxxxxxxx????????xxx????xxxx????xxx????xxxx????xxxx?x????xxxx?xxxx??????xxxxxx?????x????xxxx????xx?????xxx????xxxx" ), 0xEB ); } Patch "Hide Drift Input Prompt" in "UI/Display" by "Hyper" does "Hides the input prompt that covers up Sonic when using drift dash panels." { WriteNop ( /* 0x14081E868 */ ScanSignature ( "\xE8\x00\x00\x00\x00\x48\x8D\x4C\x24\x00\xE8\x00\x00\x00\x00\x4C\x8D\x05\x00\x00\x00\x00\x48\x8B\xD6\x48\x8D\x8C\x24\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8D\x8D\x00\x00\x00\x00\x48\x8B\xD0\xE8\x00\x00\x00\x00\x41\xB0\x01\xBA\x00\x00\x00\x00\x48\x8B\xCE\xE8\x00\x00\x00\x00\xBA\x00\x00\x00\x00\x48\x8B\xCE\xE8\x00\x00\x00\x00\xB2\x01\x48\x8B\xCE\x48\x8B\x9C\x24\x00\x00\x00\x00\x48\x81\xC4\x00\x00\x00\x00\x41\x5E\x5E\x5D\xE9\x00\x00\x00\x00", "x????xxxx?x????xxx????xxxxxxx????x????xxx????xxxx????xxxx????xxxx????x????xxxx????xxxxxxxxx????xxx????xxxxx????" ), 5 ); } Patch "Hide Party Decorations" in "UI/Display" by "Hyper" does "Disables the birthday party decorations on the HUD when using the Party Details option for Island Appearance in Extras." { WriteProtected ( /* 0x140968F33 */ ScanSignature ( "\x74\x0E\xE8\xCC\xCC\xCC\xCC\x48\x8D\x0D\xCC\xCC\xCC\xCC\xEB\x0C", "xxx????xxx????xx" ), 0xEB ); WriteProtected ( /* 0x140969157 */ ScanSignature ( "\x74\x04\x80\x4F\x28\x04", "xxxxxx" ), 0xEB ); } Patch "Force PlayStation 5 UI" in "UI/Controller" by "Hyper" { WriteAsmHook ( @" mov al, 1 add rsp, 20h pop rbx ret ", /* v1.01: 0x1409501E6 */ /* v1.10: 0x140950A80 */ ScanSignature ( "\x80\xF9\x02\x75\x60\x8B\xCA\xE8\x00\x00\x00\x00\x48\x8B\xD8\x48\x85\xC0\x74\x51\x48\x8B\x10\x48\x8B\xC8\xFF\x52\x38\x84\xC0\x74\x44\x48\x8B\xCB\xE8\x00\x00\x00\x00\x8B\x50\x54\x83\xEA\x01\x74\x2C\x83\xEA\x01\x74\x1F\x83\xEA\x01\x74\x2A\x83\xEA\x01\x74\x0D\x83\xFA\x01\x75\x20\xB0\x04\x48\x83\xC4\x20\x5B\xC3\xB0\x03\x48\x83\xC4\x20\x5B\xC3\xB0\x01\x48\x83\xC4\x20\x5B\xC3\x32\xC0\x48\x83\xC4\x20\x5B\xC3\xB0\x02\x48\x83\xC4\x20\x5B\xC3", "xxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); // Swap Share and Touchpad icons. WriteProtected ( /* 0x140951B39 */ ScanSignature ( "\x74\x1F\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x85\xC0\x74\x12\x80\x78\x4C\x02", "xxxxxx????xxxxxxxxx" ), 0xEB ); } Patch "Force PlayStation 4 UI" in "UI/Controller" by "Hyper" { WriteAsmHook ( @" mov al, 0 add rsp, 20h pop rbx ret ", /* v1.01: 0x1409501E6 */ /* v1.10: 0x140950A80 */ ScanSignature ( "\x80\xF9\x02\x75\x60\x8B\xCA\xE8\x00\x00\x00\x00\x48\x8B\xD8\x48\x85\xC0\x74\x51\x48\x8B\x10\x48\x8B\xC8\xFF\x52\x38\x84\xC0\x74\x44\x48\x8B\xCB\xE8\x00\x00\x00\x00\x8B\x50\x54\x83\xEA\x01\x74\x2C\x83\xEA\x01\x74\x1F\x83\xEA\x01\x74\x2A\x83\xEA\x01\x74\x0D\x83\xFA\x01\x75\x20\xB0\x04\x48\x83\xC4\x20\x5B\xC3\xB0\x03\x48\x83\xC4\x20\x5B\xC3\xB0\x01\x48\x83\xC4\x20\x5B\xC3\x32\xC0\x48\x83\xC4\x20\x5B\xC3\xB0\x02\x48\x83\xC4\x20\x5B\xC3", "xxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); // Swap Share and Touchpad icons. WriteProtected ( /* 0x140951B39 */ ScanSignature ( "\x74\x1F\x48\x8B\xC8\xE8\x00\x00\x00\x00\x48\x85\xC0\x74\x12\x80\x78\x4C\x02", "xxxxxx????xxxxxxxxx" ), 0xEB ); } Patch "Force Xbox One UI" in "UI/Controller" by "Hyper" { WriteAsmHook ( @" mov al, 2 add rsp, 20h pop rbx ret ", /* v1.01: 0x1409501E6 */ /* v1.10: 0x140950A80 */ ScanSignature ( "\x80\xF9\x02\x75\x60\x8B\xCA\xE8\x00\x00\x00\x00\x48\x8B\xD8\x48\x85\xC0\x74\x51\x48\x8B\x10\x48\x8B\xC8\xFF\x52\x38\x84\xC0\x74\x44\x48\x8B\xCB\xE8\x00\x00\x00\x00\x8B\x50\x54\x83\xEA\x01\x74\x2C\x83\xEA\x01\x74\x1F\x83\xEA\x01\x74\x2A\x83\xEA\x01\x74\x0D\x83\xFA\x01\x75\x20\xB0\x04\x48\x83\xC4\x20\x5B\xC3\xB0\x03\x48\x83\xC4\x20\x5B\xC3\xB0\x01\x48\x83\xC4\x20\x5B\xC3\x32\xC0\x48\x83\xC4\x20\x5B\xC3\xB0\x02\x48\x83\xC4\x20\x5B\xC3", "xxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); } Patch "Force Nintendo Switch UI" in "UI/Controller" by "Hyper" { WriteAsmHook ( @" mov al, 4 add rsp, 20h pop rbx ret ", /* v1.01: 0x1409501E6 */ /* v1.10: 0x140950A80 */ ScanSignature ( "\x80\xF9\x02\x75\x60\x8B\xCA\xE8\x00\x00\x00\x00\x48\x8B\xD8\x48\x85\xC0\x74\x51\x48\x8B\x10\x48\x8B\xC8\xFF\x52\x38\x84\xC0\x74\x44\x48\x8B\xCB\xE8\x00\x00\x00\x00\x8B\x50\x54\x83\xEA\x01\x74\x2C\x83\xEA\x01\x74\x1F\x83\xEA\x01\x74\x2A\x83\xEA\x01\x74\x0D\x83\xFA\x01\x75\x20\xB0\x04\x48\x83\xC4\x20\x5B\xC3\xB0\x03\x48\x83\xC4\x20\x5B\xC3\xB0\x01\x48\x83\xC4\x20\x5B\xC3\x32\xC0\x48\x83\xC4\x20\x5B\xC3\xB0\x02\x48\x83\xC4\x20\x5B\xC3", "xxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); } Patch "Force Xbox Series S|X UI" in "UI/Controller" by "Hyper" { WriteAsmHook ( @" mov al, 3 add rsp, 20h pop rbx ret ", /* v1.01: 0x1409501E6 */ /* v1.10: 0x140950A80 */ ScanSignature ( "\x80\xF9\x02\x75\x60\x8B\xCA\xE8\x00\x00\x00\x00\x48\x8B\xD8\x48\x85\xC0\x74\x51\x48\x8B\x10\x48\x8B\xC8\xFF\x52\x38\x84\xC0\x74\x44\x48\x8B\xCB\xE8\x00\x00\x00\x00\x8B\x50\x54\x83\xEA\x01\x74\x2C\x83\xEA\x01\x74\x1F\x83\xEA\x01\x74\x2A\x83\xEA\x01\x74\x0D\x83\xFA\x01\x75\x20\xB0\x04\x48\x83\xC4\x20\x5B\xC3\xB0\x03\x48\x83\xC4\x20\x5B\xC3\xB0\x01\x48\x83\xC4\x20\x5B\xC3\x32\xC0\x48\x83\xC4\x20\x5B\xC3\xB0\x02\x48\x83\xC4\x20\x5B\xC3", "xxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); } Patch "Disable Corruption Animations" in "Animation/Sonic" by "Hyper" does "Disables the animations for when Sonic becomes increasingly more corrupted in the later islands." { // LANDING_CORRUPTION_WEAK WriteProtected ( /* v1.10: 0x140830C7D */ ScanSignature ( "\x74\x15\xB8\x04\x00\x00\x00\x48\x8B\x5C\x24\x30", "xxxxxxxxxxxx" ), 0xEB ); // LANDING_CORRUPTION_STRONG WriteNop ( /* v1.10: 0x140830CA8 */ ScanSignature ( "\xBA\x05\x00\x00\x00\x0F\x45\xCA\x8B\xC1", "xxxxxxxxxx" ), 8 ); // IDLE_CORRUPTION_WEAK_LOOP WriteProtected ( /* v1.10: 0x140830DB4 */ ScanSignature ( "\x74\x15\xB8\x0B\x00\x00\x00", "xxxxxxx" ), 0xEB ); // IDLE_CORRUPTION_STRONG_LOOP WriteProtected ( /* v1.10: 0x140830DDA */ ScanSignature ( "\x74\x15\xB8\x0C\x00\x00\x00", "xxxxxxx" ), 0xEB ); } Code "Flail Falling" in "Animation/Sonic" by "Hyper" does "Replaces the spinning animation when flinging off terrain with a flailing animation." // #include "Helpers" noemit #lib "Memory" #lib "Player" static bool _isInitialised = false; static bool _isPlayerSonic = false; // { if (!_isInitialised) { /* 0x14B92ECE7 */ long sig = ScanSignature ( "\x41\xB0\xFE\x48\x8D\x15\xCC\xCC\xCC\xCC\x48\x89\xC1\xE8\xCC\xCC\xCC\xCC\xB2\x01\x48\x89\xF9\xE8\xCC\xCC\xCC\xCC\x84\xC0", "xxxxxx????xxxx????xxxxxx????xx" ); fixed (bool* p_isPlayerSonic = &_isPlayerSonic) { WriteAsmHook ( $@" mov r8b, 0xFE mov rdx, {(long)p_isPlayerSonic} mov dl, byte ptr [rdx] cmp dl, 1 jne isNotSonic mov rdx, {TO_STRING_PTR("BUMP_JUMP")} jmp exit isNotSonic: mov rdx, {TO_STRING_PTR("BUMP_JUMP_START")} exit: mov rcx, rax mov rax, {Memory.ReadCall(sig + 0x0D)} call rax ", sig, HookBehavior.Replace ); } _isInitialised = true; } _isPlayerSonic = Player.GetPlayerType() == Player.PlayerType.Sonic; } Code "Homing Attack Trick Animations" in "Animation/Sonic" by "Hyper & Ahremic" does "Replaces the homing attack finish animation with randomised trick animations." // #include "Helpers" noemit #lib "Memory" #lib "Player" using System.Runtime.InteropServices; static bool _isInitialised = false; static sbyte _playerType = -1; static Random _random = new Random(); static string[] _animVariations = new[] { "U", "D", "L", "R" }; static float _animSpeed = 0.5f; static IntPtr _pAnimName = Marshal.AllocHGlobal(14); // { string randAnimName = $"JUMP_TRICK_{_animVariations[_random.Next(0, 4)]}{_random.Next(0, 3)}\0"; Marshal.Copy(System.Text.Encoding.UTF8.GetBytes(randAnimName), 0, _pAnimName, randAnimName.Length); if (!_isInitialised) { /* 0x140823825 */ long playAnimCallerAddr = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x33\xD2\x49\x8B\xCE\xE8\xCC\xCC\xCC\xCC\x41\xB8\x74\x00\x00\x00", "x????xxxxxx????xxxxxx" ); /* 0x14086F023 */ long setAnimSpeedCallerAddr = ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8D\x05\xCC\xCC\xCC\xCC\xB9\x03\x00\x00\x00", "x????xxx????xxxxx" ); /* 0x1407C9300 */ long playAnimFuncAddr = Memory.ReadCall(playAnimCallerAddr); /* 0x1407C9DB0 */ long setAnimSpeedFuncAddr = Memory.ReadCall(setAnimSpeedCallerAddr); fixed (sbyte* p_playerType = &_playerType) fixed (float* p_animSpeed = &_animSpeed) { WriteAsmHook ( $@" mov rdx, {(long)p_playerType} cmp byte ptr [rdx], 0 jne default mov rdx, {(long)p_animSpeed} movss xmm2, dword ptr [rdx] mov rdx, {TO_STRING_PTR("SPEED_RATIO")} mov rcx, rax mov rax, {setAnimSpeedFuncAddr} mov rbx, rcx call rax mov rdx, {_pAnimName} mov rcx, rbx mov rax, {playAnimFuncAddr} call rax jmp exit default: mov rdx, {TO_STRING_PTR("ATTACK_BOUNCE")} mov rcx, rax mov rax, {playAnimFuncAddr} call rax exit: ", /* 0x14082381B */ playAnimCallerAddr - 0x0A, HookBehavior.Replace ); } _isInitialised = true; } _playerType = (sbyte)Player.GetPlayerType(); } Patch "Disable Stomp Transition" in "Animation/Knuckles" by "Hyper" { WriteNop ( /* 0x140986E9C */ ScanSignature ( "\x0F\x84\x64\x02\x00\x00\x48\x8B\x47\x38", "xxxxxxxxxx" ), 6 ); } Patch "Disable Gliding Transition" in "Animation/Knuckles" by "Hyper" // #lib "Memory" // { Memory.WriteForceJump ( /* v1.41: 0x14098C72E */ ScanSignature ( "\x0F\x85\x81\x00\x00\x00\xF3\x0F\x10\x75\xAF", "xxxxxxxxxxx" ) ); WriteNop ( /* 0x14098AE42 */ ScanSignature ( "\x74\x10\x48\x8D\x05\xCC\xCC\xCC\xCC\x48\x8D\x15", "xxxxx????xxx" ), 2 ); } Patch "Disable Card Spin Boost Transition" in "Animation/Amy" by "Hyper" // #lib "Player" // { Player.State.Redirect(Amy.StateID.AmyStateTarotBuild, Amy.StateID.AmyStateTarotBoost); WriteProtected ( /* 0x140927D57 */ ScanSignature ( "\x74\x45\xBA\x8B\x70\x61\x74", "xxxxxxx" ), 0xEB, 0x1B ); } Code "Use Swim Animation When Flying Underwater" in "Animation/Tails" by "Weezley" // #lib "Player" #import "States" // { if (Player.GetPlayerType() != Player.PlayerType.Tails) return; var pTailsFly = Player.State.GetState(); if (pTailsFly == null) return; if (pTailsFly->Phase == StateTailsFly.PhaseType.Tired) { Player.Animation.SetAnimation("FLY_DESCEND_LOOP"); } else if (pTailsFly->Phase == StateTailsFly.PhaseType.Intro) { Player.Animation.SetAnimation(Player.Status.IsUnderwater() ? "TAILS_BOOST_SWIM" : "FLY_START"); } else if (pTailsFly->Phase == StateTailsFly.PhaseType.Rise) { Player.Animation.SetAnimation(Player.Status.IsUnderwater() ? "TAILS_BOOST_SWIM" : "FLY_RISE_LOOP"); } else { Player.Animation.SetAnimation(Player.Status.IsUnderwater() ? "TAILS_BOOST_SWIM" : "FLY_CRUISE_LOOP"); } } Patch "Disable Stomp Transition" in "Animation/Tails" by "Hyper" { WriteNop ( /* 0x1409C19B7 */ ScanSignature ( "\x0F\x84\xEE\x00\x00\x00\x48\x8B\x46\x40", "xxxxxxxxxx" ), 6 ); } Patch "Disable Cyclone Transition" in "Animation/Tails" by "Hyper" // #lib "Player" // { Player.State.Redirect(Tails.StateID.StateCycloneAppear, Tails.StateID.StateCycloneBoost); } Library "KnucklesParameters" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamOffensive { [FieldOffset(0x00)] public ushort pointMin; [FieldOffset(0x02)] public ushort pointMax; [FieldOffset(0x04)] public float damageRandomRate; [FieldOffset(0x08)] public float damageRandomRateSS; [FieldOffset(0x0C)] public float shapeDamageRate; [FieldOffset(0x10)] public float shapeStunRate; [FieldOffset(0x14)] public float shapeStaggerRate; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDefensive { [FieldOffset(0x00)] public byte rateMin; [FieldOffset(0x01)] public byte rateMax; [FieldOffset(0x02)] public ushort infimumDropRings; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamAttackCommon { [FieldOffset(0x00)] public PlayerParamOffensive offensive; [FieldOffset(0x18)] public PlayerParamDefensive defensive; [FieldOffset(0x1C)] public float criticalDamageRate; [FieldOffset(0x20)] public float criticalRate; [FieldOffset(0x24)] public float criticalRateSS; [FieldOffset(0x28)] public float downedDamageRate; } public enum HitSE : sbyte { SE_None = -1, Weak = 0, Strong = 1, VeryStrong = 2 } [StructLayout(LayoutKind.Explicit, Size = 8)] public struct UnmanagedString { [FieldOffset(0)] public long pValue; public string Value { get { if (pValue == 0) return string.Empty; return Marshal.PtrToStringAnsi((nint)pValue); } set => pValue = (long)Marshal.StringToHGlobalAnsi(value); } public UnmanagedString(string in_value) { Value = in_value; } public static implicit operator UnmanagedString(string in_value) { return new UnmanagedString(in_value); } public static bool operator ==(UnmanagedString in_left, string in_right) { return in_left.Value == in_right; } public static bool operator !=(UnmanagedString in_left, string in_right) { return !(in_left == in_right); } public override bool Equals(object in_obj) { if (in_obj is string str) return Value == str; return base.Equals(in_obj); } public override int GetHashCode() { return Value.GetHashCode(); } public override string ToString() { return Value; } } [StructLayout(LayoutKind.Explicit, Size = 0x160)] public struct PlayerParamAttackData { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float damageRateSS; [FieldOffset(0x08)] public ushort pointMin; [FieldOffset(0x0A)] public ushort pointMax; [FieldOffset(0x0C)] public float damageRateAcceleMode; [FieldOffset(0x10)] public float damageRateManual; [FieldOffset(0x14)] public float stunPoint; [FieldOffset(0x18)] public float staggerPoint; [FieldOffset(0x20)] public Vector3 velocity; [FieldOffset(0x30)] public float velocityKeepTime; [FieldOffset(0x34)] public float addComboValue; [FieldOffset(0x38)] public float addComboValueAccele; [FieldOffset(0x3C)] public float addComboValueSS; [FieldOffset(0x40)] public float addComboValueAcceleSS; [FieldOffset(0x44)] public float addQuickCyloopEnergy; [FieldOffset(0x48)] public float addQuickCyloopEnergyAccele; [FieldOffset(0x4C)] public float addQuickCyloopEnergySS; [FieldOffset(0x50)] public float addQuickCyloopEnergyAcceleSS; [FieldOffset(0x54)] public float addQuickCyloopEnergyGuard; [FieldOffset(0x58)] public float addQuickCyloopEnergyAcceleGuard; [FieldOffset(0x60)] public Vector3 gimmickVelocity; [FieldOffset(0x70)] public float ignoreTime; [FieldOffset(0x74)] public uint attributes; [FieldOffset(0x78)] public HitSE se; [FieldOffset(0x80)] public UnmanagedString hitEffectName; [FieldOffset(0x90)] public UnmanagedString hitEffectNameSS; [FieldOffset(0xA0)] public UnmanagedString hitStopName; [FieldOffset(0xB0)] public UnmanagedString hitStopNameDead; [FieldOffset(0xC0)] public UnmanagedString hitStopNameDeadBoss; [FieldOffset(0xD0)] public UnmanagedString hitStopNameSS; [FieldOffset(0xE0)] public UnmanagedString hitStopNameDeadSS; [FieldOffset(0xF0)] public UnmanagedString hitCameraShakeName; [FieldOffset(0x100)] public UnmanagedString hitCameraShakeNameDead; [FieldOffset(0x110)] public UnmanagedString hitCameraShakeNameDeadBoss; [FieldOffset(0x120)] public UnmanagedString hitCameraShakeNameSS; [FieldOffset(0x130)] public UnmanagedString hitCameraShakeNameDeadSS; [FieldOffset(0x140)] public UnmanagedString hitVibrationName; [FieldOffset(0x150)] public UnmanagedString hitVibrationNameSS; } [StructLayout(LayoutKind.Explicit, Size = 0x4A70)] public struct PlayerParamAttack { [FieldOffset(0x00)] public PlayerParamAttackCommon common; [FieldOffset(0x30)] public PlayerParamAttackData spinAttack; [FieldOffset(0x190)] public PlayerParamAttackData spinDash; [FieldOffset(0x2F0)] public PlayerParamAttackData homingAttack; [FieldOffset(0x450)] public PlayerParamAttackData homingAttackAir; [FieldOffset(0x5B0)] public PlayerParamAttackData pursuitKick; [FieldOffset(0x710)] public PlayerParamAttackData stomping; [FieldOffset(0x870)] public PlayerParamAttackData stompingAttack; [FieldOffset(0x9D0)] public PlayerParamAttackData boundStompingLast; [FieldOffset(0xB30)] public PlayerParamAttackData sliding; [FieldOffset(0xC90)] public PlayerParamAttackData loopKick; [FieldOffset(0xDF0)] public PlayerParamAttackData crasher; [FieldOffset(0xF50)] public PlayerParamAttackData spinSlashHoming; [FieldOffset(0x10B0)] public PlayerParamAttackData spinSlash; [FieldOffset(0x1210)] public PlayerParamAttackData spinSlashLast; [FieldOffset(0x1370)] public PlayerParamAttackData sonicBoom; [FieldOffset(0x14D0)] public PlayerParamAttackData crossSlash; [FieldOffset(0x1630)] public PlayerParamAttackData homingShot; [FieldOffset(0x1790)] public PlayerParamAttackData chargeAttack; [FieldOffset(0x18F0)] public PlayerParamAttackData chargeAttackLast; [FieldOffset(0x1A50)] public PlayerParamAttackData cyloop; [FieldOffset(0x1BB0)] public PlayerParamAttackData cyloopQuick; [FieldOffset(0x1D10)] public PlayerParamAttackData cyloopAerial; [FieldOffset(0x1E70)] public PlayerParamAttackData accele1; [FieldOffset(0x1FD0)] public PlayerParamAttackData accele2; [FieldOffset(0x2130)] public PlayerParamAttackData aerialAccele1; [FieldOffset(0x2290)] public PlayerParamAttackData aerialAccele2; [FieldOffset(0x23F0)] public PlayerParamAttackData comboFinish; [FieldOffset(0x2550)] public PlayerParamAttackData comboFinishF; [FieldOffset(0x26B0)] public PlayerParamAttackData comboFinishB; [FieldOffset(0x2810)] public PlayerParamAttackData comboFinishL; [FieldOffset(0x2970)] public PlayerParamAttackData comboFinishR; [FieldOffset(0x2AD0)] public PlayerParamAttackData acceleComboFinish; [FieldOffset(0x2C30)] public PlayerParamAttackData acceleComboFinishF; [FieldOffset(0x2D90)] public PlayerParamAttackData acceleComboFinishB; [FieldOffset(0x2EF0)] public PlayerParamAttackData acceleComboFinishL; [FieldOffset(0x3050)] public PlayerParamAttackData acceleComboFinishR; [FieldOffset(0x31B0)] public PlayerParamAttackData smash; [FieldOffset(0x3310)] public PlayerParamAttackData smashLast; [FieldOffset(0x3470)] public PlayerParamAttackData slingShot; [FieldOffset(0x35D0)] public PlayerParamAttackData knucklesPunch1; [FieldOffset(0x3730)] public PlayerParamAttackData knucklesPunch2; [FieldOffset(0x3890)] public PlayerParamAttackData knucklesUppercut; [FieldOffset(0x39F0)] public PlayerParamAttackData knucklesHeatKnuckle; [FieldOffset(0x3B50)] public PlayerParamAttackData knucklesHeatKnuckleLast; [FieldOffset(0x3CB0)] public PlayerParamAttackData amyTarotAttack; [FieldOffset(0x3E10)] public PlayerParamAttackData amyTarotAttack2; [FieldOffset(0x3F70)] public PlayerParamAttackData amyTarotRolling; [FieldOffset(0x40D0)] public PlayerParamAttackData amyCharmAttack; [FieldOffset(0x4230)] public PlayerParamAttackData amyTarotBoost; [FieldOffset(0x4390)] public PlayerParamAttackData tailsSpanner; [FieldOffset(0x44F0)] public PlayerParamAttackData tailsSpannerFloat; [FieldOffset(0x4650)] public PlayerParamAttackData tailsPowerBoost; [FieldOffset(0x47B0)] public PlayerParamAttackData tailsWaveCannon; [FieldOffset(0x4910)] public PlayerParamAttackData tailsWaveCannonFinish; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamWaterAct { [FieldOffset(0x00)] public float resistRate; [FieldOffset(0x04)] public float breatheBrake; [FieldOffset(0x08)] public float breatheTime; [FieldOffset(0x0C)] public float breatheGravity; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBaseJump { [FieldOffset(0x00)] public float baseSpeed; [FieldOffset(0x04)] public float upSpeed; [FieldOffset(0x08)] public float upSpeedAir; [FieldOffset(0x0C)] public float edgeSpeed; [FieldOffset(0x10)] public float airActionTime; [FieldOffset(0x14)] public float wallMoveTime; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamBallMove { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float slidePower; [FieldOffset(0x08)] public float brakeForce; [FieldOffset(0x0C)] public float slidePowerSlalom; [FieldOffset(0x10)] public float brakeForceSlalom; [FieldOffset(0x14)] public float releaseSpeed; [FieldOffset(0x18)] public bool useInput; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamLocusData { [FieldOffset(0x00)] public float width; [FieldOffset(0x04)] public float distance; [FieldOffset(0x08)] public float u0; [FieldOffset(0x0C)] public float u1; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamLocus { [FieldOffset(0x00)] public unsafe fixed byte /* PlayerParamLocusData[4] */ _data[64]; public unsafe PlayerParamLocusData* data { get { fixed (byte* p_data = _data) return (PlayerParamLocusData*)p_data; } } } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAuraTrain { [FieldOffset(0x00)] public float effectSpanTime; [FieldOffset(0x04)] public float effectLifeTime; [FieldOffset(0x08)] public float effectOffsetDistance; [FieldOffset(0x0C)] public float effectOverlapDistance; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamLevel { [FieldOffset(0x00)] public byte ringsLevel; [FieldOffset(0x01)] public byte speedLevel; [FieldOffset(0x02)] public byte offensiveLevel; [FieldOffset(0x03)] public byte defensiveLevel; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamBarrierWall { [FieldOffset(0x00)] public float coolTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamDamageRateLevel { [FieldOffset(0x00)] public unsafe fixed float rates[5]; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerParamDamageRate { [FieldOffset(0x00)] public unsafe fixed byte /* PlayerParamDamageRateLevel[4] */ _diffculties[80]; public unsafe PlayerParamDamageRateLevel* diffculties { get { fixed (byte* p_diffculties = _diffculties) return (PlayerParamDamageRateLevel*)p_diffculties; } } } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamAcceleMode { [FieldOffset(0x00)] public float declineSpeed; [FieldOffset(0x04)] public float declineSpeedAccele; [FieldOffset(0x08)] public float lossDamaged; [FieldOffset(0x0C)] public float lossDamagedAccele; [FieldOffset(0x10)] public uint comboRateAccele; } [StructLayout(LayoutKind.Explicit, Size = 0x4B70)] public struct CommonPackage { [FieldOffset(0x00)] public PlayerParamAttack attack; [FieldOffset(0x4A70)] public PlayerParamWaterAct wateract; [FieldOffset(0x4A80)] public PlayerParamBaseJump basejump; [FieldOffset(0x4A98)] public PlayerParamBallMove ballmove; [FieldOffset(0x4AB4)] public PlayerParamLocus locus; [FieldOffset(0x4AF4)] public PlayerParamAuraTrain auratrain; [FieldOffset(0x4B04)] public PlayerParamLevel level; [FieldOffset(0x4B08)] public PlayerParamBarrierWall barrierWall; [FieldOffset(0x4B0C)] public PlayerParamDamageRate damageRate; [FieldOffset(0x4B5C)] public PlayerParamAcceleMode acceleMode; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamComboCommon { [FieldOffset(0x00)] public float longPressTime; } public enum ComboMoveType : byte { Homing = 0, Step = 1, None = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamComboMove { [FieldOffset(0x00)] public ComboMoveType moveType; [FieldOffset(0x04)] public float moveInitialSpeed; [FieldOffset(0x08)] public float moveMaxSpeed; [FieldOffset(0x0C)] public float moveAccele; [FieldOffset(0x10)] public float timeout; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct PlayerParamComboMoveCorrection { [FieldOffset(0x00)] public float moveSpeed; [FieldOffset(0x04)] public float rotateSpeed; } public enum Action : sbyte { Root = 0, HomingAttack = 1, AerialHomingAttack = 2, Pursuit = 3, Stomping = 4, LoopKick = 5, Crasher = 6, SpinSlash = 7, SonicBoom = 8, CrossSlash = 9, HomingShot = 10, ChargeAttack = 11, QuickCyloop = 12, AerialQuickCyloop = 13, AcceleCombo1 = 14, AcceleCombo2 = 15, AcceleCombo3 = 16, AcceleCombo4 = 17, AerialAcceleCombo1 = 18, AerialAcceleCombo2 = 19, AerialAcceleCombo3 = 20, AerialAcceleCombo4 = 21, ComboFinish = 22, SpinJump = 23, Smash = 24, Behind = 25, Guarded = 26, Avoid = 27, AirBoost = 28, AfterAirBoost = 29, KnucklesPunch1 = 30, KnucklesPunch2 = 31, KnucklesUppercut = 32, KnucklesCyKnuckle = 33, KnucklesHeatKnuckle = 34, AmyTarotAttack = 35, AmyTarotAttack2 = 36, AmyTarotRolling = 37, AmyCyHammer = 38, AmyCharmAttack = 39, TailsSpanner = 40, ActionNum = 41 } [StructLayout(LayoutKind.Explicit, Size = 0x12)] public struct PlayerParamComboTransit { [FieldOffset(0x00)] public unsafe fixed byte /* Action[6] */ _transitExistTarget[6]; public unsafe Action* transitExistTarget { get { fixed (byte* p_transitExistTarget = _transitExistTarget) return (Action*)p_transitExistTarget; } } [FieldOffset(0x06)] public unsafe fixed byte /* Action[6] */ _transitInAir[6]; public unsafe Action* transitInAir { get { fixed (byte* p_transitInAir = _transitInAir) return (Action*)p_transitInAir; } } [FieldOffset(0x0C)] public unsafe fixed byte /* Action[6] */ _transitNotExistTarget[6]; public unsafe Action* transitNotExistTarget { get { fixed (byte* p_transitNotExistTarget = _transitNotExistTarget) return (Action*)p_transitNotExistTarget; } } } [StructLayout(LayoutKind.Explicit, Size = 0x2AC)] public struct PlayerParamComboTransitTable { [FieldOffset(0x00)] public PlayerParamComboTransit root; [FieldOffset(0x12)] public PlayerParamComboTransit homingAttack; [FieldOffset(0x24)] public PlayerParamComboTransit aerialHoming; [FieldOffset(0x36)] public PlayerParamComboTransit pursuit; [FieldOffset(0x48)] public PlayerParamComboTransit stomping; [FieldOffset(0x5A)] public PlayerParamComboTransit loopKick; [FieldOffset(0x6C)] public PlayerParamComboTransit crasher; [FieldOffset(0x7E)] public PlayerParamComboTransit spinSlash; [FieldOffset(0x90)] public PlayerParamComboTransit sonicBoom; [FieldOffset(0xA2)] public PlayerParamComboTransit crossSlash; [FieldOffset(0xB4)] public PlayerParamComboTransit homingShot; [FieldOffset(0xC6)] public PlayerParamComboTransit chargeAttack; [FieldOffset(0xD8)] public PlayerParamComboTransit quickCyloop; [FieldOffset(0xEA)] public PlayerParamComboTransit aerialQuickCyloop; [FieldOffset(0xFC)] public PlayerParamComboTransit acceleCombo1; [FieldOffset(0x10E)] public PlayerParamComboTransit acceleCombo2; [FieldOffset(0x120)] public PlayerParamComboTransit acceleCombo3; [FieldOffset(0x132)] public PlayerParamComboTransit acceleCombo4; [FieldOffset(0x144)] public PlayerParamComboTransit aerialAcceleCombo1; [FieldOffset(0x156)] public PlayerParamComboTransit aerialAcceleCombo2; [FieldOffset(0x168)] public PlayerParamComboTransit aerialAcceleCombo3; [FieldOffset(0x17A)] public PlayerParamComboTransit aerialAcceleCombo4; [FieldOffset(0x18C)] public PlayerParamComboTransit behind; [FieldOffset(0x19E)] public PlayerParamComboTransit guarded; [FieldOffset(0x1B0)] public PlayerParamComboTransit avoid; [FieldOffset(0x1C2)] public PlayerParamComboTransit airBoost; [FieldOffset(0x1D4)] public PlayerParamComboTransit afterAirBoost; [FieldOffset(0x1E6)] public PlayerParamComboTransit knucklesPunch1; [FieldOffset(0x1F8)] public PlayerParamComboTransit knucklesPunch2; [FieldOffset(0x20A)] public PlayerParamComboTransit knucklesUppercut; [FieldOffset(0x21C)] public PlayerParamComboTransit knucklesCyKnuckle; [FieldOffset(0x22E)] public PlayerParamComboTransit knucklesHeatKnuckle; [FieldOffset(0x240)] public PlayerParamComboTransit amyTarotAttack; [FieldOffset(0x252)] public PlayerParamComboTransit amyTarotAttack2; [FieldOffset(0x264)] public PlayerParamComboTransit amyTarotRolling; [FieldOffset(0x276)] public PlayerParamComboTransit amyCyHammer; [FieldOffset(0x288)] public PlayerParamComboTransit amyCharmAttack; [FieldOffset(0x29A)] public PlayerParamComboTransit tailsSpanner; } [StructLayout(LayoutKind.Explicit, Size = 0x2E0)] public struct PlayerParamCombo { [FieldOffset(0x00)] public PlayerParamComboCommon common; [FieldOffset(0x04)] public PlayerParamComboMove comboMoveSonic; [FieldOffset(0x18)] public PlayerParamComboMove comboMoveSupersonic; [FieldOffset(0x2C)] public PlayerParamComboMoveCorrection comboMoveCorrection; [FieldOffset(0x34)] public PlayerParamComboTransitTable comboTable; } public enum Condition : sbyte { Time = 0, Animation = 1 } public enum Shape : sbyte { Sphere = 0, Cylinder = 1, Box = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamAttackCollider { [FieldOffset(0x00)] public Condition condition; [FieldOffset(0x01)] public sbyte count; [FieldOffset(0x04)] public float spanTime; [FieldOffset(0x08)] public Shape shape; [FieldOffset(0x10)] public Vector3 shapeSize; [FieldOffset(0x20)] public Vector3 shapeOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct KnucklesParamComboPunch1 { [FieldOffset(0x00)] public PlayerParamAttackCollider hit; [FieldOffset(0x30)] public float motionScale; [FieldOffset(0x34)] public float motionSpeedRate; [FieldOffset(0x38)] public int fallSpeedBaseCount; [FieldOffset(0x3C)] public float fallSpeedStep; [FieldOffset(0x40)] public float fallSpeedMax; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct KnucklesParamComboPunch2 { [FieldOffset(0x00)] public PlayerParamAttackCollider hit; [FieldOffset(0x30)] public float motionScale; [FieldOffset(0x34)] public float motionSpeedRate; [FieldOffset(0x38)] public int fallSpeedBaseCount; [FieldOffset(0x3C)] public float fallSpeedStep; [FieldOffset(0x40)] public float fallSpeedMax; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct KnucklesParamComboUppercut { [FieldOffset(0x00)] public PlayerParamAttackCollider hit; [FieldOffset(0x30)] public float motionScale; [FieldOffset(0x34)] public float motionSpeedRate; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct KnucklesParamParryDebuff { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float effectTime; } [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct CyloopSlashEffectBaseParameter { [FieldOffset(0x00)] public int m_divideCircle; [FieldOffset(0x04)] public float m_circleRadius; [FieldOffset(0x08)] public float m_circleWaveCycle; [FieldOffset(0x0C)] public float m_circleWaveWidth; [FieldOffset(0x10)] public float m_circleWaveSpeed; [FieldOffset(0x14)] public Vector2 m_scale; [FieldOffset(0x20)] public UnmanagedString m_textureName; [FieldOffset(0x30)] public float m_flowSpeed; [FieldOffset(0x34)] public float m_twistCycle; [FieldOffset(0x38)] public float m_rollCycle; [FieldOffset(0x3C)] public float m_rollPhase; [FieldOffset(0x40)] public float m_alphaHeadDistance; [FieldOffset(0x44)] public float m_alphaTailDistance; [FieldOffset(0x48)] public float m_offsetCycle; [FieldOffset(0x4C)] public float m_offsetPhase; [FieldOffset(0x50)] public float m_offsetRadius; } public struct ColorF { public float A; public float R; public float G; public float B; } [StructLayout(LayoutKind.Explicit, Size = 0xA8)] public struct CyloopTransparentLocusParameter { [FieldOffset(0)] public CyloopSlashEffectBaseParameter cyloopSlashEffectBaseParameter; [FieldOffset(0x58)] public ColorF m_color0; [FieldOffset(0x68)] public ColorF m_color1; [FieldOffset(0x78)] public float m_luminance; [FieldOffset(0x7C)] public ColorF m_flashColor0; [FieldOffset(0x8C)] public ColorF m_flashColor1; [FieldOffset(0x9C)] public float m_flashLuminance; [FieldOffset(0xA0)] public float m_flashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct OpaqueLineUvCell { [FieldOffset(0x00)] public float scale; [FieldOffset(0x04)] public float speedX; [FieldOffset(0x08)] public float speedY; } [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct CyloopOpaqueLocusParameter { [FieldOffset(0)] public CyloopSlashEffectBaseParameter cyloopSlashEffectBaseParameter; [FieldOffset(0x58)] public ColorF m_color; [FieldOffset(0x68)] public float m_alphaThreshold; [FieldOffset(0x6C)] public unsafe fixed byte /* OpaqueLineUvCell[2] */ _m_uvCells[24]; public unsafe OpaqueLineUvCell* m_uvCells { get { fixed (byte* p_m_uvCells = _m_uvCells) return (OpaqueLineUvCell*)p_m_uvCells; } } [FieldOffset(0x84)] public float m_uvLineScaleX; [FieldOffset(0x88)] public float m_uvLineScaleY; [FieldOffset(0x8C)] public ColorF m_flashColor; [FieldOffset(0x9C)] public float m_flashTime; } [StructLayout(LayoutKind.Explicit, Size = 0xF0)] public struct CyloopCrossLineParameter { [FieldOffset(0x00)] public UnmanagedString m_textureNamePattern; [FieldOffset(0x10)] public UnmanagedString m_textureNameDist; [FieldOffset(0x20)] public ColorF startColor; [FieldOffset(0x30)] public ColorF endColor; [FieldOffset(0x40)] public float startColorLuminance; [FieldOffset(0x44)] public float endColorLuminance; [FieldOffset(0x48)] public ColorF startColorFlash; [FieldOffset(0x58)] public ColorF endColorFlash; [FieldOffset(0x68)] public float startColorLuminanceFlash; [FieldOffset(0x6C)] public float endColorLuminanceFlash; [FieldOffset(0x70)] public float flashTime; [FieldOffset(0x74)] public float patternDepth; [FieldOffset(0x78)] public float patternScrollSpeed; [FieldOffset(0x7C)] public float patternDarkness; [FieldOffset(0x80)] public float patternScale; [FieldOffset(0x84)] public float glitchResX; [FieldOffset(0x88)] public float glitchResY; [FieldOffset(0x8C)] public float glitchOffset; [FieldOffset(0x90)] public float glitchMaxLength; [FieldOffset(0x94)] public float startGlitchScrollSpeed; [FieldOffset(0x98)] public float startGlitchChangeSpeed; [FieldOffset(0x9C)] public float startGlitchShift; [FieldOffset(0xA0)] public float startGlitchContrust; [FieldOffset(0xA4)] public float endGlitchScrollSpeed; [FieldOffset(0xA8)] public float endGlitchChangeSpeed; [FieldOffset(0xAC)] public float endGlitchShift; [FieldOffset(0xB0)] public float endGlitchContrust; [FieldOffset(0xB4)] public float lineWidth; [FieldOffset(0xB8)] public float lineDisplayWidth; [FieldOffset(0xBC)] public float lineBlackEdgeWidth; [FieldOffset(0xC0)] public float lineBlackEdgeIntensity; [FieldOffset(0xC4)] public float lineBlackEdgeNormalFade; [FieldOffset(0xC8)] public float distNoiseScale; [FieldOffset(0xCC)] public float distLowNoiseScale; [FieldOffset(0xD0)] public float distHighNoiseScale; [FieldOffset(0xD4)] public float distNoiseRate; [FieldOffset(0xD8)] public float distScrollSpeed; [FieldOffset(0xDC)] public float distIntensity; [FieldOffset(0xE0)] public float dissolve; [FieldOffset(0xE4)] public float dissolveRate; [FieldOffset(0xE8)] public float heightOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x4E0)] public struct CyloopLocusParameter { [FieldOffset(0x00)] public int m_numTransparentLines; [FieldOffset(0x08)] public unsafe fixed byte /* CyloopTransparentLocusParameter[3] */ _m_transparentLines[504]; public unsafe CyloopTransparentLocusParameter* m_transparentLines { get { fixed (byte* p_m_transparentLines = _m_transparentLines) return (CyloopTransparentLocusParameter*)p_m_transparentLines; } } [FieldOffset(0x200)] public int m_numOpaqueLines; [FieldOffset(0x208)] public unsafe fixed byte /* CyloopOpaqueLocusParameter[3] */ _m_opaqueLines[480]; public unsafe CyloopOpaqueLocusParameter* m_opaqueLines { get { fixed (byte* p_m_opaqueLines = _m_opaqueLines) return (CyloopOpaqueLocusParameter*)p_m_opaqueLines; } } [FieldOffset(0x3E8)] public int m_numCrossLines; [FieldOffset(0x3F0)] public CyloopCrossLineParameter m_crossline; } [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct CyloopDropItemWeightParameter { [FieldOffset(0x00)] public uint noneWeight; [FieldOffset(0x04)] public uint ring10Weight; [FieldOffset(0x08)] public uint powerSeedWeight; [FieldOffset(0x0C)] public uint guardSeedWeight; [FieldOffset(0x10)] public uint sequenceItemWeight; [FieldOffset(0x14)] public uint portalBitWeight; [FieldOffset(0x18)] public uint skillPieceWeight; [FieldOffset(0x1C)] public uint skillPieceAmyWeight; [FieldOffset(0x20)] public uint skillPieceKnucklesWeight; [FieldOffset(0x24)] public uint skillPieceTailsWeight; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct CyloopDropItemParameter { [FieldOffset(0x00)] public CyloopDropItemWeightParameter weight; [FieldOffset(0x28)] public CyloopDropItemWeightParameter weight2; [FieldOffset(0x50)] public uint numRings; [FieldOffset(0x54)] public uint numRings2; [FieldOffset(0x58)] public uint num10Rings; [FieldOffset(0x5C)] public uint numSkillPieces; [FieldOffset(0x60)] public uint skillPieceExp; [FieldOffset(0x64)] public float rareDropCoolTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct CyloopShapeWindCountParameter { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float stunRate; [FieldOffset(0x08)] public float staggerRate; [FieldOffset(0x0C)] public float velocityRate; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct CyloopShapeWindEffectParaemter { [FieldOffset(0x00)] public unsafe fixed byte /* CyloopShapeWindCountParameter[5] */ _param[80]; public unsafe CyloopShapeWindCountParameter* param { get { fixed (byte* p_param = _param) return (CyloopShapeWindCountParameter*)p_param; } } } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct CyloopShapeEffectParameter { [FieldOffset(0x00)] public CyloopShapeWindEffectParaemter wind; } [StructLayout(LayoutKind.Explicit, Size = 0x1460)] public struct PlayerParamCyloop { [FieldOffset(0x00)] public CyloopLocusParameter locus; [FieldOffset(0x4E0)] public CyloopLocusParameter locusQuick; [FieldOffset(0x9C0)] public CyloopLocusParameter locusSuperSonic; [FieldOffset(0xEA0)] public CyloopLocusParameter locusSuperSonicQuick; [FieldOffset(0x1380)] public ColorF auraColor; [FieldOffset(0x1390)] public CyloopDropItemParameter dropItem; [FieldOffset(0x13F8)] public float needSpeed; [FieldOffset(0x13FC)] public CyloopShapeEffectParameter shapeEffect; [FieldOffset(0x144C)] public float lossQuickCyloopEnergy; [FieldOffset(0x1450)] public float recoveryQuickCyloopEnergyByTime; [FieldOffset(0x1454)] public float recoveryQuickCyloopEnergyByTimeInMinigame; [FieldOffset(0x1458)] public float recoveryFriendsQuickCyloopEnergyByRing; } [StructLayout(LayoutKind.Explicit, Size = 0x63A0)] public struct CommonPackageKnuckles { [FieldOffset(0)] public CommonPackage commonPackage; [FieldOffset(0x4B70)] public PlayerParamCombo combo; [FieldOffset(0x4E50)] public KnucklesParamComboPunch1 comboPunch1; [FieldOffset(0x4EA0)] public KnucklesParamComboPunch2 comboPunch2; [FieldOffset(0x4EF0)] public KnucklesParamComboUppercut comboUppercut; [FieldOffset(0x4F30)] public KnucklesParamParryDebuff parryDebuff; [FieldOffset(0x4F38)] public PlayerParamCyloop cyloop; } public enum SupportedPlane : sbyte { Flat = 0, Slope = 1, Wall = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamCommon { [FieldOffset(0x00)] public float movableMaxSlope; [FieldOffset(0x04)] public float activeLandingSlope; [FieldOffset(0x08)] public float activeLandingSlopeInBoost; [FieldOffset(0x0C)] public float landingMaxSlope; [FieldOffset(0x10)] public float slidingMaxSlope; [FieldOffset(0x14)] public float wallAngleMaxSlope; [FieldOffset(0x18)] public SupportedPlane onStand; [FieldOffset(0x19)] public SupportedPlane onRunInAir; [FieldOffset(0x1A)] public SupportedPlane onRun; [FieldOffset(0x1B)] public bool moveHolding; [FieldOffset(0x1C)] public bool wallSlideSlowInBoost; [FieldOffset(0x1D)] public bool attrWallOnGround; [FieldOffset(0x20)] public float priorityInputTime; [FieldOffset(0x24)] public int capacityRings; [FieldOffset(0x28)] public int capacityRingsLvMax; [FieldOffset(0x2C)] public float collectRingRange; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamSpeedData { [FieldOffset(0x00)] public float initial; [FieldOffset(0x04)] public float min; [FieldOffset(0x08)] public float max; [FieldOffset(0x0C)] public float minTurn; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamSpeedAcceleData { [FieldOffset(0x00)] public float force; [FieldOffset(0x04)] public float force2; [FieldOffset(0x08)] public float damperRange; [FieldOffset(0x0C)] public float jerkMin; [FieldOffset(0x10)] public float jerkMax; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamSpeedAcceleData2 { [FieldOffset(0x00)] public float force; [FieldOffset(0x04)] public float damperRange; [FieldOffset(0x08)] public float jerkMin; [FieldOffset(0x0C)] public float jerkMax; } [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct PlayerParamSpeed { [FieldOffset(0x00)] public PlayerParamSpeedData normal; [FieldOffset(0x10)] public PlayerParamSpeedData normal2; [FieldOffset(0x20)] public PlayerParamSpeedData boost; [FieldOffset(0x30)] public PlayerParamSpeedData boost2; [FieldOffset(0x40)] public PlayerParamSpeedData boostLvMax; [FieldOffset(0x50)] public PlayerParamSpeedData boostLvMax2; [FieldOffset(0x60)] public float maxSpeedOver; [FieldOffset(0x64)] public float opitonMaxSpeedLimitMin; [FieldOffset(0x68)] public float opitonMaxSpeedLimitMax; [FieldOffset(0x6C)] public float thresholdStopSpeed; [FieldOffset(0x70)] public float maxFallSpeed; [FieldOffset(0x74)] public PlayerParamSpeedAcceleData accele; [FieldOffset(0x88)] public PlayerParamSpeedAcceleData decele; [FieldOffset(0x9C)] public PlayerParamSpeedAcceleData2 deceleNeutralMin; [FieldOffset(0xAC)] public PlayerParamSpeedAcceleData2 deceleNeutralMax; [FieldOffset(0xBC)] public float acceleAuto; [FieldOffset(0xC0)] public float deceleAuto; [FieldOffset(0xC4)] public float turnDeceleAngleMin; [FieldOffset(0xC8)] public float turnDeceleAngleMax; [FieldOffset(0xCC)] public float maxGravityAccele; [FieldOffset(0xD0)] public float maxGravityDecele; [FieldOffset(0xD4)] public float deceleSquat; [FieldOffset(0xD8)] public float acceleSensitive; [FieldOffset(0xDC)] public float boostAnimSpeedInWater; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamRotation { [FieldOffset(0x00)] public float baseRotateForce; [FieldOffset(0x04)] public float baseRotateForce2; [FieldOffset(0x08)] public float baseRotateForceSpeed; [FieldOffset(0x0C)] public float minRotateForce; [FieldOffset(0x10)] public float maxRotateForce; [FieldOffset(0x14)] public bool angleRotateForceDecayEnabled; [FieldOffset(0x18)] public float frontRotateRatio; [FieldOffset(0x1C)] public float rotationForceDecaySpeed; [FieldOffset(0x20)] public float rotationForceDecayRate; [FieldOffset(0x24)] public float rotationForceDecayMax; [FieldOffset(0x28)] public float autorunRotateForce; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamRunning { [FieldOffset(0x00)] public float walkSpeed; [FieldOffset(0x04)] public float sneakingSpeed; [FieldOffset(0x08)] public float animSpeedSneak; [FieldOffset(0x0C)] public float animSpeedWalk; [FieldOffset(0x10)] public float animSpeedRun; [FieldOffset(0x14)] public float animSpeedBoost; [FieldOffset(0x18)] public float animLRBlendSampleTime; [FieldOffset(0x1C)] public float animLRBlendAngleMin; [FieldOffset(0x20)] public float animLRBlendAngleMax; [FieldOffset(0x24)] public float animLRBlendSpeed; [FieldOffset(0x28)] public float animLRBlendSpeedToCenter; [FieldOffset(0x2C)] public float minChangeWalkTime; [FieldOffset(0x30)] public float fallAnimationAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamBalanceData { [FieldOffset(0x00)] public float rotateSpeedMinFB; [FieldOffset(0x04)] public float rotateSpeedMaxFB; [FieldOffset(0x08)] public float rotateSpeedMinLR; [FieldOffset(0x0C)] public float rotateSpeedMaxLR; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamBalance { [FieldOffset(0x00)] public PlayerParamBalanceData standard; [FieldOffset(0x10)] public PlayerParamBalanceData loop; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBrake { [FieldOffset(0x00)] public float initialSpeedRatio; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float forceLand; [FieldOffset(0x0C)] public float forceAir; [FieldOffset(0x10)] public float endSpeed; [FieldOffset(0x14)] public float stopTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamTurn { [FieldOffset(0x00)] public float thresholdSpeed; [FieldOffset(0x04)] public float thresholdAngle; [FieldOffset(0x08)] public float turnAfterSpeed; [FieldOffset(0x0C)] public bool stopEdge; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamJump { [FieldOffset(0x00)] public float preActionTime; [FieldOffset(0x04)] public float longPressTime; [FieldOffset(0x08)] public float addForceTime; [FieldOffset(0x0C)] public float force; [FieldOffset(0x10)] public float addForce; [FieldOffset(0x14)] public float forceMin; [FieldOffset(0x18)] public float gravitySize; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamJumpSpeed { [FieldOffset(0x00)] public float acceleForce; [FieldOffset(0x04)] public float deceleForce; [FieldOffset(0x08)] public float deceleNeutralForce; [FieldOffset(0x0C)] public float deceleBackForce; [FieldOffset(0x10)] public float limitMin; [FieldOffset(0x14)] public float limitUpSpeed; [FieldOffset(0x18)] public float rotationForce; [FieldOffset(0x1C)] public float rotationForceDecaySpeed; [FieldOffset(0x20)] public float rotationForceDecayRate; [FieldOffset(0x24)] public float rotationForceDecayMax; [FieldOffset(0x28)] public float baseAirDragScaleMin; [FieldOffset(0x2C)] public float baseAirDragScaleMax; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDoubleJump { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float bounceSpeed; [FieldOffset(0x08)] public float limitSpeedMin; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamFall { [FieldOffset(0x00)] public float thresholdVertSpeed; [FieldOffset(0x04)] public float tolerateJumpTime; [FieldOffset(0x08)] public float fallEndDelayTime; [FieldOffset(0x0C)] public float fallEndFadeTime; [FieldOffset(0x10)] public float acceleForce; [FieldOffset(0x14)] public float deceleForce; [FieldOffset(0x18)] public float overSpeedDeceleForce; [FieldOffset(0x1C)] public float rotationForce; [FieldOffset(0x20)] public float rotationForceDecaySpeed; [FieldOffset(0x24)] public float rotationForceDecayRate; [FieldOffset(0x28)] public float rotationForceDecayMax; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageCommon { [FieldOffset(0x00)] public float invincibleTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamDamageNormal { [FieldOffset(0x00)] public float initialHorzSpeed; [FieldOffset(0x04)] public float initialVertSpeed; [FieldOffset(0x08)] public float deceleForce; [FieldOffset(0x0C)] public float transitFallTime; [FieldOffset(0x10)] public float gravityScale; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageTurnBack { [FieldOffset(0x00)] public float fixedTime; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamDamageBlowOff { [FieldOffset(0x00)] public float initialHorzSpeed; [FieldOffset(0x04)] public float initialVertSpeed; [FieldOffset(0x08)] public float deceleForceInAir; [FieldOffset(0x0C)] public float deceleForceOnGround; [FieldOffset(0x10)] public float gravityScale; [FieldOffset(0x14)] public float downTime; [FieldOffset(0x18)] public float transitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamDamageGuarded { [FieldOffset(0x00)] public float vertSpeed; [FieldOffset(0x04)] public float horzSpeed; [FieldOffset(0x08)] public float deceleForce; [FieldOffset(0x0C)] public float transitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamDamageRunning { [FieldOffset(0x00)] public float actionTime; [FieldOffset(0x04)] public float minSpeed; [FieldOffset(0x08)] public float lossSpeed; [FieldOffset(0x0C)] public float lossTime; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageQuake { [FieldOffset(0x00)] public float actionTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamDamageLava { [FieldOffset(0x00)] public Vector3 jumpVelocity; [FieldOffset(0x10)] public float gravitySize; [FieldOffset(0x14)] public float invincibleTime; [FieldOffset(0x18)] public float noActionTime; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerParamDamageMine { [FieldOffset(0x00)] public Vector3 jumpVelocity; [FieldOffset(0x10)] public float gravitySize; [FieldOffset(0x14)] public float invincibleTime; [FieldOffset(0x18)] public float noActionTime; [FieldOffset(0x1C)] public float gravitySizeForFall; [FieldOffset(0x20)] public float maxFallSpeed; [FieldOffset(0x28)] public UnmanagedString cameraShakeName; [FieldOffset(0x38)] public UnmanagedString vibrationName; } [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct PlayerParamDamage { [FieldOffset(0x00)] public PlayerParamDamageCommon common; [FieldOffset(0x04)] public PlayerParamDamageNormal normal; [FieldOffset(0x18)] public PlayerParamDamageTurnBack turnBack; [FieldOffset(0x1C)] public PlayerParamDamageBlowOff blowOff; [FieldOffset(0x38)] public PlayerParamDamageGuarded guarded; [FieldOffset(0x48)] public PlayerParamDamageGuarded guardedSS; [FieldOffset(0x58)] public PlayerParamDamageRunning running; [FieldOffset(0x68)] public PlayerParamDamageQuake quake; [FieldOffset(0x70)] public PlayerParamDamageLava lava; [FieldOffset(0x90)] public PlayerParamDamageMine mine; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDeadNormal { [FieldOffset(0x00)] public float invincibleTime; [FieldOffset(0x04)] public float initialHorzSpeed; [FieldOffset(0x08)] public float initialVertSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDead { [FieldOffset(0x00)] public PlayerParamDeadNormal normal; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamSliding { [FieldOffset(0x00)] public float minSpeed; [FieldOffset(0x04)] public float endSpeed; [FieldOffset(0x08)] public float deceleJerk; [FieldOffset(0x0C)] public float deceleJerkContinue; [FieldOffset(0x10)] public float deceleForceMax; [FieldOffset(0x14)] public float baseRotateForce; [FieldOffset(0x18)] public float baseRotateForceSpeed; [FieldOffset(0x1C)] public float maxRotateForce; [FieldOffset(0x20)] public float frontRotateRatio; [FieldOffset(0x24)] public float rotationForceAutoRun; [FieldOffset(0x28)] public float movableMaxSlope; [FieldOffset(0x2C)] public float gravitySize; [FieldOffset(0x30)] public float minContinueTime; [FieldOffset(0x34)] public float maxAutoRunTime; [FieldOffset(0x38)] public float endSpeedAutoRun; [FieldOffset(0x3C)] public float loopKickTransitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamStomping { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float initialAccele; [FieldOffset(0x08)] public float maxAccele; [FieldOffset(0x0C)] public float jerk; [FieldOffset(0x10)] public float maxFallSpeed; [FieldOffset(0x14)] public float angle; [FieldOffset(0x18)] public float landingCancelTime; [FieldOffset(0x1C)] public float boundStompingCollisionScale; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamGrind { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float maxBoostSpeed; [FieldOffset(0x08)] public float acceleForce; [FieldOffset(0x0C)] public float deceleForce; [FieldOffset(0x10)] public float limitSpeedMin; } [StructLayout(LayoutKind.Explicit, Size = 0x38)] public struct PlayerParamFallSlope { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float brakeAngle; [FieldOffset(0x0C)] public float highBrakeAngle; [FieldOffset(0x10)] public float brakeForce; [FieldOffset(0x14)] public float brakeForceHigh; [FieldOffset(0x18)] public float gravitySize; [FieldOffset(0x1C)] public float gravitySizeAir; [FieldOffset(0x20)] public float endSpeedFront; [FieldOffset(0x24)] public float endSpeedBack; [FieldOffset(0x28)] public float reverseFallTime; [FieldOffset(0x2C)] public float fallToSlipTime; [FieldOffset(0x30)] public float slipIdlingTime; [FieldOffset(0x34)] public float minSlipTime; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamFallFlip { [FieldOffset(0x00)] public float thresholdSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float flipAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct PlayerParamTumble { [FieldOffset(0x00)] public bool enabled; [FieldOffset(0x04)] public float sideSpinAngle; [FieldOffset(0x08)] public float initialVertSpeed; [FieldOffset(0x0C)] public float gravitySize; [FieldOffset(0x10)] public float gravitySize2; [FieldOffset(0x14)] public float deceleForceInAir; [FieldOffset(0x18)] public float minSpeedInAir; [FieldOffset(0x1C)] public float rotateEaseTimeLeftRight; [FieldOffset(0x20)] public float rotateEaseTimeFrontBack; [FieldOffset(0x24)] public float rotateSpeedMinLeftRight; [FieldOffset(0x28)] public float rotateSpeedMaxLeftRight; [FieldOffset(0x2C)] public float rotateSpeedMinFrontBack; [FieldOffset(0x30)] public float rotateSpeedMaxFrontBack; [FieldOffset(0x34)] public float angleLeftRightStagger; [FieldOffset(0x38)] public float angleLeftRightRoll; [FieldOffset(0x3C)] public float angleFrontBackRoll; [FieldOffset(0x40)] public float angleBigRoll; [FieldOffset(0x44)] public float inRunTime; [FieldOffset(0x48)] public float inAirTime; [FieldOffset(0x4C)] public float rollSpeedFront; [FieldOffset(0x50)] public float bigRollVelocityRatio; [FieldOffset(0x54)] public float dropDashHoldTime; [FieldOffset(0x58)] public float airBrakeVertSpeed; [FieldOffset(0x5C)] public float airBrakeForce; [FieldOffset(0x60)] public float airTrickHeight; [FieldOffset(0x64)] public float airTrickTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSpinAttack { [FieldOffset(0x00)] public float jumpForce; [FieldOffset(0x04)] public float jumpAddForce; [FieldOffset(0x08)] public float addTime; [FieldOffset(0x0C)] public float acceleForce; [FieldOffset(0x10)] public float deceleForce; [FieldOffset(0x14)] public float brakeForce; [FieldOffset(0x18)] public float limitSpeedMin; [FieldOffset(0x1C)] public float limitSpeedMax; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamHomingAttackData { [FieldOffset(0x00)] public float speed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamHomingBounceData { [FieldOffset(0x00)] public float bounceVertSpeed; [FieldOffset(0x04)] public float bounceHorzSpeed; [FieldOffset(0x08)] public float bounceAcceleForce; [FieldOffset(0x0C)] public float bounceDeceleForce; [FieldOffset(0x10)] public float bounceAngleWidth; [FieldOffset(0x14)] public float bounceTime; [FieldOffset(0x18)] public float attackDownTime; [FieldOffset(0x1C)] public float attackDownTimeForStomp; } [StructLayout(LayoutKind.Explicit, Size = 0xB0)] public struct PlayerParamHomingAttack { [FieldOffset(0x00)] public PlayerParamHomingAttackData sonic; [FieldOffset(0x04)] public PlayerParamHomingAttackData supersonic; [FieldOffset(0x08)] public PlayerParamHomingBounceData sonicBounce; [FieldOffset(0x28)] public PlayerParamHomingBounceData sonicBounceWeak; [FieldOffset(0x48)] public PlayerParamHomingBounceData sonicBounceStorm; [FieldOffset(0x68)] public PlayerParamHomingBounceData sonicBounceStormSwirl; [FieldOffset(0x88)] public PlayerParamHomingBounceData supersonicBounce; [FieldOffset(0xA8)] public float cameraEaseInTime; [FieldOffset(0xAC)] public float cameraEaseOutTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamHitEnemy { [FieldOffset(0x00)] public float bounceVertSpeed; [FieldOffset(0x04)] public float bounceHorzSpeed; [FieldOffset(0x08)] public float attackDownTime; [FieldOffset(0x0C)] public float enableHomingTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct SpeedParam { [FieldOffset(0x00)] public float maxVertSpeed; [FieldOffset(0x04)] public float acceleVertForce; [FieldOffset(0x08)] public float maxHorzSpeed; [FieldOffset(0x0C)] public float acceleHorzForce; } [StructLayout(LayoutKind.Explicit, Size = 0x5C)] public struct PlayerParamDiving { [FieldOffset(0x00)] public SpeedParam normal; [FieldOffset(0x10)] public SpeedParam fast; [FieldOffset(0x20)] public SpeedParam damaged; [FieldOffset(0x30)] public SpeedParam ringdash; [FieldOffset(0x40)] public float startHeight; [FieldOffset(0x44)] public float startSpeed; [FieldOffset(0x48)] public float deceleVertForce; [FieldOffset(0x4C)] public float deceleHorzForce; [FieldOffset(0x50)] public float deceleNeutralForce; [FieldOffset(0x54)] public float damageTime; [FieldOffset(0x58)] public float ringdashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamFan { [FieldOffset(0x00)] public float damperV; [FieldOffset(0x04)] public float damperH; [FieldOffset(0x08)] public float accelRate; [FieldOffset(0x0C)] public float moveForceFV; [FieldOffset(0x10)] public float moveForceSV; [FieldOffset(0x14)] public float jumpCheckSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBackflip { [FieldOffset(0x00)] public float jumpSpeed; [FieldOffset(0x04)] public float backSpeed; [FieldOffset(0x08)] public float downAccel; [FieldOffset(0x0C)] public float damperV; [FieldOffset(0x10)] public float damperH; [FieldOffset(0x14)] public float time; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSlowMove { [FieldOffset(0x00)] public float startSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float accel; [FieldOffset(0x0C)] public float brake; [FieldOffset(0x10)] public float damageSpeed; [FieldOffset(0x14)] public float damageBrake; [FieldOffset(0x18)] public float steeringSpeed; [FieldOffset(0x1C)] public float endSteeringSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSpin { [FieldOffset(0x00)] public float startSlopeAngle; [FieldOffset(0x04)] public float endSlopeAngle; [FieldOffset(0x08)] public float startSpeed; [FieldOffset(0x0C)] public float endSpeed; [FieldOffset(0x10)] public float stickAngle; [FieldOffset(0x14)] public float brake; [FieldOffset(0x18)] public float forceBrake; [FieldOffset(0x1C)] public float maxSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x88)] public struct PlayerParamWallMove { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float walkSpeed; [FieldOffset(0x08)] public float walkSpeedMax; [FieldOffset(0x0C)] public float runSpeed; [FieldOffset(0x10)] public float runSpeedMax; [FieldOffset(0x14)] public float walkSpeedOnMesh; [FieldOffset(0x18)] public float walkSpeedOnMeshMax; [FieldOffset(0x1C)] public float runSpeedOnMesh; [FieldOffset(0x20)] public float runSpeedOnMeshMax; [FieldOffset(0x24)] public float minAccessSpeed; [FieldOffset(0x28)] public float stickSpeed; [FieldOffset(0x2C)] public float gravity; [FieldOffset(0x30)] public float accel; [FieldOffset(0x34)] public float brake; [FieldOffset(0x38)] public float stopBrake; [FieldOffset(0x3C)] public float fallSpeed; [FieldOffset(0x40)] public float steeringSpeed1; [FieldOffset(0x44)] public float steeringSpeed2; [FieldOffset(0x48)] public float startSteeringSpeed; [FieldOffset(0x4C)] public float endSteeringSpeed; [FieldOffset(0x50)] public float startTime; [FieldOffset(0x54)] public float useEnergySpeedBase; [FieldOffset(0x58)] public float useEnergySpeedBaseOnMesh; [FieldOffset(0x5C)] public float useEnergySpeedVal; [FieldOffset(0x60)] public float useEnergySpeedValOnMesh; [FieldOffset(0x64)] public float useEnergyAngle; [FieldOffset(0x68)] public float useEnergyAngleOnMesh; [FieldOffset(0x6C)] public float brakeStartEnergy; [FieldOffset(0x70)] public float brakeStartEnergyOnMesh; [FieldOffset(0x74)] public float homingSearchDistanceNear; [FieldOffset(0x78)] public float homingSearchDistanceFar; [FieldOffset(0x7C)] public float wallBumpHeightUpper; [FieldOffset(0x80)] public float wallBumpHeightUnder; [FieldOffset(0x84)] public float recoveryCheckTime; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerParamWallJump { [FieldOffset(0x00)] public float gravitySize; [FieldOffset(0x04)] public float minTime; [FieldOffset(0x08)] public float maxTime; [FieldOffset(0x0C)] public float stopTime; [FieldOffset(0x10)] public float maxDownSpeed; [FieldOffset(0x14)] public float fallGroundDistance; [FieldOffset(0x18)] public float frontForce; [FieldOffset(0x1C)] public float upForce; [FieldOffset(0x20)] public float impulseTime; } [StructLayout(LayoutKind.Explicit, Size = 0x54)] public struct PlayerParamClimbing { [FieldOffset(0x00)] public float stepSpeedFront; [FieldOffset(0x04)] public float stepSpeedFrontDash; [FieldOffset(0x08)] public float stepSpeedSide; [FieldOffset(0x0C)] public float stepSpeedSideDash; [FieldOffset(0x10)] public float stepSpeedBack; [FieldOffset(0x14)] public float stepDashRate; [FieldOffset(0x18)] public float maxAnimSpeed; [FieldOffset(0x1C)] public float exhaustAngle; [FieldOffset(0x20)] public float exhaustAngleOnMesh; [FieldOffset(0x24)] public float exhaustBase; [FieldOffset(0x28)] public float exhaustBaseOnMesh; [FieldOffset(0x2C)] public float exhaustRate; [FieldOffset(0x30)] public float exhaustRateOnMesh; [FieldOffset(0x34)] public float useGrabGaugeSpeed; [FieldOffset(0x38)] public float useGrabGaugeSpeedOnMesh; [FieldOffset(0x3C)] public float useGrabGaugeTurbo; [FieldOffset(0x40)] public float useGrabGaugeTurboOnMesh; [FieldOffset(0x44)] public float homingSearchDistanceNear; [FieldOffset(0x48)] public float homingSearchDistanceFar; [FieldOffset(0x4C)] public float resetAngle; [FieldOffset(0x50)] public float recoveryCheckTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamSlideDown { [FieldOffset(0x00)] public float time; [FieldOffset(0x04)] public float speed; [FieldOffset(0x08)] public float speedOnMesh; [FieldOffset(0x0C)] public float accel; [FieldOffset(0x10)] public float brake; [FieldOffset(0x14)] public float brakeOnMesh; } [StructLayout(LayoutKind.Explicit, Size = 0x3C)] public struct PlayerParamBoost { [FieldOffset(0x00)] public float consumptionRate; [FieldOffset(0x04)] public float consumptionRateSS; [FieldOffset(0x08)] public float recoveryRate; [FieldOffset(0x0C)] public float recoveryRateSS; [FieldOffset(0x10)] public float reigniteRatio; [FieldOffset(0x14)] public float recoveryByRing; [FieldOffset(0x18)] public float recoveryByAttack; [FieldOffset(0x1C)] public unsafe fixed float blurPowers[3]; [FieldOffset(0x28)] public float blurEaseInTime; [FieldOffset(0x2C)] public float blurEaseOutTime; [FieldOffset(0x30)] public float endSpeed; [FieldOffset(0x34)] public float powerBoostCoolTime; [FieldOffset(0x38)] public float infinityBoostTime; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamAirBoost { [FieldOffset(0x00)] public float startHSpeed; [FieldOffset(0x04)] public float startHSpeedMax; [FieldOffset(0x08)] public float startVSpeed; [FieldOffset(0x0C)] public float minHSpeed; [FieldOffset(0x10)] public float minHSpeedMax; [FieldOffset(0x14)] public float brakeTime; [FieldOffset(0x18)] public float minKeepTime; [FieldOffset(0x1C)] public float maxKeepTime; [FieldOffset(0x20)] public float maxTime; [FieldOffset(0x24)] public float gravityRate; [FieldOffset(0x28)] public float steeringSpeed; [FieldOffset(0x2C)] public float additionalTransitTime; [FieldOffset(0x30)] public float supersonicTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAutorun { [FieldOffset(0x00)] public float initialSideSpeed; [FieldOffset(0x04)] public float acceleSideForce; [FieldOffset(0x08)] public float deceleSideForce; [FieldOffset(0x0C)] public float maxSideSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSideStep { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float brakeForce; [FieldOffset(0x08)] public float motionSpeedRatio; [FieldOffset(0x0C)] public float stepSpeed; [FieldOffset(0x10)] public float maxStepDistance; [FieldOffset(0x14)] public float minStepDistance; [FieldOffset(0x18)] public float maxStepSpeed; [FieldOffset(0x1C)] public float minStepSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSideStep2 { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float brakeForce; [FieldOffset(0x08)] public float motionSpeedRatio; [FieldOffset(0x0C)] public float stepSpeed; [FieldOffset(0x10)] public float maxStepDistance; [FieldOffset(0x14)] public float minStepDistance; [FieldOffset(0x18)] public float maxStepSpeed; [FieldOffset(0x1C)] public float minStepSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerParamQuickStep { [FieldOffset(0x00)] public float needSpeed; [FieldOffset(0x04)] public float acceleForce; [FieldOffset(0x08)] public float acceleSideForce; [FieldOffset(0x0C)] public float stepInitialSpeed; [FieldOffset(0x10)] public float avoidForce; [FieldOffset(0x14)] public float justBoostForce; [FieldOffset(0x18)] public float justBoostMax; [FieldOffset(0x1C)] public float justBoostTime; [FieldOffset(0x20)] public float justBoostBrake; } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct PlayerParamParry { [FieldOffset(0x00)] public float minRecieveTime; [FieldOffset(0x04)] public unsafe fixed float maxRecieveTimes[4]; [FieldOffset(0x14)] public unsafe fixed float justRecieveTimes[4]; [FieldOffset(0x24)] public float frozenTime; [FieldOffset(0x28)] public float justFrozenTime; [FieldOffset(0x2C)] public float justEffectEasein; [FieldOffset(0x30)] public float justEffectEaseout; [FieldOffset(0x34)] public float justEffectTime; [FieldOffset(0x38)] public float justEffectEasein2; [FieldOffset(0x3C)] public float justEffectEaseout2; [FieldOffset(0x40)] public float justEffectTime2; [FieldOffset(0x44)] public float justEffectEasein3; [FieldOffset(0x48)] public float justEffectEaseout3; [FieldOffset(0x4C)] public float justEffectTime3; [FieldOffset(0x50)] public UnmanagedString cameraName; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAvoidData { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float damper; [FieldOffset(0x08)] public float parryTime; [FieldOffset(0x0C)] public float invincibleTime; } [StructLayout(LayoutKind.Explicit, Size = 0x94)] public struct PlayerParamAvoid { [FieldOffset(0x00)] public float time; [FieldOffset(0x04)] public float fixedTime; [FieldOffset(0x08)] public float reentryInputPriorityTime; [FieldOffset(0x0C)] public float reentryTime; [FieldOffset(0x10)] public float frontAngle; [FieldOffset(0x14)] public float backAngle; [FieldOffset(0x18)] public float addFallSpeed; [FieldOffset(0x1C)] public unsafe fixed byte /* PlayerParamAvoidData[7] */ _data[112]; public unsafe PlayerParamAvoidData* data { get { fixed (byte* p_data = _data) return (PlayerParamAvoidData*)p_data; } } [FieldOffset(0x8C)] public float baseDistance; [FieldOffset(0x90)] public float limitAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x8F0)] public struct ModePackage { [FieldOffset(0x00)] public PlayerParamCommon common; [FieldOffset(0x30)] public PlayerParamSpeed speed; [FieldOffset(0x110)] public PlayerParamRotation rotation; [FieldOffset(0x13C)] public PlayerParamRunning running; [FieldOffset(0x170)] public PlayerParamBalance balance; [FieldOffset(0x190)] public PlayerParamBrake brake; [FieldOffset(0x1A8)] public PlayerParamTurn turn; [FieldOffset(0x1B8)] public PlayerParamJump jump; [FieldOffset(0x1D4)] public PlayerParamJumpSpeed jumpSpeed; [FieldOffset(0x204)] public PlayerParamDoubleJump doubleJump; [FieldOffset(0x210)] public PlayerParamFall fall; [FieldOffset(0x240)] public PlayerParamDamage damage; [FieldOffset(0x320)] public PlayerParamDead dead; [FieldOffset(0x32C)] public PlayerParamSliding sliding; [FieldOffset(0x36C)] public PlayerParamStomping stomping; [FieldOffset(0x38C)] public PlayerParamGrind grind; [FieldOffset(0x3A0)] public PlayerParamFallSlope fallSlope; [FieldOffset(0x3D8)] public PlayerParamFallFlip fallFlip; [FieldOffset(0x3E4)] public PlayerParamTumble tumble; [FieldOffset(0x44C)] public PlayerParamSpinAttack spinAttack; [FieldOffset(0x46C)] public PlayerParamHomingAttack homingAttack; [FieldOffset(0x51C)] public PlayerParamHitEnemy hitEnemy; [FieldOffset(0x52C)] public PlayerParamDiving diving; [FieldOffset(0x588)] public PlayerParamFan fan; [FieldOffset(0x5A0)] public PlayerParamBackflip backflip; [FieldOffset(0x5B8)] public PlayerParamSlowMove slowmove; [FieldOffset(0x5D8)] public PlayerParamSpin spin; [FieldOffset(0x5F8)] public PlayerParamWallMove wallmove; [FieldOffset(0x680)] public PlayerParamWallJump walljump; [FieldOffset(0x6A4)] public PlayerParamClimbing climbing; [FieldOffset(0x6F8)] public PlayerParamSlideDown slidedown; [FieldOffset(0x710)] public PlayerParamBoost boost; [FieldOffset(0x74C)] public PlayerParamAirBoost airboost; [FieldOffset(0x780)] public PlayerParamAutorun autorun; [FieldOffset(0x790)] public PlayerParamSideStep sidestep; [FieldOffset(0x7B0)] public PlayerParamSideStep2 sidestep2; [FieldOffset(0x7D0)] public PlayerParamQuickStep quickstep; [FieldOffset(0x7F8)] public PlayerParamParry parry; [FieldOffset(0x858)] public PlayerParamAvoid avoid; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct KnucklesParamGlidingCamera { [FieldOffset(0x00)] public float azimuthSensitivity; [FieldOffset(0x04)] public float elevationOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x5C)] public struct KnucklesParamGliding { [FieldOffset(0x00)] public float minSpeed; [FieldOffset(0x04)] public float minSpeedRingMax; [FieldOffset(0x08)] public float moveWaitTime; [FieldOffset(0x0C)] public float minActionTime; [FieldOffset(0x10)] public float fallSpeed; [FieldOffset(0x14)] public float fallAccel; [FieldOffset(0x18)] public float maxSteerSpeed; [FieldOffset(0x1C)] public float rollSpeed; [FieldOffset(0x20)] public float neutralRollSpeed; [FieldOffset(0x24)] public float rollSpeedRingMax; [FieldOffset(0x28)] public float neutralRollSpeedRingMax; [FieldOffset(0x2C)] public float yawSpeed; [FieldOffset(0x30)] public float yawSpeedRingMax; [FieldOffset(0x34)] public float maxRollAngle; [FieldOffset(0x38)] public float rollAngleRatioMin; [FieldOffset(0x3C)] public float rollAngleRatioMax; [FieldOffset(0x40)] public float rollAngleRatioMinRingMax; [FieldOffset(0x44)] public float rollAngleRatioMaxRingMax; [FieldOffset(0x48)] public float height; [FieldOffset(0x4C)] public float startHeight; [FieldOffset(0x50)] public KnucklesParamGlidingCamera camera; [FieldOffset(0x58)] public float practiceTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct KnucklesParamCyKnuckle { [FieldOffset(0x00)] public float findRadius; [FieldOffset(0x04)] public uint numNotifies; [FieldOffset(0x08)] public float effectTime; [FieldOffset(0x0C)] public float effectTimeWall; [FieldOffset(0x10)] public float rotateCycleTime; [FieldOffset(0x14)] public float activeRadius; [FieldOffset(0x18)] public float findDistanceStomp; [FieldOffset(0x1C)] public float findRadiusStomp; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct KnucklesParamCyKnuckleDig { [FieldOffset(0x00)] public float diveScale; [FieldOffset(0x04)] public float speed; [FieldOffset(0x08)] public float stompingAttackScale; [FieldOffset(0x0C)] public bool alsoStomping; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct KnucklesParamCyKnuckleWarp { [FieldOffset(0x00)] public float appearWaitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct KnucklesParamCyKnucklePopupItem { [FieldOffset(0x00)] public float appearWaitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x6C)] public struct KnucklesParamCyKnuckleAppearGimmick { [FieldOffset(0x00)] public float appearWaitTime; [FieldOffset(0x04)] public CyloopDropItemParameter dropItem; } [StructLayout(LayoutKind.Explicit, Size = 0x120)] public struct KnucklesParamMaximumHeatKnuckle { [FieldOffset(0x00)] public unsafe fixed float lockonLevelUpSpanTime[4]; [FieldOffset(0x10)] public unsafe fixed float damageTime[4]; [FieldOffset(0x20)] public float speed; [FieldOffset(0x24)] public float chargeTime; [FieldOffset(0x28)] public float chargeTime2; [FieldOffset(0x2C)] public float preDamageTime; [FieldOffset(0x30)] public float postDamageTime; [FieldOffset(0x34)] public float slowRate; [FieldOffset(0x40)] public PlayerParamAttackCollider hit; [FieldOffset(0x70)] public PlayerParamAttackCollider hit2; [FieldOffset(0xA0)] public Vector3 hitVisualOffset; [FieldOffset(0xB0)] public Vector3 hitEffectOffset; [FieldOffset(0xC0)] public float followSpeed; [FieldOffset(0xC4)] public float followTime; [FieldOffset(0xC8)] public UnmanagedString cameraNameMove; [FieldOffset(0xD8)] public UnmanagedString cameraNameHit; [FieldOffset(0xE8)] public bool startMoveCameraFromCharge; [FieldOffset(0xEC)] public float enabledCameraHeight; [FieldOffset(0xF0)] public UnmanagedString cameraShakeName; [FieldOffset(0x100)] public UnmanagedString vibrationName; [FieldOffset(0x110)] public float shakeEndTime; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct KnucklesParamDrillBoost { [FieldOffset(0x00)] public float prepareTime; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamSpinBoostSpeed { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public PlayerParamSpeedAcceleData accele; [FieldOffset(0x1C)] public PlayerParamSpeedAcceleData decele; [FieldOffset(0x30)] public float baseRotateForce; [FieldOffset(0x34)] public float minTurnSpeed; [FieldOffset(0x38)] public float turnDeceleAngleMin; [FieldOffset(0x3C)] public float turnDeceleAngleMax; } public enum AirAccelMode : sbyte { Alawys = 0, AirAccelMode_None = 1, Speed = 2 } [StructLayout(LayoutKind.Explicit, Size = 0xF8)] public struct PlayerParamSpinBoost { [FieldOffset(0x00)] public float forceRunTime; [FieldOffset(0x04)] public float initialRunTime; [FieldOffset(0x08)] public PlayerParamSpinBoostSpeed speedBall; [FieldOffset(0x48)] public PlayerParamSpinBoostSpeed speedBoost; [FieldOffset(0x88)] public PlayerParamSpeedAcceleData2 deceleNeutralMin; [FieldOffset(0x98)] public PlayerParamSpeedAcceleData2 deceleNeutralMax; [FieldOffset(0xA8)] public float gravitySize; [FieldOffset(0xAC)] public float gravityBeginTime; [FieldOffset(0xB0)] public float gravityMaxTime; [FieldOffset(0xB4)] public float gravitySizeMinInAir; [FieldOffset(0xB8)] public float gravitySizeMaxInAir; [FieldOffset(0xBC)] public float maxGravityAccele; [FieldOffset(0xC0)] public float maxGravityDecele; [FieldOffset(0xC4)] public float inAirTime; [FieldOffset(0xC8)] public float spinBoostEndSpeed; [FieldOffset(0xCC)] public float jumpOutAngle; [FieldOffset(0xD0)] public float jumpOutSpeed; [FieldOffset(0xD4)] public bool humpJumpOut; [FieldOffset(0xD5)] public AirAccelMode airAccelMode; [FieldOffset(0xD8)] public float airAccelVertSpeedThreshold; [FieldOffset(0xDC)] public float chargeRotateForce; [FieldOffset(0xE0)] public float chargeRotateForceMinAngle; [FieldOffset(0xE4)] public float chargeRotateForceMaxAngle; [FieldOffset(0xE8)] public UnmanagedString cameraShakeName; } [StructLayout(LayoutKind.Explicit, Size = 0xC10)] public struct ModePackageKnuckles { [FieldOffset(0)] public ModePackage modePackage; [FieldOffset(0x8F0)] public KnucklesParamGliding gliding; [FieldOffset(0x94C)] public KnucklesParamCyKnuckle cyknuckle; [FieldOffset(0x96C)] public KnucklesParamCyKnuckleDig cyknuckleDig; [FieldOffset(0x97C)] public KnucklesParamCyKnuckleWarp cyknuckleWarp; [FieldOffset(0x980)] public KnucklesParamCyKnucklePopupItem cyknucklePopupItem; [FieldOffset(0x984)] public KnucklesParamCyKnuckleAppearGimmick cyknuckleAppearGimmick; [FieldOffset(0x9F0)] public KnucklesParamMaximumHeatKnuckle maximumHeatKnuckle; [FieldOffset(0xB10)] public KnucklesParamDrillBoost drillBoost; [FieldOffset(0xB18)] public PlayerParamSpinBoost spinBoost; } [StructLayout(LayoutKind.Explicit, Size = 0x1A8)] public struct WaterModePackage { [FieldOffset(0x00)] public PlayerParamSpeed speed; [FieldOffset(0xE0)] public PlayerParamJump jump; [FieldOffset(0xFC)] public PlayerParamJumpSpeed jumpSpeed; [FieldOffset(0x12C)] public PlayerParamDoubleJump doubleJump; [FieldOffset(0x138)] public PlayerParamBoost boost; [FieldOffset(0x174)] public PlayerParamAirBoost airboost; } [StructLayout(LayoutKind.Explicit, Size = 0x7D70)] public struct Root { [FieldOffset(0x00)] public CommonPackageKnuckles common; [FieldOffset(0x63A0)] public ModePackageKnuckles forwardView; [FieldOffset(0x6FB0)] public WaterModePackage water; [FieldOffset(0x7160)] public ModePackageKnuckles cyberspaceSV; } } Library "NeedleFxSceneData" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; public enum DOFRenderTargetSize : int { DOF_RTSIZE_FULL_SCALE = 0, DOF_RTSIZE_HALF_SCALE = 1, DOF_RTSIZE_QUARTER_SCALE = 2, DOF_RTSIZE_COUNT = 3, DOF_RTSIZE_INVALID = 3 } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct FxRenderTargetSetting { [FieldOffset(0x00)] public DOFRenderTargetSize dofRenderTargetScale; [FieldOffset(0x04)] public int shadowMapWidth; [FieldOffset(0x08)] public int shadowMapHeight; } public enum AntiAliasingType : sbyte { AATYPE_NONE = 0, AATYPE_TAA = 1, AATYPE_FXAA = 2, AATYPE_SMAA = 3, AATYPE_LAST = 4 } public enum UpscaleType : sbyte { USTYPE_LINEAR = 0, USTYPE_FSR_FAST = 1, USTYPE_FSR_EASU = 2, USTYPE_FSR_RCAS = 3 } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct FxAntiAliasing { [FieldOffset(0x00)] public AntiAliasingType aaType; [FieldOffset(0x01)] public UpscaleType usType; [FieldOffset(0x04)] public float fsrSharpness; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct StageCommonAtmosphereParameter { [FieldOffset(0x00)] public float illuminanceScale; } [StructLayout(LayoutKind.Explicit, Size = 0x84)] public struct FxLODParameter { [FieldOffset(0x00)] public bool enableDebugDrawLayerRange; [FieldOffset(0x04)] public unsafe fixed float layerRange[32]; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct FxDetailParameter { [FieldOffset(0x00)] public float detailDistance; [FieldOffset(0x04)] public float detailFadeRange; } public enum Mode : sbyte { DISABLE = 0, ENABLE = 1, FIXED_RESOLUTION = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct FxDynamicResolutionParameter { [FieldOffset(0x00)] public Mode mode; [FieldOffset(0x04)] public float fixedResolutionRatio; [FieldOffset(0x08)] public float minResolutionRatio; [FieldOffset(0x0C)] public float minTargetTimeDifference; [FieldOffset(0x10)] public float maxTargetTimeDifference; [FieldOffset(0x14)] public float increaseRate; [FieldOffset(0x18)] public float decreaseRate; [FieldOffset(0x1C)] public float increaseMaxScaleDelta; [FieldOffset(0x20)] public float decreaseMaxScaleDelta; [FieldOffset(0x24)] public bool debugSineFluctuation; } [StructLayout(LayoutKind.Explicit, Size = 0x02)] public struct HourMinuteData { [FieldOffset(0x00)] public byte hour; [FieldOffset(0x01)] public byte minute; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct TimeIntervalData { [FieldOffset(0x00)] public HourMinuteData beginTime; [FieldOffset(0x02)] public HourMinuteData endTime; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct ProgressTimePairData { [FieldOffset(0)] public TimeIntervalData timeIntervalData; [FieldOffset(0x04)] public float hourlyTime; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct StageCommonTimeProgressParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float solarRadiusScale; [FieldOffset(0x08)] public float azimuthAngle; [FieldOffset(0x0C)] public float latitude; [FieldOffset(0x10)] public float longitude; [FieldOffset(0x14)] public int month; [FieldOffset(0x18)] public int day; [FieldOffset(0x1C)] public float time; [FieldOffset(0x20)] public float hourlyTime; [FieldOffset(0x24)] public unsafe fixed byte /* ProgressTimePairData[8] */ _overrideSpeeds[64]; public unsafe ProgressTimePairData* overrideSpeeds { get { fixed (byte* p_overrideSpeeds = _overrideSpeeds) return (ProgressTimePairData*)p_overrideSpeeds; } } [FieldOffset(0x64)] public TimeIntervalData night; } [StructLayout(LayoutKind.Explicit, Size = 0x01)] public struct StageCommonWeatherProgressParameter { [FieldOffset(0x00)] public bool enable; } [StructLayout(LayoutKind.Explicit, Size = 0x01)] public struct FxTerrainParameter { [FieldOffset(0x00)] public bool enableDrawGrid; } [StructLayout(LayoutKind.Explicit, Size = 0x02)] public struct FxModelParameter { [FieldOffset(0x00)] public bool zprepass; [FieldOffset(0x01)] public bool ditherAsBlueNoize; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct StageCommonDecalModelParameter { [FieldOffset(0x00)] public float cullingRange; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PerformanceSetting { [FieldOffset(0x00)] public float smallCullingThreshold; } [StructLayout(LayoutKind.Explicit, Size = 0x140)] public struct NeedleFxSceneConfig { [FieldOffset(0x00)] public FxRenderTargetSetting rendertarget; [FieldOffset(0x0C)] public FxAntiAliasing antialiasing; [FieldOffset(0x14)] public StageCommonAtmosphereParameter atmosphere; [FieldOffset(0x18)] public FxLODParameter lod; [FieldOffset(0x9C)] public FxDetailParameter detail; [FieldOffset(0xA4)] public FxDynamicResolutionParameter dynamicResolution; [FieldOffset(0xCC)] public StageCommonTimeProgressParameter timeProgress; [FieldOffset(0x134)] public StageCommonWeatherProgressParameter weatherProgress; [FieldOffset(0x135)] public FxTerrainParameter terrain; [FieldOffset(0x136)] public FxModelParameter modelParam; [FieldOffset(0x138)] public StageCommonDecalModelParameter decalModelParam; [FieldOffset(0x13C)] public PerformanceSetting performance; } public enum DebugViewType : sbyte { DEBUG_VIEW_DEFAULT = 0, DEBUG_VIEW_DIR_DIFFUSE = 1, DEBUG_VIEW_DIR_SPECULAR = 2, DEBUG_VIEW_AMB_DIFFUSE = 3, DEBUG_VIEW_AMB_SPECULAR = 4, DEBUG_VIEW_ONLY_IBL = 5, DEBUG_VIEW_ONLY_IBL_SURF_NORMAL = 6, DEBUG_VIEW_SHADOW = 7, DEBUG_VIEW_WHITE_ALBEDO = 8, DEBUG_VIEW_WHITE_ALBEDO_NO_AO = 9, DEBUG_VIEW_USER0 = 10, DEBUG_VIEW_USER1 = 11, DEBUG_VIEW_USER2 = 12, DEBUG_VIEW_USER3 = 13, DEBUG_VIEW_ALBEDO = 14, DEBUG_VIEW_ALBEDO_CHECK_OUTLIER = 15, DEBUG_VIEW_OPACITY = 16, DEBUG_VIEW_NORMAL = 17, DEBUG_VIEW_ROUGHNESS = 18, DEBUG_VIEW_AMBIENT = 19, DEBUG_VIEW_CAVITY = 20, DEBUG_VIEW_REFLECTANCE = 21, DEBUG_VIEW_METALLIC = 22, DEBUG_VIEW_LOCAL_LIGHT = 23, DEBUG_VIEW_SCATTERING_FEX = 24, DEBUG_VIEW_SCATTERING_LIN = 25, DEBUG_VIEW_SSAO = 26, DEBUG_VIEW_RLR = 27, DEBUG_VIEW_IBL_DIFFUSE = 28, DEBUG_VIEW_IBL_SPECULAR = 29, DEBUG_VIEW_ENV_BRDF = 30, DEBUG_VIEW_WORLD_POSITION = 31, DEBUG_VIEW_SHADING_MODEL_ID = 32, DEBUG_VIEW_IBL_CAPTURE = 33, DEBUG_VIEW_IBL_SKY_TERRAIN = 34, DEBUG_VIEW_WRITE_DEPTH_TO_ALPHA = 35, DEBUG_VIEW_SMOOTHNESS = 36, DEBUG_VIEW_OCCLUSION_CAPSULE = 37, DEBUG_VIEW_PROBE = 38, DEBUG_VIEW_COUNT = 39, DEBUG_VIEW_INVALID = 39 } public enum Type : sbyte { NONE = 0, SHADOW_LIGHT = 1, SHADOW_AND_DISTANT_LIGHT = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct GlobalLightAngleLimit { [FieldOffset(0x00)] public Type type; [FieldOffset(0x04)] public float minLightElevationAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct GlobalLightParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public GlobalLightAngleLimit limit; } public enum LocalLightCullingType : sbyte { LOCAL_LIGHT_CULLING_TYPE_NONE = 0, LOCAL_LIGHT_CULLING_TYPE_CPU_TILE = 1, LOCAL_LIGHT_CULLING_TYPE_GPU_TILE = 2, LOCAL_LIGHT_CULLING_TYPE_GPU_CLUSTER = 3, LOCAL_LIGHT_CULLING_TYPE_COUNT = 4, LOCAL_LIGHT_CULLING_TYPE_DEFAULT = 0 } public enum TextureViewType : sbyte { TEXTURE_VIEW_NONE = 0, TEXTURE_VIEW_DEPTH = 1, TEXTURE_VIEW_LUMINANCE = 2, TEXTURE_VIEW_DOF_BOKEH = 3, TEXTURE_VIEW_DOF_BOKEH_NEAR = 4, TEXTURE_VIEW_SSAO_SOURCE = 5, TEXTURE_VIEW_DOWNSAMPLE = 6, TEXTURE_VIEW_COUNT = 7 } public enum AmbientSpecularType : sbyte { AMBIENT_SPECULAR_NONE = 0, AMBIENT_SPECULAR_SG = 1, AMBIENT_SPECULAR_IBL = 2, AMBIENT_SPECULAR_BLEND = 3 } public enum ChannelMode : sbyte { CHANNELMODE_RGB = 0, CHANNELMODE_RRR = 1, CHANNELMODE_GGG = 2, CHANNELMODE_BBB = 3, CHANNELMODE_AAA = 4, CHANNELMODE_RG = 5, CHANNELMODE_BA = 6 } public enum DebugScreenType : sbyte { DEBUG_SCREEN_GBUFFER0 = 0, DEBUG_SCREEN_GBUFFER1 = 1, DEBUG_SCREEN_GBUFFER2 = 2, DEBUG_SCREEN_GBUFFER3 = 3, DEBUG_SCREEN_DEPTHBUFFER = 4, DEBUG_SCREEN_CSM0 = 5, DEBUG_SCREEN_CSM1 = 6, DEBUG_SCREEN_CSM2 = 7, DEBUG_SCREEN_CSM3 = 8, DEBUG_SCREEN_HDR = 9, DEBUG_SCREEN_BLOOM = 10, DEBUG_SCREEN_RLR = 11, DEBUG_SCREEN_GODRAY = 12, DEBUG_SCREEN_SSAO = 13, DEBUG_SCREEN_CSM_CACHE0 = 14, DEBUG_SCREEN_CSM_CACHE1 = 15, DEBUG_SCREEN_CSM_CACHE2 = 16, DEBUG_SCREEN_CSM_CACHE3 = 17, DEBUG_SCREEN_CSM_CACHE4 = 18, DEBUG_SCREEN_CSM_CACHE5 = 19, DEBUG_SCREEN_CUSTOM0 = 20, DEBUG_SCREEN_CUSTOM1 = 21, DEBUG_SCREEN_CUSTOM2 = 22, DEBUG_SCREEN_CUSTOM3 = 23 } public enum ErrorCheckType : sbyte { ERROR_CHECK_NONE = 0, ERROR_CHECK_NAN = 1, ERROR_CHECK_ALBEDO = 2, ERROR_CHECK_NORMAL = 3 } public enum VisualizeMode : sbyte { DEFAULT = 0, HEATMAP_TYPE0 = 1, HEATMAP_TYPE1 = 2, HEATMAP_TYPE2 = 3, VECTOR2D_TYPE0 = 4, VECTOR2D_TYPE1 = 5, VECTOR2D_TYPE2 = 6 } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct DebugScreenOption { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool fullScreen; [FieldOffset(0x02)] public ChannelMode channelMode; [FieldOffset(0x04)] public float min; [FieldOffset(0x08)] public float max; [FieldOffset(0x0C)] public int renderTargetType; [FieldOffset(0x10)] public int depthTargetType; [FieldOffset(0x14)] public DebugScreenType screenType; [FieldOffset(0x15)] public ErrorCheckType errorCheck; [FieldOffset(0x16)] public VisualizeMode visualizeMode; } public enum DebugScreenView : sbyte { DEBUG_SCREEN_VIEW_DEFAULT = 0, DEBUG_SCREEN_VIEW_ALL_ENABLE = 1, DEBUG_SCREEN_VIEW_ALL_DISABLE = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct GlobalUserParamOption { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x10)] public Vector4 value; } [StructLayout(LayoutKind.Explicit, Size = 0x250)] public struct FxRenderOption { [FieldOffset(0x00)] public DebugViewType debugViewType; [FieldOffset(0x01)] public bool clearRenderTarget; [FieldOffset(0x02)] public bool enableDrawCubeProbe; [FieldOffset(0x04)] public GlobalLightParameter globalLight; [FieldOffset(0x10)] public bool enablePointLight; [FieldOffset(0x11)] public bool enableEffectDeformation; [FieldOffset(0x12)] public bool enablePreMergeIBL; [FieldOffset(0x13)] public bool enableLitePostEffect; [FieldOffset(0x14)] public LocalLightCullingType localLightCullingType; [FieldOffset(0x18)] public float localLightScale; [FieldOffset(0x1C)] public float shadowIBLAttenuation; [FieldOffset(0x20)] public int maxCubeProbe; [FieldOffset(0x24)] public bool debugEnableDrawLocalLight; [FieldOffset(0x25)] public TextureViewType debugTextureViewType; [FieldOffset(0x26)] public bool debugEnableOutputTextureView; [FieldOffset(0x28)] public int debugScreenshotResolutionHeight; [FieldOffset(0x2C)] public float debugScreenshotDepthNear; [FieldOffset(0x30)] public float debugScreenshotDepthFar; [FieldOffset(0x34)] public AmbientSpecularType debugAmbientSpecularType; [FieldOffset(0x35)] public bool debugEnableSGGIVer2nd; [FieldOffset(0x36)] public bool debugEnableAOGI; [FieldOffset(0x38)] public unsafe fixed byte /* DebugScreenOption[16] */ _debugScreen[384]; public unsafe DebugScreenOption* debugScreen { get { fixed (byte* p_debugScreen = _debugScreen) return (DebugScreenOption*)p_debugScreen; } } [FieldOffset(0x1B8)] public DebugScreenView debugScreenView; [FieldOffset(0x1B9)] public bool enableMSAA; [FieldOffset(0x1BA)] public bool debugEnableDrawFrustumCullFrustum; [FieldOffset(0x1BB)] public bool debugEnableFixFrustumCullFrustum; [FieldOffset(0x1BC)] public int debugDrawFrustumCullGroupSettingIndex; [FieldOffset(0x1C0)] public bool debugEnableOcclusionCullingView; [FieldOffset(0x1C4)] public int debugOccluderVertThreshold; [FieldOffset(0x1D0)] public unsafe fixed byte /* GlobalUserParamOption[4] */ _globalUserParam[128]; public unsafe GlobalUserParamOption* globalUserParam { get { fixed (byte* p_globalUserParam = _globalUserParam) return (GlobalUserParamOption*)p_globalUserParam; } } } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct FxSGGIParameter { [FieldOffset(0x00)] public float sgStartSmoothness; [FieldOffset(0x04)] public float sgEndSmoothness; [FieldOffset(0x08)] public float doStartSmoothness; [FieldOffset(0x0C)] public float doEndSmoothness; [FieldOffset(0x10)] public float doOffset; [FieldOffset(0x14)] public float aoOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct FxRLRParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool traceSky; [FieldOffset(0x02)] public bool useTrans; [FieldOffset(0x03)] public bool usePenet; [FieldOffset(0x04)] public bool useQuat; [FieldOffset(0x05)] public bool useNormal; [FieldOffset(0x08)] public float rayMarchingCount; [FieldOffset(0x0C)] public float planeNormalDist; [FieldOffset(0x10)] public float traceThreshold; [FieldOffset(0x14)] public float resolveReproj; [FieldOffset(0x18)] public float overrideRatio; [FieldOffset(0x1C)] public float maxRoughness; [FieldOffset(0x20)] public float roughnessLevel; [FieldOffset(0x24)] public float uvOffsetScale; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct FxSSGIDebugParameter { [FieldOffset(0x00)] public bool useDenoise; [FieldOffset(0x04)] public float rayLength; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct FxSSGIParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float intensity; [FieldOffset(0x08)] public bool useAlbedo; [FieldOffset(0x09)] public bool useParameter; [FieldOffset(0x0C)] public FxSSGIDebugParameter debugParam; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct FxPlanarReflectionParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x10)] public Vector4 plane; [FieldOffset(0x20)] public uint width; [FieldOffset(0x24)] public uint height; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct FxBloomParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool fast; [FieldOffset(0x04)] public float bloomScale; [FieldOffset(0x08)] public float sampleRadiusScale; [FieldOffset(0x0C)] public int blurQuality; } public enum Exposure : sbyte { EXPOSURE_MANUAL = 0, EXPOSURE_AUTO = 1 } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct FxManualExposureParameter { [FieldOffset(0x00)] public float exposureValue; } public enum LUMINANCE_RANGE : sbyte { LUMINANCE_RANGE_CLAMP = 0, LUMINANCE_RANGE_CUTOFF = 1, LUMINANCE_RANGE_CUTOFF_PCT_RATE = 2, LUMINANCE_RANGE_CUTOFF_PCT_AREA = 3 } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct FxAutoExposureParameter { [FieldOffset(0x00)] public float middleGray; [FieldOffset(0x04)] public float lumMax; [FieldOffset(0x08)] public float lumMin; [FieldOffset(0x0C)] public float cutMax; [FieldOffset(0x10)] public float cutMin; [FieldOffset(0x14)] public float pctMax; [FieldOffset(0x18)] public float pctMin; [FieldOffset(0x1C)] public float adaptedRatio; [FieldOffset(0x20)] public LUMINANCE_RANGE luminanceRangeType; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct FxCameraControlParameter { [FieldOffset(0x00)] public Exposure exposureType; [FieldOffset(0x04)] public FxManualExposureParameter manualExposure; [FieldOffset(0x08)] public FxAutoExposureParameter autoExposure; } public enum Tonemap : sbyte { TONEMAP_DISNEY = 0, TONEMAP_FILMIC = 1, TONEMAP_ACES = 2, TONEMAP_GT = 3 } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct FxToneMapParameterFilmic { [FieldOffset(0x00)] public float whitePoint; [FieldOffset(0x04)] public float toeStrength; [FieldOffset(0x08)] public float linearAngle; [FieldOffset(0x0C)] public float linearStrength; [FieldOffset(0x10)] public float shoulderStrength; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct FxToneMapParameterGT { [FieldOffset(0x00)] public float maxDisplayBrightness; [FieldOffset(0x04)] public float contrast; [FieldOffset(0x08)] public float linearSectionStart; [FieldOffset(0x0C)] public float linearSectionLength; [FieldOffset(0x10)] public float black; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct FxToneMapParameter { [FieldOffset(0x00)] public Tonemap tonemapType; [FieldOffset(0x04)] public FxToneMapParameterFilmic tonemapParamFilmic; [FieldOffset(0x18)] public FxToneMapParameterGT tonemapParamGT; [FieldOffset(0x2C)] public bool updateLuminance; } public enum LutIndex : int { LUT_INDEX_DEFAULT = 0, LUT_INDEX_WB = 1, LUT_INDEX_USER_0 = 2, LUT_INDEX_USER_1 = 3, LUT_INDEX_USER_2 = 4, LUT_INDEX_USER_3 = 5, LUT_INDEX_USER_4 = 6, LUT_INDEX_USER_5 = 7, LUT_INDEX_COUNT = 8 } [StructLayout(LayoutKind.Explicit, Size = 0x4C)] public struct FxColorContrastParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float contrast; [FieldOffset(0x08)] public float dynamicRange; [FieldOffset(0x0C)] public float crushShadows; [FieldOffset(0x10)] public float crushHilights; [FieldOffset(0x14)] public bool useLut; [FieldOffset(0x18)] public LutIndex lutIndex0; [FieldOffset(0x1C)] public LutIndex lutIndex1; [FieldOffset(0x20)] public float blendRatio; [FieldOffset(0x24)] public float lutRatio; [FieldOffset(0x28)] public bool useHlsCorrection; [FieldOffset(0x2C)] public float hlsHueOffset; [FieldOffset(0x30)] public float hlsLightnessOffset; [FieldOffset(0x34)] public float hlsSaturationOffset; [FieldOffset(0x38)] public unsafe fixed int hlsColorOffset[3]; [FieldOffset(0x44)] public float hlsColorizeRate; [FieldOffset(0x48)] public float hlsColorizeHue; } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct FxLightScatteringParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x10)] public Vector3 color; [FieldOffset(0x20)] public float inScatteringScale; [FieldOffset(0x30)] public Vector3 betaRayleigh; [FieldOffset(0x40)] public float betaMie; [FieldOffset(0x44)] public float g; [FieldOffset(0x48)] public float znear; [FieldOffset(0x4C)] public float zfar; [FieldOffset(0x50)] public float depthScale; } public enum RenderTargetSize : int { RTSIZE_FULL_SCALE = 0, RTSIZE_HALF_SCALE = 1, RTSIZE_QUARTER_SCALE = 2, RTSIZE_COUNT = 3, RTSIZE_INVALID = 3 } [StructLayout(LayoutKind.Explicit, Size = 0x54)] public struct FxDOFParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool useFocusLookAt; [FieldOffset(0x04)] public float foregroundBokehMaxDepth; [FieldOffset(0x08)] public float foregroundBokehStartDepth; [FieldOffset(0x0C)] public float backgroundBokehStartDepth; [FieldOffset(0x10)] public float backgroundBokehMaxDepth; [FieldOffset(0x14)] public bool enableCircleDOF; [FieldOffset(0x18)] public float cocMaxRadius; [FieldOffset(0x1C)] public float bokehRadiusScale; [FieldOffset(0x20)] public int bokehSampleCount; [FieldOffset(0x24)] public float skyFocusDistance; [FieldOffset(0x28)] public float bokehBias; [FieldOffset(0x2C)] public bool drawFocalPlane; [FieldOffset(0x30)] public RenderTargetSize rtScale; [FieldOffset(0x34)] public bool enableSWA; [FieldOffset(0x38)] public float swaFocus; [FieldOffset(0x3C)] public float swaFocusRange; [FieldOffset(0x40)] public float swaNear; [FieldOffset(0x44)] public float swaFar; [FieldOffset(0x48)] public bool enableEnhancedForeBokeh; [FieldOffset(0x4C)] public float foreBokehScale; [FieldOffset(0x50)] public float foreBokehMaxLuminance; } public enum ShadowRenderingType : sbyte { SHADOW_RENDERING_TYPE_SHADOW_MAP = 0, SHADOW_RENDERING_TYPE_PLANAR_PROJECTION = 1, SHADOW_RENDERING_TYPE_PLANAR_PROJECTION_SHADOW_MAP = 2, SHADOW_RENDERING_TYPE_MULTI_SHADOW_MAP = 3, SHADOW_RENDERING_TYPE_COUNT = 4 } public enum ShadowFilter : sbyte { SHADOW_FILTER_POINT = 0, SHADOW_FILTER_PCF = 1, SHADOW_FILTER_PCSS = 2, SHADOW_FILTER_ESM = 3, SHADOW_FILTER_MSM = 4, SHADOW_FILTER_VSM_POINT = 5, SHADOW_FILTER_VSM_LINEAR = 6, SHADOW_FILTER_VSM_ANISO_2 = 7, SHADOW_FILTER_VSM_ANISO_4 = 8, SHADOW_FILTER_VSM_ANISO_8 = 9, SHADOW_FILTER_VSM_ANISO_16 = 10, SHADOW_FILTER_COUNT = 11, SHADOW_FILTER_VSM_FIRST = 5, SHADOW_FILTER_VSM_LAST = 10 } public enum ShadowRangeType : sbyte { SHADOW_RANGE_TYPE_CAMERA_LOOKAT = 0, SHADOW_RANGE_TYPE_POSITION_MANUAL = 1, SHADOW_RANGE_TYPE_FULL_MANUAL = 2, SHADOW_RANGE_TYPE_COUNT = 3, SHADOW_RANGE_TYPE_DEFAULT = 0 } public enum FitProjection : sbyte { FIT_PROJECTION_TO_CASCADES = 0, FIT_PROJECTION_TO_SCENE = 1, FIT_PROJECTION_TO_ROTATE_CASCADES = 2 } public enum FitNearFar : sbyte { FIT_NEARFAR_ZERO_ONE = 0, FIT_NEARFAR_AABB = 1, FIT_NEARFAR_SCENE_AABB = 2 } public enum PartitionType : sbyte { PARTITION_PSSM = 0, PARTITION_MANUAL = 1 } [StructLayout(LayoutKind.Explicit, Size = 0x150)] public struct FxShadowMapParameter { [FieldOffset(0x00)] public ShadowRenderingType renderingType; [FieldOffset(0x01)] public bool enable; [FieldOffset(0x02)] public ShadowFilter shadowFilter; [FieldOffset(0x03)] public ShadowRangeType shadowRangeType; [FieldOffset(0x04)] public FitProjection fitProjection; [FieldOffset(0x05)] public FitNearFar fitNearFar; [FieldOffset(0x06)] public PartitionType partitionType; [FieldOffset(0x08)] public float sceneRange; [FieldOffset(0x0C)] public unsafe fixed float sceneCenter[3]; [FieldOffset(0x18)] public unsafe fixed float manualLightPos[3]; [FieldOffset(0x24)] public float pssmLambda; [FieldOffset(0x28)] public float cascadeOffset; [FieldOffset(0x2C)] public int cascadeLevel; [FieldOffset(0x30)] public unsafe fixed float cascadeSplits[4]; [FieldOffset(0x40)] public unsafe fixed float cascadeBias[4]; [FieldOffset(0x50)] public float bias; [FieldOffset(0x54)] public float offset; [FieldOffset(0x58)] public float normalBias; [FieldOffset(0x5C)] public int width; [FieldOffset(0x60)] public int height; [FieldOffset(0x64)] public int blurQuality; [FieldOffset(0x68)] public int blurSize; [FieldOffset(0x6C)] public float fadeoutDistance; [FieldOffset(0x70)] public float cascadeTransitionfadeDistance; [FieldOffset(0x74)] public bool enableCSMCache; [FieldOffset(0x78)] public float csmCacheMaxHeight; [FieldOffset(0x7C)] public float csmCacheMinHeight; [FieldOffset(0x80)] public int csmCacheMaxRenderPass; [FieldOffset(0x84)] public float csmCacheFixedFovy; [FieldOffset(0x88)] public float csmCacheLightDirectionThreshold; [FieldOffset(0x8C)] public bool csmCacheParallaxCorrectionEnabled; [FieldOffset(0x90)] public float csmCacheParallaxCorrectionHorizontalBias; [FieldOffset(0x94)] public float csmCacheParallaxCorrectionVerticalBias; [FieldOffset(0x98)] public unsafe fixed int csmCacheFramesToRender[3]; [FieldOffset(0xA4)] public float csmCacheFadeLightElevationAngle; [FieldOffset(0xA8)] public float csmCacheMinLightElevationAngle; [FieldOffset(0xB0)] public Matrix4x4 shadowCameraViewMatrix; [FieldOffset(0xF0)] public Matrix4x4 shadowCameraProjectionMatrix; [FieldOffset(0x130)] public float shadowCameraNearDepth; [FieldOffset(0x134)] public float shadowCameraFarDepth; [FieldOffset(0x138)] public float shadowCameraLookAtDepth; [FieldOffset(0x13C)] public bool enableBackFaceShadow; [FieldOffset(0x13D)] public bool enableShadowCamera; [FieldOffset(0x13E)] public bool enableDrawSceneAABB; [FieldOffset(0x13F)] public bool enableDrawShadowFrustum; [FieldOffset(0x140)] public bool enableDrawCascade; [FieldOffset(0x141)] public bool enableDrawCameraFrustum; [FieldOffset(0x142)] public bool enableDrawCSMCache; [FieldOffset(0x143)] public bool enableClearOnCSMCacheIsInvalidated; [FieldOffset(0x144)] public bool enablePauseCamera; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct FxShadowHeightMapParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float bias; [FieldOffset(0x08)] public float distanceFalloff; [FieldOffset(0x0C)] public float heightFalloffMinHeight; [FieldOffset(0x10)] public float heightFalloffDistance; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct FxVolumetricShadowParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool isForceUseShadowmap; [FieldOffset(0x02)] public bool isUseCloudShadow; [FieldOffset(0x03)] public bool isUseHeightmapShadow; } public enum SSAOType : sbyte { SSAO = 0, HBAO = 1, HBAO_SSS = 2, SSS = 3, TYPE_COUNT = 4 } public enum FxSSAOParameter_RenderTargetSize : sbyte { RTSIZE_SAME_AS_FRAMEBUFFER = 0, RTSIZE_ONE_SECOND = 1, RTSIZE_ONE_FORTH = 2, FxSSAOParameter_RenderTargetSize_RTSIZE_COUNT = 3 } public enum BLURType : sbyte { None = 1, Gauss2x2 = 2, Gauss3x3 = 3, Gauss4x4 = 4, Gauss5x5 = 5, Gauss6x6 = 6, Gauss7x7 = 7, Gauss8x8 = 8, Gauss9x9 = 9, Bilateral = 10, BLUR_COUNT = 11 } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct FxSSAO_Parameter { [FieldOffset(0x00)] public float intensity; [FieldOffset(0x04)] public float radius; [FieldOffset(0x08)] public float fadeoutDistance; [FieldOffset(0x0C)] public float fadeoutRadius; [FieldOffset(0x10)] public float power; [FieldOffset(0x14)] public float bias; [FieldOffset(0x18)] public float occlusionDistance; [FieldOffset(0x1C)] public float directLightingInfluence; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct FxHBAO_Parameter { [FieldOffset(0x00)] public float hbaoPower; [FieldOffset(0x04)] public float hbaoBias; [FieldOffset(0x08)] public float hbaoRadius; [FieldOffset(0x0C)] public float hbaoFalloff; [FieldOffset(0x10)] public float hbaoSteps; [FieldOffset(0x14)] public float hbaoGitter; [FieldOffset(0x18)] public sbyte hbaoRaycount; [FieldOffset(0x19)] public bool hbaoGiMaskEnable; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct FxSSS_Parameter { [FieldOffset(0x00)] public float sssRayLength; [FieldOffset(0x04)] public sbyte sssRaycount; [FieldOffset(0x08)] public float sssBias; [FieldOffset(0x0C)] public float sssIntensity; [FieldOffset(0x10)] public float sssDepthMin; [FieldOffset(0x14)] public float sssDepthMax; [FieldOffset(0x18)] public float sssLightDistance; [FieldOffset(0x1C)] public float sssThickness; [FieldOffset(0x20)] public bool sssGiMaskEnable; [FieldOffset(0x24)] public float sssLimit; [FieldOffset(0x28)] public bool sssDitherEnable; } [StructLayout(LayoutKind.Explicit, Size = 0x70)] public struct FxSSAOParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public SSAOType postType; [FieldOffset(0x02)] public FxSSAOParameter_RenderTargetSize renderTargetSize; [FieldOffset(0x03)] public BLURType blurStep; [FieldOffset(0x04)] public float bilateralThreshold; [FieldOffset(0x08)] public FxSSAO_Parameter ssaoParam; [FieldOffset(0x28)] public FxHBAO_Parameter hbaoParam; [FieldOffset(0x44)] public FxSSS_Parameter sssParam; } public enum DebugDrawType : sbyte { DEBUG_DRAW_NONE = 0, DEBUG_DRAW_ONLY_ENABLED = 1, DEBUG_DRAW_ALL = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct FxLightFieldMergeParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float blendRatio; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct FxSHLightFieldParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public DebugDrawType debugDrawType; [FieldOffset(0x02)] public bool showSkyVisibility; [FieldOffset(0x04)] public float debugProbeSize; [FieldOffset(0x10)] public Vector3 multiplyColorUp; [FieldOffset(0x20)] public Vector3 multiplyColorDown; [FieldOffset(0x30)] public float normalBias; [FieldOffset(0x34)] public FxLightFieldMergeParameter lfMerge; } public enum BlurType : sbyte { BLURTYPE_PREV_SURFACE = 0, BLURTYPE_RADIAL = 1, BLURTYPE_CAMERA = 2, BLURTYPE_COUNT = 3 } public enum FocusType : sbyte { FOCUSTYPE_CENTER = 0, FOCUSTYPE_LOOKAT = 1, FOCUSTYPE_USER_SETTING = 2, FOCUSTYPE_COUNT = 3 } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct FxScreenBlurParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public BlurType blurType; [FieldOffset(0x04)] public float blurPower; [FieldOffset(0x08)] public FocusType focusType; [FieldOffset(0x10)] public Vector3 focusPosition; [FieldOffset(0x20)] public float focusRange; [FieldOffset(0x24)] public float alphaSlope; [FieldOffset(0x28)] public int sampleNum; [FieldOffset(0x2C)] public bool singleDirectionOpt; } public struct Color8 { public byte A; public byte R; public byte G; public byte B; } [StructLayout(LayoutKind.Explicit, Size = 0x90)] public struct FxOcclusionCapsuleParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool enableOcclusion; [FieldOffset(0x04)] public Color8 occlusionColor; [FieldOffset(0x08)] public float occlusionPower; [FieldOffset(0x0C)] public bool enableSpecularOcclusion; [FieldOffset(0x10)] public float specularOcclusionAlpha; [FieldOffset(0x14)] public float specularOcclusionPower; [FieldOffset(0x18)] public float specularOcclusionConeAngle; [FieldOffset(0x1C)] public bool enableShadow; [FieldOffset(0x20)] public Color8 shadowColor; [FieldOffset(0x24)] public float shadowPower; [FieldOffset(0x28)] public float shadowConeAngle; [FieldOffset(0x2C)] public float cullingDistance; [FieldOffset(0x30)] public bool enableManualLight; [FieldOffset(0x34)] public int manualLightCount; [FieldOffset(0x40)] public unsafe fixed byte /* Vector3[4] */ _manualLightPos[64]; public unsafe Vector3* manualLightPos { get { fixed (byte* p_manualLightPos = _manualLightPos) return (Vector3*)p_manualLightPos; } } [FieldOffset(0x80)] public bool debugDraw; } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct FxEffectParameter { [FieldOffset(0x00)] public float lightFieldColorCoefficient; [FieldOffset(0x04)] public float invTonemapCoefficient; [FieldOffset(0x10)] public Vector3 shadowColor; [FieldOffset(0x20)] public Vector3 directionalLightOverwrite; [FieldOffset(0x30)] public float directionalLightIntensityOverwrite; [FieldOffset(0x34)] public bool overwriteDirectionalLight; [FieldOffset(0x38)] public float localLightIntensityScale; [FieldOffset(0x3C)] public unsafe fixed float lodDistances[8]; [FieldOffset(0x5C)] public bool enableVisualizeOverdraw; [FieldOffset(0x5D)] public bool renderWireframe; [FieldOffset(0x5E)] public bool upsampleBilateral; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct FxScreenSpaceGodrayParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float rayMarchingCount; [FieldOffset(0x08)] public float density; [FieldOffset(0x0C)] public float decay; [FieldOffset(0x10)] public float threshold; [FieldOffset(0x14)] public float lumMax; [FieldOffset(0x18)] public float intensity; [FieldOffset(0x1C)] public bool enableDither; [FieldOffset(0x20)] public Vector3 lightPos; [FieldOffset(0x30)] public Vector3 lightDir; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct FxGodrayVolumeTexture { [FieldOffset(0x00)] public bool enableVolumeTexture; [FieldOffset(0x04)] public float uvScale; [FieldOffset(0x08)] public float timeScale; [FieldOffset(0x0C)] public float animationAngle; } [StructLayout(LayoutKind.Explicit, Size = 0xF0)] public struct FxGodrayParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool isUseShadowmap; [FieldOffset(0x02)] public bool isVariableStep; [FieldOffset(0x10)] public Matrix4x4 shadow; [FieldOffset(0x50)] public Matrix4x4 box; [FieldOffset(0x90)] public Vector3 color; [FieldOffset(0xA0)] public float density; [FieldOffset(0xA4)] public float anisotropy; [FieldOffset(0xA8)] public float range; [FieldOffset(0xAC)] public float rayMarchingCount; [FieldOffset(0xB0)] public float rayMarchingStep; [FieldOffset(0xB4)] public float shadowEdge; [FieldOffset(0xB8)] public bool isScanFromBack; [FieldOffset(0xBC)] public int boxCount; [FieldOffset(0xC0)] public bool isNewMode; [FieldOffset(0xC4)] public FxGodrayVolumeTexture volumeTexture; [FieldOffset(0xD4)] public float transparency; [FieldOffset(0xD8)] public bool enable3d; [FieldOffset(0xDC)] public float reProject3d; [FieldOffset(0xE0)] public float logNear3d; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct FxHeatHazeParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float speed; [FieldOffset(0x08)] public float scale; [FieldOffset(0x0C)] public float cycle; [FieldOffset(0x10)] public float nearDepth; [FieldOffset(0x14)] public float farDepth; [FieldOffset(0x18)] public float maxHeight; [FieldOffset(0x1C)] public float parallaxCorrectFactor; } public enum SunPosType : sbyte { SUN_POS_TYPE_NONE = 0, SUN_POS_TYPE_ANGLE = 1, SUN_POS_TYPE_EARTH = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct FxSunPosAngle { [FieldOffset(0x00)] public float azimuthAngle; [FieldOffset(0x04)] public float elevationAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct FxSunPosEarth { [FieldOffset(0x00)] public float azimuthAngle; [FieldOffset(0x04)] public float latitude; [FieldOffset(0x08)] public float longitude; [FieldOffset(0x0C)] public int month; [FieldOffset(0x10)] public int day; [FieldOffset(0x14)] public float time; [FieldOffset(0x18)] public bool enableAnimation; [FieldOffset(0x1C)] public float animationSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct FxSun { [FieldOffset(0x00)] public float solarRadiusScale; [FieldOffset(0x04)] public SunPosType sunPosType; [FieldOffset(0x08)] public FxSunPosAngle posTypeAngle; [FieldOffset(0x10)] public FxSunPosEarth posTypeEarth; } public enum MoonPosType : sbyte { MOON_POS_TYPE_NONE = 0, MOON_POS_TYPE_INV_SUN = 1, MOON_POS_TYPE_EARTH = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x01)] public struct FxMoon { [FieldOffset(0x00)] public MoonPosType moonPosType; } public enum SkyModel : sbyte { BRUNETON = 0, SEBASTIEN = 1 } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct FxSkyCommon { [FieldOffset(0x00)] public SkyModel skyModel; [FieldOffset(0x04)] public float illuminanceScale; [FieldOffset(0x08)] public bool enableScattering; [FieldOffset(0x0C)] public float scatteringRatio; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct FxBrunetonSkyNight { [FieldOffset(0x00)] public float lunarIntensityInSky; [FieldOffset(0x04)] public float starIntensityInSky; [FieldOffset(0x08)] public float lunarIntensityInCloud; [FieldOffset(0x0C)] public float lunarIntensity; [FieldOffset(0x10)] public float skyIntensity; [FieldOffset(0x14)] public Color8 lunarLightColor; [FieldOffset(0x20)] public Vector4 lunarLightColorOffset; [FieldOffset(0x30)] public float lunarLightPower; } [StructLayout(LayoutKind.Explicit, Size = 0x90)] public struct FxBrunetonSky { [FieldOffset(0x00)] public float illuminanceScale; [FieldOffset(0x04)] public Color8 rayleighColor; [FieldOffset(0x08)] public Color8 lightColorScale; [FieldOffset(0x0C)] public float miePhaseFunctionG; [FieldOffset(0x10)] public Color8 mieScatteringColor; [FieldOffset(0x14)] public float mieScatteringScale; [FieldOffset(0x18)] public Color8 mieAbsorptionColor; [FieldOffset(0x1C)] public float mieAbsorptionScale; [FieldOffset(0x20)] public Color8 rayleighScatteringColor; [FieldOffset(0x24)] public float rayleighScatteringScale; [FieldOffset(0x28)] public Color8 groundAlbedo; [FieldOffset(0x2C)] public Color8 groundIrradianceScale; [FieldOffset(0x30)] public Color8 cubemapColorScale; [FieldOffset(0x34)] public float cubemapColorAngleRatio; [FieldOffset(0x38)] public bool enableScattering; [FieldOffset(0x3C)] public float scatteringRatio; [FieldOffset(0x40)] public FxBrunetonSkyNight night; [FieldOffset(0x80)] public bool enableLimitY; [FieldOffset(0x84)] public float debugSkyCubeIntensity; } [StructLayout(LayoutKind.Explicit, Size = 0x90)] public struct FxSebastienSky { [FieldOffset(0x00)] public float miePhaseFunctionG; [FieldOffset(0x04)] public Color8 mieScatteringColor; [FieldOffset(0x10)] public Vector4 mieScatteringColorOffset; [FieldOffset(0x20)] public float mieScatteringScale; [FieldOffset(0x24)] public Color8 mieAbsorptionColor; [FieldOffset(0x30)] public Vector4 mieAbsorptionColorOffset; [FieldOffset(0x40)] public float mieAbsorptionScale; [FieldOffset(0x44)] public Color8 rayleighScatteringColor; [FieldOffset(0x50)] public Vector4 rayleighScatteringColorOffset; [FieldOffset(0x60)] public float rayleighScatteringScale; [FieldOffset(0x64)] public Color8 groundAlbedo; [FieldOffset(0x70)] public Vector4 groundAlbedoOffset; [FieldOffset(0x80)] public bool enableGround; [FieldOffset(0x84)] public int numScatteringOrder; [FieldOffset(0x88)] public bool enableScattering; [FieldOffset(0x89)] public bool enableLimitY; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct FxCloudProcedural { [FieldOffset(0x00)] public Vector3 uvScale; [FieldOffset(0x10)] public Vector3 colorGamma; [FieldOffset(0x20)] public Vector3 colorScale; [FieldOffset(0x30)] public Vector3 colorOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct FxCloudBlendParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float probability; [FieldOffset(0x08)] public float cloudiness; [FieldOffset(0x10)] public FxCloudProcedural proceduralCloud; } [StructLayout(LayoutKind.Explicit, Size = 0x100)] public struct FxCloudParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool enableAnimation; [FieldOffset(0x04)] public float animationFrame; [FieldOffset(0x08)] public float animationSpeed; [FieldOffset(0x0C)] public float animationAngle; [FieldOffset(0x10)] public float animationSpeedCirrus; [FieldOffset(0x14)] public float animationAngleCirrus; [FieldOffset(0x18)] public float skyHorizonOffset; [FieldOffset(0x1C)] public float cloudStartHeight; [FieldOffset(0x20)] public float cloudCoverageSpeed; [FieldOffset(0x24)] public float cloudTypeSpeed; [FieldOffset(0x28)] public float cloudWetnessSpeed; [FieldOffset(0x2C)] public float miePhaseFunctionG; [FieldOffset(0x30)] public float silverIntensity; [FieldOffset(0x34)] public float silverSpread; [FieldOffset(0x38)] public float scale; [FieldOffset(0x3C)] public float density; [FieldOffset(0x40)] public float densityThreshold; [FieldOffset(0x44)] public Color8 cloudsExtinctionColor1; [FieldOffset(0x50)] public Vector4 cloudsExtinctionColor1Offset; [FieldOffset(0x60)] public Color8 cloudsExtinctionColor2; [FieldOffset(0x70)] public Vector4 cloudsExtinctionColor2Offset; [FieldOffset(0x80)] public Color8 cloudsExtinctionColor3; [FieldOffset(0x90)] public Vector4 cloudsExtinctionColor3Offset; [FieldOffset(0xA0)] public float cloudExtinctionBlend; [FieldOffset(0xA4)] public bool enableShadow; [FieldOffset(0xA8)] public int shadowCoverage; [FieldOffset(0xAC)] public float shadowValueMin; [FieldOffset(0xB0)] public FxCloudBlendParameter blendParam; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct FxCrepuscularRay { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float density; [FieldOffset(0x08)] public float decay; [FieldOffset(0x0C)] public float weight; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct FxManualHeightFog { [FieldOffset(0x00)] public Vector3 sunColor; [FieldOffset(0x10)] public Vector3 ambColor; } [StructLayout(LayoutKind.Explicit, Size = 0x70)] public struct FxHeightFog { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool enableFogMap; [FieldOffset(0x04)] public float heightScale; [FieldOffset(0x08)] public float distanceOffset; [FieldOffset(0x0C)] public float distanceScale; [FieldOffset(0x10)] public Vector3 rayleighScale; [FieldOffset(0x20)] public Vector3 mieScale; [FieldOffset(0x30)] public float noiseBlend; [FieldOffset(0x34)] public float noiseScale; [FieldOffset(0x38)] public float noiseDistance; [FieldOffset(0x3C)] public float animationSpeed; [FieldOffset(0x40)] public float animationAngle; [FieldOffset(0x44)] public bool isAtmospheric; [FieldOffset(0x50)] public FxManualHeightFog manualFog; } [StructLayout(LayoutKind.Explicit, Size = 0x2F0)] public struct FxAtmosphereParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public FxSun sunParam; [FieldOffset(0x34)] public FxMoon moonParam; [FieldOffset(0x38)] public FxSkyCommon commonSkyParam; [FieldOffset(0x50)] public FxBrunetonSky brunetonSkyParam; [FieldOffset(0xE0)] public FxSebastienSky sebastienSkyParam; [FieldOffset(0x170)] public FxCloudParameter cloudParam; [FieldOffset(0x270)] public FxCrepuscularRay crepuscularRayParam; [FieldOffset(0x280)] public FxHeightFog heightFogParam; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct FxPuddleParameter { [FieldOffset(0x00)] public float heightThreshold; [FieldOffset(0x04)] public float slopeThreshold; [FieldOffset(0x08)] public float noiseScaleXZ; [FieldOffset(0x0C)] public float noiseScaleY; [FieldOffset(0x10)] public float noiseThreshold; [FieldOffset(0x14)] public float noiseAttenuationRange; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct FxRippleParameter { [FieldOffset(0x00)] public float intensity; [FieldOffset(0x04)] public float uvScale; [FieldOffset(0x08)] public float timeScale; [FieldOffset(0x0C)] public float normalIntensity; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct FxDropParameter { [FieldOffset(0x00)] public float uvScale; [FieldOffset(0x04)] public float timeScale; [FieldOffset(0x08)] public float normalIntensity; } [StructLayout(LayoutKind.Explicit, Size = 0x80)] public struct FxRainParameter { [FieldOffset(0x00)] public bool enableDrop; [FieldOffset(0x01)] public bool enableFilter; [FieldOffset(0x02)] public bool enableRipple; [FieldOffset(0x04)] public float intensity; [FieldOffset(0x10)] public Vector4 dropColor; [FieldOffset(0x20)] public bool dropRotTarget; [FieldOffset(0x21)] public bool enableDropOcc; [FieldOffset(0x24)] public float dropCameraLerp; [FieldOffset(0x28)] public float dropCameraRate; [FieldOffset(0x2C)] public float dropCameraRotation; [FieldOffset(0x30)] public float dropWidth; [FieldOffset(0x34)] public float dropLength; [FieldOffset(0x38)] public float dropWind; [FieldOffset(0x3C)] public float dropRange; [FieldOffset(0x40)] public Vector4 filterColor; [FieldOffset(0x50)] public float filterRange; [FieldOffset(0x54)] public float filterEdge; [FieldOffset(0x58)] public float filterAngle; [FieldOffset(0x5C)] public FxRippleParameter ripple; [FieldOffset(0x6C)] public FxDropParameter drop; } [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct FxWeatherParameter { [FieldOffset(0x00)] public float wetness; [FieldOffset(0x04)] public FxPuddleParameter puddle; [FieldOffset(0x20)] public FxRainParameter rain; } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct FxSceneEnvironmentParameter { [FieldOffset(0x00)] public float windRotationY; [FieldOffset(0x04)] public float windStrength; [FieldOffset(0x08)] public float windNoise; [FieldOffset(0x0C)] public float windAmplitude; [FieldOffset(0x10)] public unsafe fixed float windFrequencies[4]; [FieldOffset(0x20)] public bool enableTreadGrass; [FieldOffset(0x30)] public Vector4 grassLodDistance; [FieldOffset(0x40)] public bool enableHighLight; [FieldOffset(0x44)] public float highLightThreshold; [FieldOffset(0x48)] public float highLightObjectAmbientScale; [FieldOffset(0x4C)] public float highLightObjectAlbedoHeighten; [FieldOffset(0x50)] public float highLightCharaAmbientScale; [FieldOffset(0x54)] public float highLightCharaAlbedoHeighten; [FieldOffset(0x58)] public float highLightCharaFalloffScale; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct FxTAAParameter { [FieldOffset(0x00)] public bool enableUpscaling; [FieldOffset(0x04)] public float jitterScale; [FieldOffset(0x08)] public float mipBias; [FieldOffset(0x0C)] public float sharpnessPower; [FieldOffset(0x10)] public float baseWeight; [FieldOffset(0x14)] public float velocityVarianceBasedWeightBias; [FieldOffset(0x18)] public float colorSpaceClippingScale; [FieldOffset(0x1C)] public float colorSpaceClippingScaleForStatic; [FieldOffset(0x20)] public float velocityVarianceMin; [FieldOffset(0x24)] public float velocityVarianceMax; [FieldOffset(0x28)] public bool enableCharaStencilMask; [FieldOffset(0x29)] public bool enableLiteMode; [FieldOffset(0x2A)] public bool enablePassThrough; [FieldOffset(0x2B)] public bool debugVisualizeVelcotiyVariance; [FieldOffset(0x30)] public Vector4 debug; } public enum PlacementType : sbyte { CirclePacking = 0, RandomPos = 1, PT_COUNT = 2 } public enum ShadowCullingType : sbyte { Normal = 0, AabbUpScale2 = 1, ShadowFrustum = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct FxDensityLodParameter { [FieldOffset(0x00)] public float lodRatio; [FieldOffset(0x04)] public float lodRise; [FieldOffset(0x08)] public float lodDecrease; [FieldOffset(0x0C)] public float lodThreshold; [FieldOffset(0x10)] public bool lodFadeEnable; } [StructLayout(LayoutKind.Explicit, Size = 0xCC)] public struct FxDensityDebugParameter { [FieldOffset(0x00)] public bool underSelect; [FieldOffset(0x04)] public float factor; [FieldOffset(0x08)] public unsafe fixed float unit[32]; [FieldOffset(0x88)] public unsafe fixed sbyte chunk[32]; [FieldOffset(0xA8)] public float lodAddition; [FieldOffset(0xAC)] public int chunkAddition; [FieldOffset(0xB0)] public float drawLimitLenght; [FieldOffset(0xB4)] public bool drawCallReduction; [FieldOffset(0xB5)] public bool enableDither; [FieldOffset(0xB8)] public int ditherGrass; [FieldOffset(0xBC)] public int ditherOther; [FieldOffset(0xC0)] public int ditherPreComputeGrass; [FieldOffset(0xC4)] public int ditherPreComputeOther; [FieldOffset(0xC8)] public int computeMode; } [StructLayout(LayoutKind.Explicit, Size = 0x10C)] public struct FxDensityParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool precomputeEnable; [FieldOffset(0x02)] public bool cameraUpdate; [FieldOffset(0x03)] public PlacementType placement; [FieldOffset(0x04)] public float placementScale; [FieldOffset(0x08)] public bool alphaEnable; [FieldOffset(0x0C)] public float alphaThreshold; [FieldOffset(0x10)] public float alphaScale; [FieldOffset(0x14)] public bool complementEnable; [FieldOffset(0x15)] public bool disableCut; [FieldOffset(0x16)] public ShadowCullingType shadowCulling; [FieldOffset(0x17)] public bool occlusionCulling; [FieldOffset(0x18)] public float occlusionSize; [FieldOffset(0x1C)] public float occlusionShadowSize; [FieldOffset(0x20)] public float occlusionBias; [FieldOffset(0x24)] public FxDensityLodParameter lodParam; [FieldOffset(0x38)] public bool angleCulling; [FieldOffset(0x3C)] public float angleCullingParam; [FieldOffset(0x40)] public FxDensityDebugParameter debugParam; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct FxChromaticAberrationParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float offsetR; [FieldOffset(0x08)] public float offsetG; [FieldOffset(0x0C)] public float offsetB; [FieldOffset(0x10)] public float curve; [FieldOffset(0x14)] public float scaleX; [FieldOffset(0x18)] public float scaleY; [FieldOffset(0x1C)] public float centerX; [FieldOffset(0x20)] public float centerY; } public enum GradationMode : sbyte { GRADATION_MODE_CIRCLE = 0, GRADATION_MODE_LINE = 1 } public enum BlendMode : sbyte { BLEND_MODE_ALPHA_BLEND = 0, BLEND_MODE_ADD = 1, BLEND_MODE_MUL = 2, BLEND_MODE_SCREEN = 3, BLEND_MODE_OVERLAY = 4 } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct FxVfImageCircleParameter { [FieldOffset(0x00)] public float centerX; [FieldOffset(0x04)] public float centerY; [FieldOffset(0x08)] public float scaleX; [FieldOffset(0x0C)] public float scaleY; [FieldOffset(0x10)] public float scale; [FieldOffset(0x14)] public float rotation; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct FxVfLineParameter { [FieldOffset(0x00)] public float centerX; [FieldOffset(0x04)] public float centerY; [FieldOffset(0x08)] public float directionX; [FieldOffset(0x0C)] public float directionY; [FieldOffset(0x10)] public float rotation; } [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct FxVfDepthParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float minPenumbraScale; [FieldOffset(0x08)] public float maxPenumbraScale; [FieldOffset(0x0C)] public float bokehScale; [FieldOffset(0x10)] public float minDofOpacityScale; [FieldOffset(0x14)] public float maxDofOpacityScale; [FieldOffset(0x18)] public float minOpacityScale; [FieldOffset(0x1C)] public float maxOpacityScale; [FieldOffset(0x20)] public float minOpacityDist; [FieldOffset(0x24)] public float maxOpacityDist; } [StructLayout(LayoutKind.Explicit, Size = 0x80)] public struct FxVignetteParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public GradationMode gradationType; [FieldOffset(0x02)] public BlendMode blendMode; [FieldOffset(0x10)] public Vector3 color; [FieldOffset(0x20)] public float opacity; [FieldOffset(0x24)] public FxVfImageCircleParameter imageCircle; [FieldOffset(0x3C)] public FxVfLineParameter line; [FieldOffset(0x50)] public float penumbraScale; [FieldOffset(0x54)] public float intensity; [FieldOffset(0x58)] public FxVfDepthParameter depth; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct FxWindComputeDebugParameter { [FieldOffset(0x00)] public bool debugEnable; [FieldOffset(0x01)] public bool debugSpace; [FieldOffset(0x02)] public bool debugGlobal; [FieldOffset(0x03)] public bool debugGlobalMap; [FieldOffset(0x04)] public bool debugSpaceAll; [FieldOffset(0x08)] public int spaceIndex; [FieldOffset(0x0C)] public float spaceThreshold; [FieldOffset(0x10)] public float min; [FieldOffset(0x14)] public float max; } [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct FxWindComputeParameter { [FieldOffset(0x00)] public bool enableAll; [FieldOffset(0x01)] public bool enableDynamicWind; [FieldOffset(0x02)] public bool enableGlobalWind; [FieldOffset(0x04)] public float timeScale; [FieldOffset(0x08)] public float decreaseRate; [FieldOffset(0x10)] public Vector3 globalWind; [FieldOffset(0x20)] public float globalWindPower; [FieldOffset(0x24)] public float globalWindSpeed; [FieldOffset(0x28)] public float globalWindOffset; [FieldOffset(0x30)] public Vector3 globalSecondWind; [FieldOffset(0x40)] public float globalSecondWindPower; [FieldOffset(0x44)] public float globalSecondWindSpeed; [FieldOffset(0x48)] public float globalSecondWindOffset; [FieldOffset(0x50)] public Vector3 globalWindMapSize; [FieldOffset(0x60)] public Vector3 globalWindMapCenter; [FieldOffset(0x70)] public Vector3 globalWindMapOffset; [FieldOffset(0x80)] public float globalWindMapPower; [FieldOffset(0x84)] public float globalWindMapTimeScale; [FieldOffset(0x88)] public FxWindComputeDebugParameter debugParam; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct FxTerrainMaterialBlendingParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float blendPower; [FieldOffset(0x08)] public float blendHightPower; [FieldOffset(0x0C)] public float cullingDistance; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct FxInteractionDebugParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool collisionEnable; [FieldOffset(0x04)] public float threshold; } [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct FxInteractionParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float power; [FieldOffset(0x08)] public float decrease; [FieldOffset(0x0C)] public float timeScale; [FieldOffset(0x10)] public FxInteractionDebugParameter debug; [FieldOffset(0x18)] public float tremorPower; [FieldOffset(0x1C)] public float tremorSpeed; [FieldOffset(0x20)] public float tremorScaleCriterion; [FieldOffset(0x24)] public float tremorScaleReduce; } [StructLayout(LayoutKind.Explicit, Size = 0x38)] public struct FxGpuEnvironmentParameter { [FieldOffset(0x00)] public float grassDitherStart; [FieldOffset(0x04)] public float grassDitherEnd; [FieldOffset(0x08)] public FxInteractionParameter interaction; [FieldOffset(0x30)] public bool enableZoomBias; [FieldOffset(0x34)] public float zoomBias; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct FxInteractiveWaveParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x01)] public bool enableDebugDisplay; [FieldOffset(0x04)] public float waveDamping; [FieldOffset(0x08)] public float waveReduceRange; [FieldOffset(0x0C)] public float waveSpeed; [FieldOffset(0x10)] public float simurationScale; [FieldOffset(0x14)] public float playerMaxSpeed; [FieldOffset(0x18)] public bool isInWaterDummy; } [StructLayout(LayoutKind.Explicit, Size = 0x3C)] public struct FxCyberNoiseEffectParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float tileX; [FieldOffset(0x08)] public float tileY; [FieldOffset(0x0C)] public float tileScrollSpeed; [FieldOffset(0x10)] public float noiseScrollSpeed; [FieldOffset(0x14)] public float thresholdSpeed; [FieldOffset(0x18)] public float thredholdMin; [FieldOffset(0x1C)] public float thredholdMax; [FieldOffset(0x20)] public float selectRate; [FieldOffset(0x24)] public float scanLineRSpeed; [FieldOffset(0x28)] public float scanLineRBlend; [FieldOffset(0x2C)] public float scanLineGSpeed; [FieldOffset(0x30)] public float scanLineGBlend; [FieldOffset(0x34)] public float rgbLineScale; [FieldOffset(0x38)] public float rgbLineBlend; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct UVShift { [FieldOffset(0x00)] public float blockLNoiseSizeX; [FieldOffset(0x04)] public float blockLNoiseSizeY; [FieldOffset(0x08)] public float blockHNoiseSizeX; [FieldOffset(0x0C)] public float blockHNoiseSizeY; [FieldOffset(0x10)] public float bNoiseHighRate; [FieldOffset(0x14)] public float intensity; [FieldOffset(0x18)] public float pixelShiftIntensity; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct ColorShift { [FieldOffset(0x00)] public float blockLNoiseSize; [FieldOffset(0x04)] public float blockHNoiseSize; [FieldOffset(0x08)] public float bNoiseHighRate; [FieldOffset(0x0C)] public float intensity; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct InterlaceNoise { [FieldOffset(0x00)] public float blockLNoiseSize; [FieldOffset(0x04)] public float blockHNoiseSize; [FieldOffset(0x08)] public float bNoiseHighRate; [FieldOffset(0x0C)] public float intensity; [FieldOffset(0x10)] public float dropout; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct ColorDropout { [FieldOffset(0x00)] public float blockLNoiseSizeX; [FieldOffset(0x04)] public float blockLNoiseSizeY; [FieldOffset(0x08)] public float blockHNoiseSizeX; [FieldOffset(0x0C)] public float blockHNoiseSizeY; [FieldOffset(0x10)] public float bNoiseHighRate; [FieldOffset(0x14)] public float intensity; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct InvertColor { [FieldOffset(0x00)] public float blockLNoiseSizeX; [FieldOffset(0x04)] public float blockLNoiseSizeY; [FieldOffset(0x08)] public float blockHNoiseSizeX; [FieldOffset(0x0C)] public float blockHNoiseSizeY; [FieldOffset(0x10)] public float bNoiseHighRate; [FieldOffset(0x14)] public float intensity; [FieldOffset(0x18)] public float invertAllRate; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct GlayScaleColor { [FieldOffset(0x00)] public float blockLNoiseSizeX; [FieldOffset(0x04)] public float blockLNoiseSizeY; [FieldOffset(0x08)] public float blockHNoiseSizeX; [FieldOffset(0x0C)] public float blockHNoiseSizeY; [FieldOffset(0x10)] public float bNoiseHighRate; [FieldOffset(0x14)] public float intensity; [FieldOffset(0x18)] public float invertAllRate; } [StructLayout(LayoutKind.Explicit, Size = 0xA4)] public struct FxCyberSpaceStartNoiseParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public UVShift uvShift; [FieldOffset(0x20)] public ColorShift colorShift; [FieldOffset(0x30)] public InterlaceNoise interlaceNoise; [FieldOffset(0x44)] public ColorDropout colorDrop; [FieldOffset(0x5C)] public InvertColor invertColor; [FieldOffset(0x78)] public GlayScaleColor glayscaleColor; [FieldOffset(0x94)] public float noiseSpeed; [FieldOffset(0x98)] public float noiseBias; [FieldOffset(0x9C)] public float noiseWaveAmplitude; [FieldOffset(0xA0)] public float noiseWaveCycle; } [StructLayout(LayoutKind.Explicit, Size = 0x01)] public struct FxCyberNPCSSEffectRenderParameter { [FieldOffset(0x00)] public bool enable; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct FxFieldScanEffectRenderParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x10)] public Vector3 centerPos; [FieldOffset(0x20)] public Color8 color; [FieldOffset(0x24)] public float radius1; [FieldOffset(0x28)] public float radius2; [FieldOffset(0x2C)] public float radius3; [FieldOffset(0x30)] public float intensity1; [FieldOffset(0x34)] public float intensity2; [FieldOffset(0x38)] public float intensity3; [FieldOffset(0x3C)] public float gridIntensity; [FieldOffset(0x40)] public float innerWidth; [FieldOffset(0x44)] public float gridLineWidth; [FieldOffset(0x48)] public float gridLineSpan; } public enum ColorblinidSimulationType : sbyte { COLORBLIND_SIM_NONE = 0, COLORBLIND_SIM_PROTANOPIA = 1, COLORBLIND_SIM_DEUTERANOPIA = 2, COLORBLIND_SIM_TRITANOPIA = 3, COLORBLIND_SIM_ALL = 4 } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct FxColorAccessibilityFilterParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float daltonizeFactor; [FieldOffset(0x08)] public float protanopiaFactor; [FieldOffset(0x0C)] public float deuteranopiaFactor; [FieldOffset(0x10)] public float tritanopiaFactor; [FieldOffset(0x14)] public float brightness; [FieldOffset(0x18)] public float contrast; [FieldOffset(0x1C)] public unsafe fixed float maskIntensity[5]; [FieldOffset(0x30)] public ColorblinidSimulationType simulationType; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct FxDentParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float simRadius; [FieldOffset(0x08)] public float dentDepth; [FieldOffset(0x0C)] public float normalIntensity; [FieldOffset(0x10)] public float edgeBulge; [FieldOffset(0x14)] public float fade; } [StructLayout(LayoutKind.Explicit, Size = 0x110)] public struct FxSeparableSSSParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float width; [FieldOffset(0x08)] public float normalOffset; [FieldOffset(0x0C)] public float blurOffsetMax; [FieldOffset(0x10)] public unsafe fixed byte /* Vector4[16] */ _strength[256]; public unsafe Vector4* strength { get { fixed (byte* p_strength = _strength) return (Vector4*)p_strength; } } } [StructLayout(LayoutKind.Explicit, Size = 0x1270)] public struct NeedleFxParameter { [FieldOffset(0x00)] public FxRenderOption renderOption; [FieldOffset(0x250)] public FxSGGIParameter sggi; [FieldOffset(0x268)] public FxRLRParameter rlr; [FieldOffset(0x290)] public FxSSGIParameter ssgi; [FieldOffset(0x2B0)] public FxPlanarReflectionParameter planarReflection; [FieldOffset(0x2E0)] public FxBloomParameter bloom; [FieldOffset(0x2F0)] public FxCameraControlParameter cameraControl; [FieldOffset(0x31C)] public FxToneMapParameter tonemap; [FieldOffset(0x34C)] public FxColorContrastParameter colorContrast; [FieldOffset(0x3A0)] public FxLightScatteringParameter lightscattering; [FieldOffset(0x400)] public FxDOFParameter dof; [FieldOffset(0x460)] public FxShadowMapParameter shadowmap; [FieldOffset(0x5B0)] public FxShadowHeightMapParameter shadowHeightMap; [FieldOffset(0x5C4)] public FxVolumetricShadowParameter volShadow; [FieldOffset(0x5C8)] public FxSSAOParameter ssao; [FieldOffset(0x640)] public FxSHLightFieldParameter shlightfield; [FieldOffset(0x680)] public FxScreenBlurParameter blur; [FieldOffset(0x6B0)] public FxOcclusionCapsuleParameter occlusionCapsule; [FieldOffset(0x740)] public FxEffectParameter effect; [FieldOffset(0x7A0)] public FxScreenSpaceGodrayParameter ssGodray; [FieldOffset(0x7E0)] public FxGodrayParameter godray; [FieldOffset(0x8D0)] public FxHeatHazeParameter heatHaze; [FieldOffset(0x8F0)] public FxAtmosphereParameter atmosphere; [FieldOffset(0xBE0)] public FxWeatherParameter weather; [FieldOffset(0xC80)] public FxSceneEnvironmentParameter sceneEnv; [FieldOffset(0xCE0)] public FxTAAParameter taa; [FieldOffset(0xD20)] public FxDensityParameter density; [FieldOffset(0xE2C)] public FxChromaticAberrationParameter chromaticAberration; [FieldOffset(0xE50)] public FxVignetteParameter vignette; [FieldOffset(0xED0)] public FxWindComputeParameter wind; [FieldOffset(0xF70)] public FxTerrainMaterialBlendingParameter terrainBlend; [FieldOffset(0xF80)] public FxGpuEnvironmentParameter gpuEnvironment; [FieldOffset(0xFB8)] public FxInteractiveWaveParameter interactiveWave; [FieldOffset(0xFD4)] public FxCyberNoiseEffectParameter cyberNoise; [FieldOffset(0x1010)] public FxCyberSpaceStartNoiseParameter cyberStartNoise; [FieldOffset(0x10B4)] public FxCyberNPCSSEffectRenderParameter cyberNPCSS; [FieldOffset(0x10C0)] public FxFieldScanEffectRenderParameter fieldScan; [FieldOffset(0x1110)] public FxColorAccessibilityFilterParameter colorAccessibility; [FieldOffset(0x1144)] public FxDentParameter dent; [FieldOffset(0x1160)] public FxSeparableSSSParameter ssss; } [StructLayout(LayoutKind.Explicit, Size = 0x2B0)] public struct TimeProgressAtmosphereParameter { [FieldOffset(0x00)] public FxSkyCommon commonSkyParam; [FieldOffset(0x10)] public FxBrunetonSky brunetonSkyParam; [FieldOffset(0xA0)] public FxSebastienSky sebastienSkyParam; [FieldOffset(0x130)] public FxCloudParameter cloudParam; [FieldOffset(0x230)] public FxCrepuscularRay crepuscularRayParam; [FieldOffset(0x240)] public FxHeightFog heightFogParam; } [StructLayout(LayoutKind.Explicit, Size = 0x650)] public struct TimeProgressNeedleFxParam { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public float time; [FieldOffset(0x08)] public FxBloomParameter bloom; [FieldOffset(0x18)] public FxCameraControlParameter cameraControl; [FieldOffset(0x44)] public FxCameraControlParameter cameraControlEvent; [FieldOffset(0x70)] public FxToneMapParameter tonemap; [FieldOffset(0xA0)] public FxColorContrastParameter colorContrast; [FieldOffset(0xF0)] public FxLightScatteringParameter lightscattering; [FieldOffset(0x150)] public FxEffectParameter effect; [FieldOffset(0x1B0)] public FxScreenSpaceGodrayParameter ssGodray; [FieldOffset(0x1F0)] public FxGodrayParameter godray; [FieldOffset(0x2E0)] public FxHeatHazeParameter heatHaze; [FieldOffset(0x300)] public TimeProgressAtmosphereParameter atmosphere; [FieldOffset(0x5B0)] public FxWeatherParameter weather; } [StructLayout(LayoutKind.Explicit, Size = 0x6F0)] public struct WeatherFxParameter { [FieldOffset(0x00)] public bool enable; [FieldOffset(0x04)] public FxBloomParameter bloom; [FieldOffset(0x14)] public FxCameraControlParameter cameraControl; [FieldOffset(0x40)] public FxCameraControlParameter cameraControlEvent; [FieldOffset(0x6C)] public FxToneMapParameter tonemap; [FieldOffset(0x9C)] public FxColorContrastParameter colorContrast; [FieldOffset(0xF0)] public FxLightScatteringParameter lightscattering; [FieldOffset(0x150)] public FxEffectParameter effect; [FieldOffset(0x1B0)] public FxScreenSpaceGodrayParameter ssGodray; [FieldOffset(0x1F0)] public FxGodrayParameter godray; [FieldOffset(0x2E0)] public FxHeatHazeParameter heatHaze; [FieldOffset(0x300)] public TimeProgressAtmosphereParameter atmosphere; [FieldOffset(0x5B0)] public FxWeatherParameter weather; [FieldOffset(0x650)] public FxWindComputeParameter wind; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct StageCommonParameter { [FieldOffset(0x00)] public float deadline; [FieldOffset(0x04)] public float oceanSurface; [FieldOffset(0x08)] public float deadFallTime; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct StageCameraParameter { [FieldOffset(0x00)] public float zNear; [FieldOffset(0x04)] public float zFar; [FieldOffset(0x08)] public float fovy; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct StageTerrainPrecisionParameter { [FieldOffset(0x00)] public float heightRange; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct StageTerrainMaterialParameter { [FieldOffset(0x00)] public float uvScaleDetail; [FieldOffset(0x04)] public float uvScaleBase; [FieldOffset(0x08)] public float detailDistance; [FieldOffset(0x0C)] public float detailFadeRange; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct StageTerrainParameter { [FieldOffset(0x00)] public bool useHeightMapTerrain; [FieldOffset(0x01)] public bool useHalfPrecision; [FieldOffset(0x04)] public StageTerrainPrecisionParameter precision; [FieldOffset(0x08)] public int worldSize; [FieldOffset(0x0C)] public int heightMapTexelDensity; [FieldOffset(0x10)] public float heightScale; [FieldOffset(0x14)] public float smallestCellSize; [FieldOffset(0x18)] public float slopeClipThrethold; [FieldOffset(0x1C)] public Vector2 aabbMin; [FieldOffset(0x24)] public Vector2 aabbMax; [FieldOffset(0x2C)] public StageTerrainMaterialParameter material; [FieldOffset(0x3C)] public bool enableGbufferBlending; } [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct StageConfig { [FieldOffset(0x00)] public StageCommonParameter common; [FieldOffset(0x0C)] public StageCameraParameter camera; [FieldOffset(0x18)] public StageTerrainParameter terrain; } [StructLayout(LayoutKind.Explicit, Size = 0x1F0B0)] public struct Root { [FieldOffset(0x00)] public NeedleFxSceneConfig config; [FieldOffset(0x140)] public unsafe fixed byte /* NeedleFxParameter[16] */ _items[75520]; public unsafe NeedleFxParameter* items { get { fixed (byte* p_items = _items) return (NeedleFxParameter*)p_items; } } [FieldOffset(0x12840)] public unsafe fixed byte /* TimeProgressNeedleFxParam[24] */ _timeItems[38784]; public unsafe TimeProgressNeedleFxParam* timeItems { get { fixed (byte* p_timeItems = _timeItems) return (TimeProgressNeedleFxParam*)p_timeItems; } } [FieldOffset(0x1BFC0)] public unsafe fixed byte /* WeatherFxParameter[7] */ _weatherItems[12432]; public unsafe WeatherFxParameter* weatherItems { get { fixed (byte* p_weatherItems = _weatherItems) return (WeatherFxParameter*)p_weatherItems; } } [FieldOffset(0x1F050)] public StageConfig stageConfig; } } Library "GameData" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; public enum Status : sbyte { STATUS_ZERO_FILL = 0, STATUS_INITIALIZED = 1 } public enum Sequence : sbyte { Island1 = 0, Island2 = 1, Island3 = 2, Island4 = 3, Island5 = 4, FinalBossBefore = 5, FinalBossAfter = 6 } public enum SaveDataIcon : sbyte { IconNoData = 0, IconIsland1 = 1, IconIsland2 = 2, IconIsland3 = 3, IconIsland4 = 4, IconIsland5 = 5, IconLastBoss = 6, IconExtra = 7 } public enum AppVersion : byte { AppVersion_1_10 = 0, AppVersion_1_20 = 1, AppVersion_1_30 = 2, AppVersion_1_40 = 3 } [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct HeaderData { [FieldOffset(0x00)] public uint signature; [FieldOffset(0x04)] public byte version; [FieldOffset(0x05)] public Status status; [FieldOffset(0x06)] public byte config; [FieldOffset(0x07)] public Sequence sequence; [FieldOffset(0x08)] public uint playTime; [FieldOffset(0x0C)] public SaveDataIcon icon; [FieldOffset(0x0D)] public AppVersion appVersion; [FieldOffset(0x0E)] public byte config2; [FieldOffset(0x0F)] public byte reserved1; [FieldOffset(0x10)] public uint saveDate; [FieldOffset(0x14)] public byte index; [FieldOffset(0x18)] public unsafe fixed uint reserved[4]; } public enum GamePlayData_Status : sbyte { STATUS_NEWGAME = 0, STATUS_CONTINUE = 1 } public enum SequenceDeprecated : sbyte { SequenceDeprecated_Island1 = 0, SequenceDeprecated_Island2 = 1, SequenceDeprecated_Island3 = 2, SequenceDeprecated_Island4 = 3, SequenceDeprecated_Island5 = 4, SequenceDeprecated_FinalBossBefore = 5, SequenceDeprecated_FinalBossAfter = 6 } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct GamePlayData { [FieldOffset(0x00)] public GamePlayData_Status status; [FieldOffset(0x01)] public sbyte lastPlayedStageNo; [FieldOffset(0x02)] public byte flags; [FieldOffset(0x03)] public SequenceDeprecated sequence; [FieldOffset(0x10)] public Vector3 position; [FieldOffset(0x20)] public Quaternion rotation; [FieldOffset(0x30)] public uint day; [FieldOffset(0x34)] public uint hour; [FieldOffset(0x38)] public uint minute; [FieldOffset(0x3C)] public float second; [FieldOffset(0x40)] public byte character; [FieldOffset(0x41)] public byte reserved0; [FieldOffset(0x42)] public ushort reserved1; [FieldOffset(0x44)] public unsafe fixed uint reserved[3]; } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct CharacterData { [FieldOffset(0x00)] public ushort numRings; [FieldOffset(0x02)] public byte ringLevel; [FieldOffset(0x03)] public byte speedLevel; [FieldOffset(0x04)] public byte obtainChaosEmeralds; [FieldOffset(0x05)] public byte hasChaosEmeralds; [FieldOffset(0x06)] public unsafe fixed byte skillLevel[30]; [FieldOffset(0x24)] public byte skillPointOld; [FieldOffset(0x25)] public byte levelOld; [FieldOffset(0x26)] public ushort padding0; [FieldOffset(0x28)] public uint expPoint; [FieldOffset(0x2C)] public byte powerLevel; [FieldOffset(0x2D)] public byte guardLevel; [FieldOffset(0x2E)] public ushort boostGaugeLevel; [FieldOffset(0x30)] public uint numPowerSeeds; [FieldOffset(0x34)] public uint numGuardSeeds; [FieldOffset(0x38)] public ushort numFishCoins; [FieldOffset(0x3A)] public ushort numFishTokens; [FieldOffset(0x3C)] public ushort numGoldCards; [FieldOffset(0x3E)] public ushort numSlotStars; [FieldOffset(0x40)] public float quickCyloopGauge; [FieldOffset(0x44)] public uint practiceMaxCleared; [FieldOffset(0x48)] public uint practiceMaxCombos; [FieldOffset(0x4C)] public uint flags; [FieldOffset(0x50)] public short skillPoint; [FieldOffset(0x52)] public short level; [FieldOffset(0x54)] public uint dlcrsvExpPoint; [FieldOffset(0x58)] public uint dlcrsvNumPowerSeeds; [FieldOffset(0x5C)] public uint dlcrsvNumGuardSeeds; } [StructLayout(LayoutKind.Explicit, Size = 0x02)] public struct IslandMapGridData { [FieldOffset(0x00)] public byte x; [FieldOffset(0x01)] public byte y; } [StructLayout(LayoutKind.Explicit, Size = 0x112)] public struct IslandMapData { [FieldOffset(0x00)] public unsafe fixed byte /* IslandMapGridData[136] */ _grid[272]; public unsafe IslandMapGridData* grid { get { fixed (byte* p_grid = _grid) return (IslandMapGridData*)p_grid; } } [FieldOffset(0x110)] public ushort numReleaseGrids; } [StructLayout(LayoutKind.Explicit, Size = 0x140)] public struct IslandStageData { [FieldOffset(0x00)] public Vector3 destination; [FieldOffset(0x10)] public uint flags; [FieldOffset(0x14)] public IslandMapData map; [FieldOffset(0x128)] public unsafe fixed uint reserved[4]; } [StructLayout(LayoutKind.Explicit, Size = 0x640)] public struct IslandStageContainerData { [FieldOffset(0x00)] public unsafe fixed byte /* IslandStageData[5] */ _islands[1600]; public unsafe IslandStageData* islands { get { fixed (byte* p_islands = _islands) return (IslandStageData*)p_islands; } } } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct CyberStageData { [FieldOffset(0x00)] public ushort flags; [FieldOffset(0x04)] public uint bestTime; [FieldOffset(0x08)] public uint flags2; [FieldOffset(0x0C)] public unsafe fixed uint reserved[3]; } [StructLayout(LayoutKind.Explicit, Size = 0x300)] public struct CyberStageContainerData { [FieldOffset(0x00)] public unsafe fixed byte /* CyberStageData[32] */ _actStages[768]; public unsafe CyberStageData* actStages { get { fixed (byte* p_actStages = _actStages) return (CyberStageData*)p_actStages; } } } [StructLayout(LayoutKind.Explicit, Size = 0x120)] public struct FlagContainerData { [FieldOffset(0x00)] public unsafe fixed uint bitFlags[24]; [FieldOffset(0x60)] public unsafe fixed sbyte byteFlags[128]; [FieldOffset(0xE0)] public unsafe fixed uint intDatas[16]; } [StructLayout(LayoutKind.Explicit, Size = 0x1C00)] public struct WorldFlagData { [FieldOffset(0x00)] public unsafe fixed uint bitFlags[1024]; [FieldOffset(0x1000)] public unsafe fixed sbyte byteFlags[1024]; [FieldOffset(0x1400)] public unsafe fixed uint intDatas[512]; } [StructLayout(LayoutKind.Explicit, Size = 0xA800)] public struct WorldFlagContainerData { [FieldOffset(0x00)] public unsafe fixed byte /* WorldFlagData[5] */ _worldDatas[35840]; public unsafe WorldFlagData* worldDatas { get { fixed (byte* p_worldDatas = _worldDatas) return (WorldFlagData*)p_worldDatas; } } [FieldOffset(0x8C00)] public WorldFlagData debugWorldData; } [StructLayout(LayoutKind.Explicit, Size = 0xE00)] public struct ExtraFlagData { [FieldOffset(0x00)] public unsafe fixed uint bitFlags[512]; [FieldOffset(0x800)] public unsafe fixed sbyte byteFlags[512]; [FieldOffset(0xA00)] public unsafe fixed uint intDatas[256]; } [StructLayout(LayoutKind.Explicit, Size = 0x2A00)] public struct ExtraFlagContainerData { [FieldOffset(0x00)] public WorldFlagData worldData; [FieldOffset(0x1C00)] public ExtraFlagData extraData; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct ScoreAndRnakData { [FieldOffset(0x00)] public uint hightScore; [FieldOffset(0x04)] public ushort rank; [FieldOffset(0x06)] public ushort padding0; [FieldOffset(0x08)] public uint reserved0; } [StructLayout(LayoutKind.Explicit, Size = 0x960)] public struct ActionChainStruct { [FieldOffset(0x00)] public unsafe fixed byte /* ScoreAndRnakData[200] */ _hightState[2400]; public unsafe ScoreAndRnakData* hightState { get { fixed (byte* p_hightState = _hightState) return (ScoreAndRnakData*)p_hightState; } } } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct ExtraCharacterData { [FieldOffset(0x00)] public uint bossRushNumRings; [FieldOffset(0x04)] public float bossRushQuickCyloopGauge; [FieldOffset(0x08)] public uint bossRushFlags; [FieldOffset(0x0C)] public uint reserved3; [FieldOffset(0x10)] public uint reserved4; [FieldOffset(0x14)] public uint reserved5; [FieldOffset(0x18)] public uint reserved6; [FieldOffset(0x1C)] public uint reserved7; [FieldOffset(0x20)] public uint reserved8; [FieldOffset(0x24)] public uint reserved9; [FieldOffset(0x28)] public uint reserved10; [FieldOffset(0x2C)] public uint reserved11; [FieldOffset(0x30)] public uint reserved12; [FieldOffset(0x34)] public uint reserved13; [FieldOffset(0x38)] public uint reserved14; [FieldOffset(0x3C)] public uint reserved15; [FieldOffset(0x40)] public uint reserved16; [FieldOffset(0x44)] public uint reserved17; [FieldOffset(0x48)] public uint reserved18; [FieldOffset(0x4C)] public uint reserved19; } [StructLayout(LayoutKind.Explicit, Size = 0x260)] public struct ExtraCharacterContainerData { [FieldOffset(0x00)] public unsafe fixed byte /* CharacterData[3] */ _characters[288]; public unsafe CharacterData* characters { get { fixed (byte* p_characters = _characters) return (CharacterData*)p_characters; } } [FieldOffset(0x120)] public unsafe fixed byte /* ExtraCharacterData[4] */ _extras[320]; public unsafe ExtraCharacterData* extras { get { fixed (byte* p_extras = _extras) return (ExtraCharacterData*)p_extras; } } } [StructLayout(LayoutKind.Explicit, Size = 0x180)] public struct ExtraCyberStageContainerData { [FieldOffset(0x00)] public unsafe fixed byte /* CyberStageData[16] */ _actStages[384]; public unsafe CyberStageData* actStages { get { fixed (byte* p_actStages = _actStages) return (CyberStageData*)p_actStages; } } } [StructLayout(LayoutKind.Explicit, Size = 0x140)] public struct ExtraIslandStageContainerData { [FieldOffset(0x00)] public IslandStageData islands; } [StructLayout(LayoutKind.Explicit, Size = 0x92DD0)] public struct ReservedData { [FieldOffset(0x00)] public unsafe fixed byte reserved[601552]; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct StatValue { [FieldOffset(0x00)] public int value; [FieldOffset(0x04)] public bool assigned; } [StructLayout(LayoutKind.Explicit, Size = 0x6A08)] public struct StatsContainerData { [FieldOffset(0x00)] public unsafe fixed byte /* StatValue[3393] */ _stats[27144]; public unsafe StatValue* stats { get { fixed (byte* p_stats = _stats) return (StatValue*)p_stats; } } } public enum Type : sbyte { Sunny = 0, Cloudy = 1, Rainy = 2, SandStorm = 3, MeteorShower = 4, Num = 5 } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct WeatherTimerData { [FieldOffset(0x00)] public float duration; [FieldOffset(0x04)] public float time; } public enum WeatherBlockData_Type : sbyte { WeatherBlockData_Type_Sunny = 0, WeatherBlockData_Type_Cloudy = 1, WeatherBlockData_Type_Rainy = 2, WeatherBlockData_Type_SandStorm = 3, WeatherBlockData_Type_MeteorShower = 4, WeatherBlockData_Type_Num = 5 } public enum WeatherBlockData_Status : sbyte { None = 0, Wait = 1, Active = 2, External = 3 } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct WeatherBlockData { [FieldOffset(0x00)] public WeatherBlockData_Type weather; [FieldOffset(0x04)] public uint hour; [FieldOffset(0x08)] public uint minute; [FieldOffset(0x0C)] public float second; [FieldOffset(0x10)] public WeatherBlockData_Status status; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct WeatherData { [FieldOffset(0x00)] public Type currentWeather; [FieldOffset(0x01)] public Type prevWeather; [FieldOffset(0x04)] public WeatherTimerData timer; [FieldOffset(0x0C)] public WeatherBlockData block; [FieldOffset(0x20)] public int stageNo; [FieldOffset(0x24)] public unsafe fixed uint reserved[4]; } [StructLayout(LayoutKind.Explicit, Size = 0xA83D0)] public struct Root { [FieldOffset(0x00)] public HeaderData header; [FieldOffset(0x30)] public GamePlayData gameplay; [FieldOffset(0x80)] public CharacterData character; [FieldOffset(0xE0)] public IslandStageContainerData islands; [FieldOffset(0x720)] public CyberStageContainerData stages; [FieldOffset(0xA20)] public FlagContainerData flags; [FieldOffset(0xB40)] public WorldFlagContainerData worldFlags; [FieldOffset(0xB340)] public ExtraFlagContainerData extraFlags; [FieldOffset(0xDD40)] public ActionChainStruct actionChain; [FieldOffset(0xE6A0)] public ExtraCharacterContainerData extraCharacters; [FieldOffset(0xE900)] public ExtraCyberStageContainerData extraStages; [FieldOffset(0xEA80)] public ExtraIslandStageContainerData extraIslands; [FieldOffset(0xEBC0)] public ReservedData reserved; [FieldOffset(0xA1990)] public StatsContainerData stats; [FieldOffset(0xA8398)] public WeatherData weather; } } Library "StandardCameraConfig" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct StandardCameraCommonParameter { [FieldOffset(0x00)] public float distance; [FieldOffset(0x04)] public float distanceSuspensionK; [FieldOffset(0x08)] public float minElevation; [FieldOffset(0x0C)] public float maxElevation; [FieldOffset(0x10)] public float azimuthSensitivity; [FieldOffset(0x14)] public float elevationUpSensitivity; [FieldOffset(0x18)] public float elevationDownSensitivity; [FieldOffset(0x1C)] public float elevationOffset; [FieldOffset(0x20)] public float targetUpOffset; [FieldOffset(0x24)] public float targetMinUpOffsetLimit; [FieldOffset(0x28)] public float targetMaxUpOffsetLimit; [FieldOffset(0x2C)] public float targetMinUpOffsetLimitDistance; [FieldOffset(0x30)] public float targetMaxUpOffsetLimitDistance; [FieldOffset(0x34)] public float targetOffsetSuspensionK; [FieldOffset(0x38)] public float delayAllowDistance; [FieldOffset(0x3C)] public float delayLimitDistance; [FieldOffset(0x40)] public float delaySuspensionK; [FieldOffset(0x44)] public float autocontrolDisabledTime; [FieldOffset(0x48)] public float chaseSegmentSuspensionK; [FieldOffset(0x4C)] public float chaseSegmentShortenSpeed; [FieldOffset(0x50)] public int chaseSegmentMaxCount; [FieldOffset(0x54)] public float inertiaMinDecel; [FieldOffset(0x58)] public float inertiaOvershootAngle; [FieldOffset(0x5C)] public float resetSuspensionK; [FieldOffset(0x60)] public float downDirectionDotThreshold; [FieldOffset(0x64)] public float baseUpLeanRate; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct StandardCameraDashParameter { [FieldOffset(0x00)] public float minDistance; [FieldOffset(0x04)] public float maxDistance; [FieldOffset(0x08)] public float minDistanceAccel; [FieldOffset(0x0C)] public float maxDistanceAccel; [FieldOffset(0x10)] public float distanceSuspensionK; [FieldOffset(0x14)] public float elevationOffset; [FieldOffset(0x18)] public float azimuthSensitivity; [FieldOffset(0x1C)] public float targetOffsetSuspensionK; [FieldOffset(0x20)] public float targetUpOffset; [FieldOffset(0x24)] public float delayAllowDistance; [FieldOffset(0x28)] public float delayLimitDistance; [FieldOffset(0x2C)] public float delaySuspensionK; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct StandardCameraCyloopParameter { [FieldOffset(0x00)] public float minDistance; [FieldOffset(0x04)] public float maxDistance; [FieldOffset(0x08)] public float elevationOffset; [FieldOffset(0x0C)] public float azimuthSensitivity; [FieldOffset(0x10)] public float elevationUpSensitivity; [FieldOffset(0x14)] public float elevationDownSensitivity; [FieldOffset(0x18)] public float targetUpOffset; [FieldOffset(0x1C)] public float minDelayLimitDistance; [FieldOffset(0x20)] public float maxDelayLimitDistance; } [StructLayout(LayoutKind.Explicit, Size = 0x38)] public struct StandardCameraLockonParameter { [FieldOffset(0x00)] public float distance; [FieldOffset(0x04)] public float minElevation; [FieldOffset(0x08)] public float maxElevation; [FieldOffset(0x0C)] public float elevationOffset; [FieldOffset(0x10)] public float minElevationCyloop; [FieldOffset(0x14)] public float maxElevationCyloop; [FieldOffset(0x18)] public float elevationOffsetCyloop; [FieldOffset(0x1C)] public float targetUpOffset; [FieldOffset(0x20)] public float delayAllowDistance; [FieldOffset(0x24)] public float delayLimitDistance; [FieldOffset(0x28)] public float delaySuspensionK; [FieldOffset(0x2C)] public float panningSuspensionK; [FieldOffset(0x30)] public float interiorPanningDistance; [FieldOffset(0x34)] public float interiorPanningSuspensionK; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct StandardCameraWallParameter { [FieldOffset(0x00)] public float distance; [FieldOffset(0x04)] public float targetUpOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct StandardCameraLoopParameter { [FieldOffset(0x00)] public float azimuthSensitivity; [FieldOffset(0x04)] public float elevationUpSensitivity; [FieldOffset(0x08)] public float elevationDownSensitivity; [FieldOffset(0x0C)] public float targetUpOffset; [FieldOffset(0x10)] public float baseUpLeanRate; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct StandardCameraBattleParameter { [FieldOffset(0x00)] public float distance; [FieldOffset(0x04)] public float distanceSuspensionK; [FieldOffset(0x08)] public float elevationOffset; [FieldOffset(0x0C)] public float azimuthMinOffset; [FieldOffset(0x10)] public float azimuthMaxOffset; [FieldOffset(0x14)] public float azimuthMinOffsetDistance; [FieldOffset(0x18)] public float azimuthMaxOffsetDistance; [FieldOffset(0x1C)] public float azimuthSensitivity; [FieldOffset(0x20)] public float targetOffsetSuspensionK; [FieldOffset(0x24)] public float targetMinUpOffset; [FieldOffset(0x28)] public float targetMaxUpOffset; [FieldOffset(0x2C)] public float targetFrontOffset; [FieldOffset(0x30)] public float delayAllowDistance; [FieldOffset(0x34)] public float delayLimitDistance; [FieldOffset(0x38)] public float delaySuspensionK; [FieldOffset(0x3C)] public float manualControlTime; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct StandardCameraOptionParameter { [FieldOffset(0x00)] public float minManualRotationSpeed; [FieldOffset(0x04)] public float maxManualRotationSpeed; [FieldOffset(0x08)] public float minDistanceScale; [FieldOffset(0x0C)] public float maxDistanceScale; [FieldOffset(0x10)] public float maxElevationAddOffset; [FieldOffset(0x14)] public float minTargetUpOffsetScale; [FieldOffset(0x18)] public float maxTargetUpOffsetScale; [FieldOffset(0x1C)] public float minFovyRate; [FieldOffset(0x20)] public float minLimitFovy; } [StructLayout(LayoutKind.Explicit, Size = 0x2B0)] public struct Root { [FieldOffset(0x00)] public StandardCameraCommonParameter common; [FieldOffset(0x68)] public StandardCameraDashParameter dash; [FieldOffset(0x98)] public StandardCameraCyloopParameter cyloop; [FieldOffset(0xBC)] public StandardCameraCyloopParameter cyloopSnipe; [FieldOffset(0xE0)] public StandardCameraLockonParameter lockon; [FieldOffset(0x118)] public StandardCameraLockonParameter lockonCharger; [FieldOffset(0x150)] public StandardCameraLockonParameter lockonSpider; [FieldOffset(0x188)] public StandardCameraLockonParameter lockonDaruma; [FieldOffset(0x1C0)] public StandardCameraLockonParameter lockonNinja; [FieldOffset(0x1F8)] public StandardCameraLockonParameter lockonSumo; [FieldOffset(0x230)] public StandardCameraWallParameter wall; [FieldOffset(0x238)] public StandardCameraLoopParameter loop; [FieldOffset(0x24C)] public StandardCameraBattleParameter battle; [FieldOffset(0x28C)] public StandardCameraOptionParameter option; } } Library "PhotoModeParameters" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PhotoModeCameraParameters { [FieldOffset(0x00)] public float translationLimit; [FieldOffset(0x04)] public float translationSpeedXZ; [FieldOffset(0x08)] public float translationSpeedY; [FieldOffset(0x0C)] public float elevLimit; [FieldOffset(0x10)] public float rotationSpeed; [FieldOffset(0x14)] public float rollRange; [FieldOffset(0x18)] public float rollSpeed; [FieldOffset(0x1C)] public float fovyRange; [FieldOffset(0x20)] public float fovySpeed; [FieldOffset(0x24)] public float speedRatioFast; [FieldOffset(0x28)] public float speedRatioSlow; [FieldOffset(0x2C)] public float distance; } [StructLayout(LayoutKind.Explicit, Size = 0x3C)] public struct PhotoModeFilterParameters { [FieldOffset(0x00)] public float sepiaSaturationOffset; [FieldOffset(0x04)] public float sepiaColorizeRate; [FieldOffset(0x08)] public float sepiaColorizeHue; [FieldOffset(0x0C)] public float increaseSaturationOffset; [FieldOffset(0x10)] public int warmColorROffset; [FieldOffset(0x14)] public int warmColorGOffset; [FieldOffset(0x18)] public int warmColorBOffset; [FieldOffset(0x1C)] public int coldColorROffset; [FieldOffset(0x20)] public int coldColorGOffset; [FieldOffset(0x24)] public int coldColorBOffset; [FieldOffset(0x28)] public float retroContrastOffset; [FieldOffset(0x2C)] public int retroROffset; [FieldOffset(0x30)] public int retroGOffset; [FieldOffset(0x34)] public int retroBOffset; [FieldOffset(0x38)] public float retroSaturationOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x6C)] public struct Root { [FieldOffset(0x00)] public PhotoModeCameraParameters camera; [FieldOffset(0x30)] public PhotoModeFilterParameters filter; } } Library "SonicParameters" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamOffensive { [FieldOffset(0x00)] public ushort pointMin; [FieldOffset(0x02)] public ushort pointMax; [FieldOffset(0x04)] public float damageRandomRate; [FieldOffset(0x08)] public float damageRandomRateSS; [FieldOffset(0x0C)] public float shapeDamageRate; [FieldOffset(0x10)] public float shapeStunRate; [FieldOffset(0x14)] public float shapeStaggerRate; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDefensive { [FieldOffset(0x00)] public byte rateMin; [FieldOffset(0x01)] public byte rateMax; [FieldOffset(0x02)] public ushort infimumDropRings; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamAttackCommon { [FieldOffset(0x00)] public PlayerParamOffensive offensive; [FieldOffset(0x18)] public PlayerParamDefensive defensive; [FieldOffset(0x1C)] public float criticalDamageRate; [FieldOffset(0x20)] public float criticalRate; [FieldOffset(0x24)] public float criticalRateSS; [FieldOffset(0x28)] public float downedDamageRate; } public enum HitSE : sbyte { SE_None = -1, Weak = 0, Strong = 1, VeryStrong = 2 } [StructLayout(LayoutKind.Explicit, Size = 8)] public struct UnmanagedString { [FieldOffset(0)] public long pValue; public string Value { get { if (pValue == 0) return string.Empty; return Marshal.PtrToStringAnsi((nint)pValue); } set => pValue = (long)Marshal.StringToHGlobalAnsi(value); } public UnmanagedString(string in_value) { Value = in_value; } public static implicit operator UnmanagedString(string in_value) { return new UnmanagedString(in_value); } public static bool operator ==(UnmanagedString in_left, string in_right) { return in_left.Value == in_right; } public static bool operator !=(UnmanagedString in_left, string in_right) { return !(in_left == in_right); } public override bool Equals(object in_obj) { if (in_obj is string str) return Value == str; return base.Equals(in_obj); } public override int GetHashCode() { return Value.GetHashCode(); } public override string ToString() { return Value; } } [StructLayout(LayoutKind.Explicit, Size = 0x160)] public struct PlayerParamAttackData { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float damageRateSS; [FieldOffset(0x08)] public ushort pointMin; [FieldOffset(0x0A)] public ushort pointMax; [FieldOffset(0x0C)] public float damageRateAcceleMode; [FieldOffset(0x10)] public float damageRateManual; [FieldOffset(0x14)] public float stunPoint; [FieldOffset(0x18)] public float staggerPoint; [FieldOffset(0x20)] public Vector3 velocity; [FieldOffset(0x30)] public float velocityKeepTime; [FieldOffset(0x34)] public float addComboValue; [FieldOffset(0x38)] public float addComboValueAccele; [FieldOffset(0x3C)] public float addComboValueSS; [FieldOffset(0x40)] public float addComboValueAcceleSS; [FieldOffset(0x44)] public float addQuickCyloopEnergy; [FieldOffset(0x48)] public float addQuickCyloopEnergyAccele; [FieldOffset(0x4C)] public float addQuickCyloopEnergySS; [FieldOffset(0x50)] public float addQuickCyloopEnergyAcceleSS; [FieldOffset(0x54)] public float addQuickCyloopEnergyGuard; [FieldOffset(0x58)] public float addQuickCyloopEnergyAcceleGuard; [FieldOffset(0x60)] public Vector3 gimmickVelocity; [FieldOffset(0x70)] public float ignoreTime; [FieldOffset(0x74)] public uint attributes; [FieldOffset(0x78)] public HitSE se; [FieldOffset(0x80)] public UnmanagedString hitEffectName; [FieldOffset(0x90)] public UnmanagedString hitEffectNameSS; [FieldOffset(0xA0)] public UnmanagedString hitStopName; [FieldOffset(0xB0)] public UnmanagedString hitStopNameDead; [FieldOffset(0xC0)] public UnmanagedString hitStopNameDeadBoss; [FieldOffset(0xD0)] public UnmanagedString hitStopNameSS; [FieldOffset(0xE0)] public UnmanagedString hitStopNameDeadSS; [FieldOffset(0xF0)] public UnmanagedString hitCameraShakeName; [FieldOffset(0x100)] public UnmanagedString hitCameraShakeNameDead; [FieldOffset(0x110)] public UnmanagedString hitCameraShakeNameDeadBoss; [FieldOffset(0x120)] public UnmanagedString hitCameraShakeNameSS; [FieldOffset(0x130)] public UnmanagedString hitCameraShakeNameDeadSS; [FieldOffset(0x140)] public UnmanagedString hitVibrationName; [FieldOffset(0x150)] public UnmanagedString hitVibrationNameSS; } [StructLayout(LayoutKind.Explicit, Size = 0x4A70)] public struct PlayerParamAttack { [FieldOffset(0x00)] public PlayerParamAttackCommon common; [FieldOffset(0x30)] public PlayerParamAttackData spinAttack; [FieldOffset(0x190)] public PlayerParamAttackData spinDash; [FieldOffset(0x2F0)] public PlayerParamAttackData homingAttack; [FieldOffset(0x450)] public PlayerParamAttackData homingAttackAir; [FieldOffset(0x5B0)] public PlayerParamAttackData pursuitKick; [FieldOffset(0x710)] public PlayerParamAttackData stomping; [FieldOffset(0x870)] public PlayerParamAttackData stompingAttack; [FieldOffset(0x9D0)] public PlayerParamAttackData boundStompingLast; [FieldOffset(0xB30)] public PlayerParamAttackData sliding; [FieldOffset(0xC90)] public PlayerParamAttackData loopKick; [FieldOffset(0xDF0)] public PlayerParamAttackData crasher; [FieldOffset(0xF50)] public PlayerParamAttackData spinSlashHoming; [FieldOffset(0x10B0)] public PlayerParamAttackData spinSlash; [FieldOffset(0x1210)] public PlayerParamAttackData spinSlashLast; [FieldOffset(0x1370)] public PlayerParamAttackData sonicBoom; [FieldOffset(0x14D0)] public PlayerParamAttackData crossSlash; [FieldOffset(0x1630)] public PlayerParamAttackData homingShot; [FieldOffset(0x1790)] public PlayerParamAttackData chargeAttack; [FieldOffset(0x18F0)] public PlayerParamAttackData chargeAttackLast; [FieldOffset(0x1A50)] public PlayerParamAttackData cyloop; [FieldOffset(0x1BB0)] public PlayerParamAttackData cyloopQuick; [FieldOffset(0x1D10)] public PlayerParamAttackData cyloopAerial; [FieldOffset(0x1E70)] public PlayerParamAttackData accele1; [FieldOffset(0x1FD0)] public PlayerParamAttackData accele2; [FieldOffset(0x2130)] public PlayerParamAttackData aerialAccele1; [FieldOffset(0x2290)] public PlayerParamAttackData aerialAccele2; [FieldOffset(0x23F0)] public PlayerParamAttackData comboFinish; [FieldOffset(0x2550)] public PlayerParamAttackData comboFinishF; [FieldOffset(0x26B0)] public PlayerParamAttackData comboFinishB; [FieldOffset(0x2810)] public PlayerParamAttackData comboFinishL; [FieldOffset(0x2970)] public PlayerParamAttackData comboFinishR; [FieldOffset(0x2AD0)] public PlayerParamAttackData acceleComboFinish; [FieldOffset(0x2C30)] public PlayerParamAttackData acceleComboFinishF; [FieldOffset(0x2D90)] public PlayerParamAttackData acceleComboFinishB; [FieldOffset(0x2EF0)] public PlayerParamAttackData acceleComboFinishL; [FieldOffset(0x3050)] public PlayerParamAttackData acceleComboFinishR; [FieldOffset(0x31B0)] public PlayerParamAttackData smash; [FieldOffset(0x3310)] public PlayerParamAttackData smashLast; [FieldOffset(0x3470)] public PlayerParamAttackData slingShot; [FieldOffset(0x35D0)] public PlayerParamAttackData knucklesPunch1; [FieldOffset(0x3730)] public PlayerParamAttackData knucklesPunch2; [FieldOffset(0x3890)] public PlayerParamAttackData knucklesUppercut; [FieldOffset(0x39F0)] public PlayerParamAttackData knucklesHeatKnuckle; [FieldOffset(0x3B50)] public PlayerParamAttackData knucklesHeatKnuckleLast; [FieldOffset(0x3CB0)] public PlayerParamAttackData amyTarotAttack; [FieldOffset(0x3E10)] public PlayerParamAttackData amyTarotAttack2; [FieldOffset(0x3F70)] public PlayerParamAttackData amyTarotRolling; [FieldOffset(0x40D0)] public PlayerParamAttackData amyCharmAttack; [FieldOffset(0x4230)] public PlayerParamAttackData amyTarotBoost; [FieldOffset(0x4390)] public PlayerParamAttackData tailsSpanner; [FieldOffset(0x44F0)] public PlayerParamAttackData tailsSpannerFloat; [FieldOffset(0x4650)] public PlayerParamAttackData tailsPowerBoost; [FieldOffset(0x47B0)] public PlayerParamAttackData tailsWaveCannon; [FieldOffset(0x4910)] public PlayerParamAttackData tailsWaveCannonFinish; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamWaterAct { [FieldOffset(0x00)] public float resistRate; [FieldOffset(0x04)] public float breatheBrake; [FieldOffset(0x08)] public float breatheTime; [FieldOffset(0x0C)] public float breatheGravity; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBaseJump { [FieldOffset(0x00)] public float baseSpeed; [FieldOffset(0x04)] public float upSpeed; [FieldOffset(0x08)] public float upSpeedAir; [FieldOffset(0x0C)] public float edgeSpeed; [FieldOffset(0x10)] public float airActionTime; [FieldOffset(0x14)] public float wallMoveTime; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamBallMove { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float slidePower; [FieldOffset(0x08)] public float brakeForce; [FieldOffset(0x0C)] public float slidePowerSlalom; [FieldOffset(0x10)] public float brakeForceSlalom; [FieldOffset(0x14)] public float releaseSpeed; [FieldOffset(0x18)] public bool useInput; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamLocusData { [FieldOffset(0x00)] public float width; [FieldOffset(0x04)] public float distance; [FieldOffset(0x08)] public float u0; [FieldOffset(0x0C)] public float u1; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamLocus { [FieldOffset(0x00)] public unsafe fixed byte /* PlayerParamLocusData[4] */ _data[64]; public unsafe PlayerParamLocusData* data { get { fixed (byte* p_data = _data) return (PlayerParamLocusData*)p_data; } } } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAuraTrain { [FieldOffset(0x00)] public float effectSpanTime; [FieldOffset(0x04)] public float effectLifeTime; [FieldOffset(0x08)] public float effectOffsetDistance; [FieldOffset(0x0C)] public float effectOverlapDistance; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamLevel { [FieldOffset(0x00)] public byte ringsLevel; [FieldOffset(0x01)] public byte speedLevel; [FieldOffset(0x02)] public byte offensiveLevel; [FieldOffset(0x03)] public byte defensiveLevel; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamBarrierWall { [FieldOffset(0x00)] public float coolTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamDamageRateLevel { [FieldOffset(0x00)] public unsafe fixed float rates[5]; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerParamDamageRate { [FieldOffset(0x00)] public unsafe fixed byte /* PlayerParamDamageRateLevel[4] */ _diffculties[80]; public unsafe PlayerParamDamageRateLevel* diffculties { get { fixed (byte* p_diffculties = _diffculties) return (PlayerParamDamageRateLevel*)p_diffculties; } } } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamAcceleMode { [FieldOffset(0x00)] public float declineSpeed; [FieldOffset(0x04)] public float declineSpeedAccele; [FieldOffset(0x08)] public float lossDamaged; [FieldOffset(0x0C)] public float lossDamagedAccele; [FieldOffset(0x10)] public uint comboRateAccele; } [StructLayout(LayoutKind.Explicit, Size = 0x4B70)] public struct CommonPackage { [FieldOffset(0x00)] public PlayerParamAttack attack; [FieldOffset(0x4A70)] public PlayerParamWaterAct wateract; [FieldOffset(0x4A80)] public PlayerParamBaseJump basejump; [FieldOffset(0x4A98)] public PlayerParamBallMove ballmove; [FieldOffset(0x4AB4)] public PlayerParamLocus locus; [FieldOffset(0x4AF4)] public PlayerParamAuraTrain auratrain; [FieldOffset(0x4B04)] public PlayerParamLevel level; [FieldOffset(0x4B08)] public PlayerParamBarrierWall barrierWall; [FieldOffset(0x4B0C)] public PlayerParamDamageRate damageRate; [FieldOffset(0x4B5C)] public PlayerParamAcceleMode acceleMode; } public enum Condition : sbyte { Time = 0, Animation = 1 } public enum Shape : sbyte { Sphere = 0, Cylinder = 1, Box = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamAttackCollider { [FieldOffset(0x00)] public Condition condition; [FieldOffset(0x01)] public sbyte count; [FieldOffset(0x04)] public float spanTime; [FieldOffset(0x08)] public Shape shape; [FieldOffset(0x10)] public Vector3 shapeSize; [FieldOffset(0x20)] public Vector3 shapeOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamAcceleCombo { [FieldOffset(0x00)] public PlayerParamAttackCollider hit; [FieldOffset(0x30)] public float motionSpeedRatio; [FieldOffset(0x34)] public float motionSpeedRatioAccele; } [StructLayout(LayoutKind.Explicit, Size = 0xC0)] public struct PlayerParamAcceleComboSet { [FieldOffset(0x00)] public PlayerParamAcceleCombo sonic; [FieldOffset(0x40)] public PlayerParamAcceleCombo superSonic1; [FieldOffset(0x80)] public PlayerParamAcceleCombo superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamLoopKick { [FieldOffset(0x00)] public float loopRadius; [FieldOffset(0x04)] public float loopTime; [FieldOffset(0x08)] public float loopSpeedCurveRatio; [FieldOffset(0x0C)] public float loopEndStopTime; [FieldOffset(0x10)] public float loopEndSpeed; [FieldOffset(0x14)] public float kickSpeed; [FieldOffset(0x18)] public float failSafeTime; [FieldOffset(0x20)] public Vector3 offset; [FieldOffset(0x30)] public UnmanagedString cameraName; } [StructLayout(LayoutKind.Explicit, Size = 0xC0)] public struct PlayerParamLoopKickSet { [FieldOffset(0x00)] public PlayerParamLoopKick sonic; [FieldOffset(0x40)] public PlayerParamLoopKick superSonic1; [FieldOffset(0x80)] public PlayerParamLoopKick superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0x90)] public struct PlayerParamCrasher { [FieldOffset(0x00)] public float startWait; [FieldOffset(0x04)] public unsafe fixed float distanceRatios[5]; [FieldOffset(0x18)] public unsafe fixed float angles[5]; [FieldOffset(0x2C)] public unsafe fixed float radii[5]; [FieldOffset(0x40)] public float distanceMax; [FieldOffset(0x44)] public float zigzagBeginOneStepTime; [FieldOffset(0x48)] public float zigzagEndOneStepTime; [FieldOffset(0x4C)] public float crasherSpeed; [FieldOffset(0x50)] public float failSafeTime; [FieldOffset(0x54)] public float cameraDistance; [FieldOffset(0x58)] public float cameraOffsetElevation; [FieldOffset(0x5C)] public float cameraOffsetAzimuth; [FieldOffset(0x60)] public float cameraRoll; [FieldOffset(0x70)] public Vector3 offset; [FieldOffset(0x80)] public UnmanagedString cameraName; } [StructLayout(LayoutKind.Explicit, Size = 0x1B0)] public struct PlayerParamCrasherSet { [FieldOffset(0x00)] public PlayerParamCrasher sonic; [FieldOffset(0x90)] public PlayerParamCrasher superSonic1; [FieldOffset(0x120)] public PlayerParamCrasher superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0xD0)] public struct PlayerParamSpinSlash { [FieldOffset(0x00)] public PlayerParamAttackCollider hit; [FieldOffset(0x30)] public PlayerParamAttackCollider hitLast; [FieldOffset(0x60)] public float chargeTime; [FieldOffset(0x64)] public float homingSpeed; [FieldOffset(0x68)] public float bounceTime; [FieldOffset(0x6C)] public float radius; [FieldOffset(0x70)] public float slashTime; [FieldOffset(0x74)] public sbyte numSlashs; [FieldOffset(0x78)] public float angle; [FieldOffset(0x7C)] public float lastHitTime; [FieldOffset(0x80)] public float slowRatio0; [FieldOffset(0x84)] public float slowRatio1; [FieldOffset(0x90)] public Vector3 offset; [FieldOffset(0xA0)] public UnmanagedString cameraName; [FieldOffset(0xB0)] public UnmanagedString cameraNamePost; [FieldOffset(0xC0)] public UnmanagedString cameraShakeName; } [StructLayout(LayoutKind.Explicit, Size = 0x270)] public struct PlayerParamSpinSlashSet { [FieldOffset(0x00)] public PlayerParamSpinSlash sonic; [FieldOffset(0xD0)] public PlayerParamSpinSlash superSonic1; [FieldOffset(0x1A0)] public PlayerParamSpinSlash superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct PlayerParamChargeAttack { [FieldOffset(0x00)] public PlayerParamAttackCollider hit; [FieldOffset(0x30)] public PlayerParamAttackCollider hitLast; [FieldOffset(0x60)] public float ignoreSwingingTime; [FieldOffset(0x64)] public float riseSlowRatio; [FieldOffset(0x68)] public float riseTime; [FieldOffset(0x6C)] public float riseDistance; [FieldOffset(0x70)] public float preRiseDistance; [FieldOffset(0x74)] public float postRiseDistance; [FieldOffset(0x78)] public float lastVelocity; [FieldOffset(0x7C)] public float spiralRadius; [FieldOffset(0x80)] public float spiralRadiusEaseInTime; [FieldOffset(0x84)] public float spiralRadiusEaseOutTime; [FieldOffset(0x88)] public float spiralAngularSpeed; [FieldOffset(0x8C)] public float lastHitTime; [FieldOffset(0x90)] public UnmanagedString cameraName; } [StructLayout(LayoutKind.Explicit, Size = 0x1E0)] public struct PlayerParamChargeAttackSet { [FieldOffset(0x00)] public PlayerParamChargeAttack sonic; [FieldOffset(0xA0)] public PlayerParamChargeAttack superSonic1; [FieldOffset(0x140)] public PlayerParamChargeAttack superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0xD0)] public struct PlayerParamStompingAttack { [FieldOffset(0x00)] public PlayerParamAttackCollider hit; [FieldOffset(0x30)] public PlayerParamAttackCollider hitLast; [FieldOffset(0x60)] public float riseTime; [FieldOffset(0x64)] public float flipSpeed; [FieldOffset(0x68)] public float motionTime; [FieldOffset(0x6C)] public float lastHitTime; [FieldOffset(0x70)] public float slowRatio; [FieldOffset(0x74)] public float minPressTime; [FieldOffset(0x78)] public float minPressTimeHeight; [FieldOffset(0x7C)] public float maxPressTime; [FieldOffset(0x80)] public float maxPressTimeHeight; [FieldOffset(0x90)] public Vector3 offset; [FieldOffset(0xA0)] public Vector3 offsetAsura; [FieldOffset(0xB0)] public UnmanagedString cameraName; [FieldOffset(0xC0)] public UnmanagedString cameraNameBarrage; } [StructLayout(LayoutKind.Explicit, Size = 0x270)] public struct PlayerParamStompingAttackSet { [FieldOffset(0x00)] public PlayerParamStompingAttack sonic; [FieldOffset(0xD0)] public PlayerParamStompingAttack superSonic1; [FieldOffset(0x1A0)] public PlayerParamStompingAttack superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamComboFinish { [FieldOffset(0x00)] public PlayerParamAttackCollider hit; [FieldOffset(0x30)] public float ignoreSwingingTime; } [StructLayout(LayoutKind.Explicit, Size = 0xC0)] public struct PlayerParamComboFinishSet { [FieldOffset(0x00)] public PlayerParamComboFinish sonic; [FieldOffset(0x40)] public PlayerParamComboFinish superSonic1; [FieldOffset(0x80)] public PlayerParamComboFinish superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamSonicBoom { [FieldOffset(0x00)] public float waitTime; [FieldOffset(0x04)] public float spanTime; [FieldOffset(0x08)] public float fallSpeed; [FieldOffset(0x0C)] public float autoContinueTime; [FieldOffset(0x10)] public float speed; [FieldOffset(0x14)] public float maxSpeed; [FieldOffset(0x18)] public float accele; [FieldOffset(0x1C)] public float slowRatio; [FieldOffset(0x20)] public Vector3 offset; [FieldOffset(0x30)] public UnmanagedString cameraName; } [StructLayout(LayoutKind.Explicit, Size = 0xC0)] public struct PlayerParamSonicBoomSet { [FieldOffset(0x00)] public PlayerParamSonicBoom sonic; [FieldOffset(0x40)] public PlayerParamSonicBoom superSonic1; [FieldOffset(0x80)] public PlayerParamSonicBoom superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0xB0)] public struct PlayerParamCrossSlash { [FieldOffset(0x00)] public float spanTime; [FieldOffset(0x04)] public float attackTime; [FieldOffset(0x08)] public float moveAngle; [FieldOffset(0x0C)] public float stopTime; [FieldOffset(0x10)] public float slowRatio; [FieldOffset(0x14)] public float spinPhase; [FieldOffset(0x18)] public float spinRadius; [FieldOffset(0x1C)] public float spinSpeed; [FieldOffset(0x20)] public unsafe fixed float spawnDelayTime[2]; [FieldOffset(0x30)] public unsafe fixed byte /* Vector3[2] */ _spawnLocalTranslation[32]; public unsafe Vector3* spawnLocalTranslation { get { fixed (byte* p_spawnLocalTranslation = _spawnLocalTranslation) return (Vector3*)p_spawnLocalTranslation; } } [FieldOffset(0x50)] public unsafe fixed byte /* Vector3[2] */ _spawnLocalAngle[32]; public unsafe Vector3* spawnLocalAngle { get { fixed (byte* p_spawnLocalAngle = _spawnLocalAngle) return (Vector3*)p_spawnLocalAngle; } } [FieldOffset(0x70)] public float speed; [FieldOffset(0x74)] public float maxSpeed; [FieldOffset(0x78)] public float accele; [FieldOffset(0x80)] public Vector3 offset; [FieldOffset(0x90)] public UnmanagedString cameraName; [FieldOffset(0xA0)] public UnmanagedString launchCameraShakeName; } [StructLayout(LayoutKind.Explicit, Size = 0x210)] public struct PlayerParamCrossSlashSet { [FieldOffset(0x00)] public PlayerParamCrossSlash sonic; [FieldOffset(0xB0)] public PlayerParamCrossSlash superSonic1; [FieldOffset(0x160)] public PlayerParamCrossSlash superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0x90)] public struct PlayerParamHomingShot { [FieldOffset(0x00)] public float appearTime; [FieldOffset(0x04)] public float appearPhaseTime; [FieldOffset(0x08)] public float spinRadius; [FieldOffset(0x0C)] public float spinSpeed; [FieldOffset(0x10)] public float spinSpeedPostLaunch; [FieldOffset(0x14)] public float chargeTime; [FieldOffset(0x18)] public float spawnTime; [FieldOffset(0x1C)] public float launchPreWaitTime; [FieldOffset(0x20)] public float spanTime; [FieldOffset(0x24)] public bool launchRandomize; [FieldOffset(0x28)] public float launchWaitTime; [FieldOffset(0x2C)] public float beginAngleX; [FieldOffset(0x30)] public float tangent0; [FieldOffset(0x34)] public float tangent1; [FieldOffset(0x38)] public float spiralWaitTime; [FieldOffset(0x3C)] public float spiralAngularSpeed; [FieldOffset(0x40)] public float spiralAngularSpeedMax; [FieldOffset(0x44)] public float spiralAngularSpeedAccele; [FieldOffset(0x48)] public byte numShots; [FieldOffset(0x4C)] public float speed; [FieldOffset(0x50)] public float maxSpeed; [FieldOffset(0x54)] public float accele; [FieldOffset(0x58)] public float whiteoutBeginTime; [FieldOffset(0x5C)] public float whiteoutFadeOutTime; [FieldOffset(0x60)] public float whiteoutFadingTime; [FieldOffset(0x64)] public float whiteoutFadeInTime; [FieldOffset(0x70)] public Vector3 offset; [FieldOffset(0x80)] public UnmanagedString cameraName; } [StructLayout(LayoutKind.Explicit, Size = 0x1B0)] public struct PlayerParamHomingShotSet { [FieldOffset(0x00)] public PlayerParamHomingShot sonic; [FieldOffset(0x90)] public PlayerParamHomingShot superSonic1; [FieldOffset(0x120)] public PlayerParamHomingShot superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0x160)] public struct PlayerParamSmash { [FieldOffset(0x00)] public PlayerParamAttackCollider hit1; [FieldOffset(0x30)] public PlayerParamAttackCollider hit2; [FieldOffset(0x60)] public unsafe fixed byte /* Vector3[16] */ _offsets[256]; public unsafe Vector3* offsets { get { fixed (byte* p_offsets = _offsets) return (Vector3*)p_offsets; } } } [StructLayout(LayoutKind.Explicit, Size = 0x420)] public struct PlayerParamSmashSet { [FieldOffset(0x00)] public PlayerParamSmash sonic; [FieldOffset(0x160)] public PlayerParamSmash superSonic1; [FieldOffset(0x2C0)] public PlayerParamSmash superSonic2; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamBehind { [FieldOffset(0x00)] public float moveTime; [FieldOffset(0x04)] public float moveTimeSS; [FieldOffset(0x08)] public float tangentScale; [FieldOffset(0x0C)] public float waitTime; [FieldOffset(0x10)] public float cameraTurnRatio; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamComboCommon { [FieldOffset(0x00)] public float longPressTime; } public enum ComboMoveType : byte { Homing = 0, Step = 1, None = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamComboMove { [FieldOffset(0x00)] public ComboMoveType moveType; [FieldOffset(0x04)] public float moveInitialSpeed; [FieldOffset(0x08)] public float moveMaxSpeed; [FieldOffset(0x0C)] public float moveAccele; [FieldOffset(0x10)] public float timeout; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct PlayerParamComboMoveCorrection { [FieldOffset(0x00)] public float moveSpeed; [FieldOffset(0x04)] public float rotateSpeed; } public enum Action : sbyte { Root = 0, HomingAttack = 1, AerialHomingAttack = 2, Pursuit = 3, Stomping = 4, LoopKick = 5, Crasher = 6, SpinSlash = 7, SonicBoom = 8, CrossSlash = 9, HomingShot = 10, ChargeAttack = 11, QuickCyloop = 12, AerialQuickCyloop = 13, AcceleCombo1 = 14, AcceleCombo2 = 15, AcceleCombo3 = 16, AcceleCombo4 = 17, AerialAcceleCombo1 = 18, AerialAcceleCombo2 = 19, AerialAcceleCombo3 = 20, AerialAcceleCombo4 = 21, ComboFinish = 22, SpinJump = 23, Smash = 24, Behind = 25, Guarded = 26, Avoid = 27, AirBoost = 28, AfterAirBoost = 29, KnucklesPunch1 = 30, KnucklesPunch2 = 31, KnucklesUppercut = 32, KnucklesCyKnuckle = 33, KnucklesHeatKnuckle = 34, AmyTarotAttack = 35, AmyTarotAttack2 = 36, AmyTarotRolling = 37, AmyCyHammer = 38, AmyCharmAttack = 39, TailsSpanner = 40, ActionNum = 41 } [StructLayout(LayoutKind.Explicit, Size = 0x12)] public struct PlayerParamComboTransit { [FieldOffset(0x00)] public unsafe fixed byte /* Action[6] */ _transitExistTarget[6]; public unsafe Action* transitExistTarget { get { fixed (byte* p_transitExistTarget = _transitExistTarget) return (Action*)p_transitExistTarget; } } [FieldOffset(0x06)] public unsafe fixed byte /* Action[6] */ _transitInAir[6]; public unsafe Action* transitInAir { get { fixed (byte* p_transitInAir = _transitInAir) return (Action*)p_transitInAir; } } [FieldOffset(0x0C)] public unsafe fixed byte /* Action[6] */ _transitNotExistTarget[6]; public unsafe Action* transitNotExistTarget { get { fixed (byte* p_transitNotExistTarget = _transitNotExistTarget) return (Action*)p_transitNotExistTarget; } } } [StructLayout(LayoutKind.Explicit, Size = 0x2AC)] public struct PlayerParamComboTransitTable { [FieldOffset(0x00)] public PlayerParamComboTransit root; [FieldOffset(0x12)] public PlayerParamComboTransit homingAttack; [FieldOffset(0x24)] public PlayerParamComboTransit aerialHoming; [FieldOffset(0x36)] public PlayerParamComboTransit pursuit; [FieldOffset(0x48)] public PlayerParamComboTransit stomping; [FieldOffset(0x5A)] public PlayerParamComboTransit loopKick; [FieldOffset(0x6C)] public PlayerParamComboTransit crasher; [FieldOffset(0x7E)] public PlayerParamComboTransit spinSlash; [FieldOffset(0x90)] public PlayerParamComboTransit sonicBoom; [FieldOffset(0xA2)] public PlayerParamComboTransit crossSlash; [FieldOffset(0xB4)] public PlayerParamComboTransit homingShot; [FieldOffset(0xC6)] public PlayerParamComboTransit chargeAttack; [FieldOffset(0xD8)] public PlayerParamComboTransit quickCyloop; [FieldOffset(0xEA)] public PlayerParamComboTransit aerialQuickCyloop; [FieldOffset(0xFC)] public PlayerParamComboTransit acceleCombo1; [FieldOffset(0x10E)] public PlayerParamComboTransit acceleCombo2; [FieldOffset(0x120)] public PlayerParamComboTransit acceleCombo3; [FieldOffset(0x132)] public PlayerParamComboTransit acceleCombo4; [FieldOffset(0x144)] public PlayerParamComboTransit aerialAcceleCombo1; [FieldOffset(0x156)] public PlayerParamComboTransit aerialAcceleCombo2; [FieldOffset(0x168)] public PlayerParamComboTransit aerialAcceleCombo3; [FieldOffset(0x17A)] public PlayerParamComboTransit aerialAcceleCombo4; [FieldOffset(0x18C)] public PlayerParamComboTransit behind; [FieldOffset(0x19E)] public PlayerParamComboTransit guarded; [FieldOffset(0x1B0)] public PlayerParamComboTransit avoid; [FieldOffset(0x1C2)] public PlayerParamComboTransit airBoost; [FieldOffset(0x1D4)] public PlayerParamComboTransit afterAirBoost; [FieldOffset(0x1E6)] public PlayerParamComboTransit knucklesPunch1; [FieldOffset(0x1F8)] public PlayerParamComboTransit knucklesPunch2; [FieldOffset(0x20A)] public PlayerParamComboTransit knucklesUppercut; [FieldOffset(0x21C)] public PlayerParamComboTransit knucklesCyKnuckle; [FieldOffset(0x22E)] public PlayerParamComboTransit knucklesHeatKnuckle; [FieldOffset(0x240)] public PlayerParamComboTransit amyTarotAttack; [FieldOffset(0x252)] public PlayerParamComboTransit amyTarotAttack2; [FieldOffset(0x264)] public PlayerParamComboTransit amyTarotRolling; [FieldOffset(0x276)] public PlayerParamComboTransit amyCyHammer; [FieldOffset(0x288)] public PlayerParamComboTransit amyCharmAttack; [FieldOffset(0x29A)] public PlayerParamComboTransit tailsSpanner; } [StructLayout(LayoutKind.Explicit, Size = 0x2E0)] public struct PlayerParamCombo { [FieldOffset(0x00)] public PlayerParamComboCommon common; [FieldOffset(0x04)] public PlayerParamComboMove comboMoveSonic; [FieldOffset(0x18)] public PlayerParamComboMove comboMoveSupersonic; [FieldOffset(0x2C)] public PlayerParamComboMoveCorrection comboMoveCorrection; [FieldOffset(0x34)] public PlayerParamComboTransitTable comboTable; } [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct CyloopSlashEffectBaseParameter { [FieldOffset(0x00)] public int m_divideCircle; [FieldOffset(0x04)] public float m_circleRadius; [FieldOffset(0x08)] public float m_circleWaveCycle; [FieldOffset(0x0C)] public float m_circleWaveWidth; [FieldOffset(0x10)] public float m_circleWaveSpeed; [FieldOffset(0x14)] public Vector2 m_scale; [FieldOffset(0x20)] public UnmanagedString m_textureName; [FieldOffset(0x30)] public float m_flowSpeed; [FieldOffset(0x34)] public float m_twistCycle; [FieldOffset(0x38)] public float m_rollCycle; [FieldOffset(0x3C)] public float m_rollPhase; [FieldOffset(0x40)] public float m_alphaHeadDistance; [FieldOffset(0x44)] public float m_alphaTailDistance; [FieldOffset(0x48)] public float m_offsetCycle; [FieldOffset(0x4C)] public float m_offsetPhase; [FieldOffset(0x50)] public float m_offsetRadius; } public struct ColorF { public float A; public float R; public float G; public float B; } [StructLayout(LayoutKind.Explicit, Size = 0xA8)] public struct CyloopTransparentLocusParameter { [FieldOffset(0)] public CyloopSlashEffectBaseParameter cyloopSlashEffectBaseParameter; [FieldOffset(0x58)] public ColorF m_color0; [FieldOffset(0x68)] public ColorF m_color1; [FieldOffset(0x78)] public float m_luminance; [FieldOffset(0x7C)] public ColorF m_flashColor0; [FieldOffset(0x8C)] public ColorF m_flashColor1; [FieldOffset(0x9C)] public float m_flashLuminance; [FieldOffset(0xA0)] public float m_flashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct OpaqueLineUvCell { [FieldOffset(0x00)] public float scale; [FieldOffset(0x04)] public float speedX; [FieldOffset(0x08)] public float speedY; } [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct CyloopOpaqueLocusParameter { [FieldOffset(0)] public CyloopSlashEffectBaseParameter cyloopSlashEffectBaseParameter; [FieldOffset(0x58)] public ColorF m_color; [FieldOffset(0x68)] public float m_alphaThreshold; [FieldOffset(0x6C)] public unsafe fixed byte /* OpaqueLineUvCell[2] */ _m_uvCells[24]; public unsafe OpaqueLineUvCell* m_uvCells { get { fixed (byte* p_m_uvCells = _m_uvCells) return (OpaqueLineUvCell*)p_m_uvCells; } } [FieldOffset(0x84)] public float m_uvLineScaleX; [FieldOffset(0x88)] public float m_uvLineScaleY; [FieldOffset(0x8C)] public ColorF m_flashColor; [FieldOffset(0x9C)] public float m_flashTime; } [StructLayout(LayoutKind.Explicit, Size = 0xF0)] public struct CyloopCrossLineParameter { [FieldOffset(0x00)] public UnmanagedString m_textureNamePattern; [FieldOffset(0x10)] public UnmanagedString m_textureNameDist; [FieldOffset(0x20)] public ColorF startColor; [FieldOffset(0x30)] public ColorF endColor; [FieldOffset(0x40)] public float startColorLuminance; [FieldOffset(0x44)] public float endColorLuminance; [FieldOffset(0x48)] public ColorF startColorFlash; [FieldOffset(0x58)] public ColorF endColorFlash; [FieldOffset(0x68)] public float startColorLuminanceFlash; [FieldOffset(0x6C)] public float endColorLuminanceFlash; [FieldOffset(0x70)] public float flashTime; [FieldOffset(0x74)] public float patternDepth; [FieldOffset(0x78)] public float patternScrollSpeed; [FieldOffset(0x7C)] public float patternDarkness; [FieldOffset(0x80)] public float patternScale; [FieldOffset(0x84)] public float glitchResX; [FieldOffset(0x88)] public float glitchResY; [FieldOffset(0x8C)] public float glitchOffset; [FieldOffset(0x90)] public float glitchMaxLength; [FieldOffset(0x94)] public float startGlitchScrollSpeed; [FieldOffset(0x98)] public float startGlitchChangeSpeed; [FieldOffset(0x9C)] public float startGlitchShift; [FieldOffset(0xA0)] public float startGlitchContrust; [FieldOffset(0xA4)] public float endGlitchScrollSpeed; [FieldOffset(0xA8)] public float endGlitchChangeSpeed; [FieldOffset(0xAC)] public float endGlitchShift; [FieldOffset(0xB0)] public float endGlitchContrust; [FieldOffset(0xB4)] public float lineWidth; [FieldOffset(0xB8)] public float lineDisplayWidth; [FieldOffset(0xBC)] public float lineBlackEdgeWidth; [FieldOffset(0xC0)] public float lineBlackEdgeIntensity; [FieldOffset(0xC4)] public float lineBlackEdgeNormalFade; [FieldOffset(0xC8)] public float distNoiseScale; [FieldOffset(0xCC)] public float distLowNoiseScale; [FieldOffset(0xD0)] public float distHighNoiseScale; [FieldOffset(0xD4)] public float distNoiseRate; [FieldOffset(0xD8)] public float distScrollSpeed; [FieldOffset(0xDC)] public float distIntensity; [FieldOffset(0xE0)] public float dissolve; [FieldOffset(0xE4)] public float dissolveRate; [FieldOffset(0xE8)] public float heightOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x4E0)] public struct CyloopLocusParameter { [FieldOffset(0x00)] public int m_numTransparentLines; [FieldOffset(0x08)] public unsafe fixed byte /* CyloopTransparentLocusParameter[3] */ _m_transparentLines[504]; public unsafe CyloopTransparentLocusParameter* m_transparentLines { get { fixed (byte* p_m_transparentLines = _m_transparentLines) return (CyloopTransparentLocusParameter*)p_m_transparentLines; } } [FieldOffset(0x200)] public int m_numOpaqueLines; [FieldOffset(0x208)] public unsafe fixed byte /* CyloopOpaqueLocusParameter[3] */ _m_opaqueLines[480]; public unsafe CyloopOpaqueLocusParameter* m_opaqueLines { get { fixed (byte* p_m_opaqueLines = _m_opaqueLines) return (CyloopOpaqueLocusParameter*)p_m_opaqueLines; } } [FieldOffset(0x3E8)] public int m_numCrossLines; [FieldOffset(0x3F0)] public CyloopCrossLineParameter m_crossline; } [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct CyloopDropItemWeightParameter { [FieldOffset(0x00)] public uint noneWeight; [FieldOffset(0x04)] public uint ring10Weight; [FieldOffset(0x08)] public uint powerSeedWeight; [FieldOffset(0x0C)] public uint guardSeedWeight; [FieldOffset(0x10)] public uint sequenceItemWeight; [FieldOffset(0x14)] public uint portalBitWeight; [FieldOffset(0x18)] public uint skillPieceWeight; [FieldOffset(0x1C)] public uint skillPieceAmyWeight; [FieldOffset(0x20)] public uint skillPieceKnucklesWeight; [FieldOffset(0x24)] public uint skillPieceTailsWeight; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct CyloopDropItemParameter { [FieldOffset(0x00)] public CyloopDropItemWeightParameter weight; [FieldOffset(0x28)] public CyloopDropItemWeightParameter weight2; [FieldOffset(0x50)] public uint numRings; [FieldOffset(0x54)] public uint numRings2; [FieldOffset(0x58)] public uint num10Rings; [FieldOffset(0x5C)] public uint numSkillPieces; [FieldOffset(0x60)] public uint skillPieceExp; [FieldOffset(0x64)] public float rareDropCoolTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct CyloopShapeWindCountParameter { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float stunRate; [FieldOffset(0x08)] public float staggerRate; [FieldOffset(0x0C)] public float velocityRate; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct CyloopShapeWindEffectParaemter { [FieldOffset(0x00)] public unsafe fixed byte /* CyloopShapeWindCountParameter[5] */ _param[80]; public unsafe CyloopShapeWindCountParameter* param { get { fixed (byte* p_param = _param) return (CyloopShapeWindCountParameter*)p_param; } } } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct CyloopShapeEffectParameter { [FieldOffset(0x00)] public CyloopShapeWindEffectParaemter wind; } [StructLayout(LayoutKind.Explicit, Size = 0x1460)] public struct PlayerParamCyloop { [FieldOffset(0x00)] public CyloopLocusParameter locus; [FieldOffset(0x4E0)] public CyloopLocusParameter locusQuick; [FieldOffset(0x9C0)] public CyloopLocusParameter locusSuperSonic; [FieldOffset(0xEA0)] public CyloopLocusParameter locusSuperSonicQuick; [FieldOffset(0x1380)] public ColorF auraColor; [FieldOffset(0x1390)] public CyloopDropItemParameter dropItem; [FieldOffset(0x13F8)] public float needSpeed; [FieldOffset(0x13FC)] public CyloopShapeEffectParameter shapeEffect; [FieldOffset(0x144C)] public float lossQuickCyloopEnergy; [FieldOffset(0x1450)] public float recoveryQuickCyloopEnergyByTime; [FieldOffset(0x1454)] public float recoveryQuickCyloopEnergyByTimeInMinigame; [FieldOffset(0x1458)] public float recoveryFriendsQuickCyloopEnergyByRing; } public enum Part : sbyte { PunchR = 0, PunchL = 1, KickR = 2, KickL = 3 } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerParamSuperSonicShapeAttackData { [FieldOffset(0x00)] public UnmanagedString name; [FieldOffset(0x10)] public Part part; [FieldOffset(0x20)] public Vector3 begin; [FieldOffset(0x30)] public Vector3 end; [FieldOffset(0x40)] public float scale; [FieldOffset(0x44)] public float roll; [FieldOffset(0x48)] public float moveTime; [FieldOffset(0x4C)] public float fadeoutTime; } [StructLayout(LayoutKind.Explicit, Size = 0xA20)] public struct PlayerParamSuperSonic { [FieldOffset(0x00)] public int numRings; [FieldOffset(0x04)] public float decreaseSec; [FieldOffset(0x08)] public float inletRadius; [FieldOffset(0x0C)] public float moveSoundSpeed; [FieldOffset(0x10)] public ColorF auraColor2; [FieldOffset(0x20)] public unsafe fixed byte /* PlayerParamSuperSonicShapeAttackData[32] */ _shapeEffects[2560]; public unsafe PlayerParamSuperSonicShapeAttackData* shapeEffects { get { fixed (byte* p_shapeEffects = _shapeEffects) return (PlayerParamSuperSonicShapeAttackData*)p_shapeEffects; } } } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamSandSki { [FieldOffset(0x00)] public float blowDeceleForce; [FieldOffset(0x04)] public float blowDeceleForceOnGround; [FieldOffset(0x08)] public float blowGravityScale; [FieldOffset(0x0C)] public float blowTransitTime; [FieldOffset(0x10)] public float blowDownTime; [FieldOffset(0x14)] public float pylonBlowUpSize; [FieldOffset(0x18)] public float pylonBlowSpeed; [FieldOffset(0x20)] public UnmanagedString pylonHitStop; } public enum CameraShakeTiming : sbyte { StartCameraInterpolation = 0, EndCameraInterpolation = 1 } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct PlayerParamSlingshot { [FieldOffset(0x00)] public float timeScaleInMove; [FieldOffset(0x04)] public float hitStartRestTime; [FieldOffset(0x10)] public Vector3 hitCameraOffset; [FieldOffset(0x20)] public float hitCameraTimeEaseIn; [FieldOffset(0x24)] public float hitCameraFovyAngle; [FieldOffset(0x28)] public float hitTimeScaleValue; [FieldOffset(0x2C)] public float hitTimeScaleTimeEaseIn; [FieldOffset(0x30)] public float resetCameraEaseOutTime; [FieldOffset(0x34)] public float resetTimeScaleEaseOutTime; [FieldOffset(0x38)] public float timeScaleKeepTime; [FieldOffset(0x3C)] public float shotEffOffset; [FieldOffset(0x40)] public float hitEffOffset; [FieldOffset(0x44)] public CameraShakeTiming cameraShakeTiming; [FieldOffset(0x48)] public UnmanagedString cameraShakeName; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamRunawayBee { [FieldOffset(0x00)] public float meanderCycle; [FieldOffset(0x04)] public float meanderAngle; [FieldOffset(0x08)] public float minSpeed; [FieldOffset(0x0C)] public float maxSpeed; [FieldOffset(0x10)] public float time; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamRunWithKodamaParam { [FieldOffset(0x00)] public int numKodamas; [FieldOffset(0x04)] public float initialSpeed; [FieldOffset(0x08)] public float minSpeed; [FieldOffset(0x0C)] public float maxSpeed; [FieldOffset(0x10)] public float jumpForce; } [StructLayout(LayoutKind.Explicit, Size = 0xA8)] public struct PlayerParamRunWithKodama { [FieldOffset(0x00)] public int maxKodamas; [FieldOffset(0x04)] public float gravitySize; [FieldOffset(0x08)] public unsafe fixed byte /* PlayerParamRunWithKodamaParam[8] */ __params[160]; public unsafe PlayerParamRunWithKodamaParam* _params { get { fixed (byte* p__params = __params) return (PlayerParamRunWithKodamaParam*)p__params; } } } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamMine { [FieldOffset(0x00)] public float radiusLow; [FieldOffset(0x04)] public float radiusMedium; [FieldOffset(0x08)] public float radiusHigh; } [StructLayout(LayoutKind.Explicit, Size = 0x81A0)] public struct CommonPackageSonic { [FieldOffset(0)] public CommonPackage commonPackage; [FieldOffset(0x4B70)] public PlayerParamAcceleComboSet acceleComboSet; [FieldOffset(0x4C30)] public PlayerParamLoopKickSet loopKickSet; [FieldOffset(0x4CF0)] public PlayerParamCrasherSet crasherSet; [FieldOffset(0x4EA0)] public PlayerParamSpinSlashSet spinSlashSet; [FieldOffset(0x5110)] public PlayerParamChargeAttackSet chargeAtackSet; [FieldOffset(0x52F0)] public PlayerParamStompingAttackSet stompingAttackSet; [FieldOffset(0x5560)] public PlayerParamComboFinishSet comboFinishSet; [FieldOffset(0x5620)] public PlayerParamSonicBoomSet sonicboomSet; [FieldOffset(0x56E0)] public PlayerParamCrossSlashSet crossSlashSet; [FieldOffset(0x58F0)] public PlayerParamHomingShotSet homingShotSet; [FieldOffset(0x5AA0)] public PlayerParamSmashSet smashSet; [FieldOffset(0x5EC0)] public PlayerParamBehind behind; [FieldOffset(0x5ED4)] public PlayerParamCombo combo; [FieldOffset(0x61B8)] public PlayerParamCyloop cyloop; [FieldOffset(0x7620)] public PlayerParamSuperSonic supersonic; [FieldOffset(0x8040)] public PlayerParamSandSki sandski; [FieldOffset(0x8070)] public PlayerParamSlingshot slingshot; [FieldOffset(0x80D0)] public PlayerParamRunawayBee runawayBee; [FieldOffset(0x80E4)] public PlayerParamRunWithKodama runWithKodama; [FieldOffset(0x818C)] public PlayerParamMine mine; } public enum SupportedPlane : sbyte { Flat = 0, Slope = 1, Wall = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamCommon { [FieldOffset(0x00)] public float movableMaxSlope; [FieldOffset(0x04)] public float activeLandingSlope; [FieldOffset(0x08)] public float activeLandingSlopeInBoost; [FieldOffset(0x0C)] public float landingMaxSlope; [FieldOffset(0x10)] public float slidingMaxSlope; [FieldOffset(0x14)] public float wallAngleMaxSlope; [FieldOffset(0x18)] public SupportedPlane onStand; [FieldOffset(0x19)] public SupportedPlane onRunInAir; [FieldOffset(0x1A)] public SupportedPlane onRun; [FieldOffset(0x1B)] public bool moveHolding; [FieldOffset(0x1C)] public bool wallSlideSlowInBoost; [FieldOffset(0x1D)] public bool attrWallOnGround; [FieldOffset(0x20)] public float priorityInputTime; [FieldOffset(0x24)] public int capacityRings; [FieldOffset(0x28)] public int capacityRingsLvMax; [FieldOffset(0x2C)] public float collectRingRange; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamSpeedData { [FieldOffset(0x00)] public float initial; [FieldOffset(0x04)] public float min; [FieldOffset(0x08)] public float max; [FieldOffset(0x0C)] public float minTurn; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamSpeedAcceleData { [FieldOffset(0x00)] public float force; [FieldOffset(0x04)] public float force2; [FieldOffset(0x08)] public float damperRange; [FieldOffset(0x0C)] public float jerkMin; [FieldOffset(0x10)] public float jerkMax; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamSpeedAcceleData2 { [FieldOffset(0x00)] public float force; [FieldOffset(0x04)] public float damperRange; [FieldOffset(0x08)] public float jerkMin; [FieldOffset(0x0C)] public float jerkMax; } [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct PlayerParamSpeed { [FieldOffset(0x00)] public PlayerParamSpeedData normal; [FieldOffset(0x10)] public PlayerParamSpeedData normal2; [FieldOffset(0x20)] public PlayerParamSpeedData boost; [FieldOffset(0x30)] public PlayerParamSpeedData boost2; [FieldOffset(0x40)] public PlayerParamSpeedData boostLvMax; [FieldOffset(0x50)] public PlayerParamSpeedData boostLvMax2; [FieldOffset(0x60)] public float maxSpeedOver; [FieldOffset(0x64)] public float opitonMaxSpeedLimitMin; [FieldOffset(0x68)] public float opitonMaxSpeedLimitMax; [FieldOffset(0x6C)] public float thresholdStopSpeed; [FieldOffset(0x70)] public float maxFallSpeed; [FieldOffset(0x74)] public PlayerParamSpeedAcceleData accele; [FieldOffset(0x88)] public PlayerParamSpeedAcceleData decele; [FieldOffset(0x9C)] public PlayerParamSpeedAcceleData2 deceleNeutralMin; [FieldOffset(0xAC)] public PlayerParamSpeedAcceleData2 deceleNeutralMax; [FieldOffset(0xBC)] public float acceleAuto; [FieldOffset(0xC0)] public float deceleAuto; [FieldOffset(0xC4)] public float turnDeceleAngleMin; [FieldOffset(0xC8)] public float turnDeceleAngleMax; [FieldOffset(0xCC)] public float maxGravityAccele; [FieldOffset(0xD0)] public float maxGravityDecele; [FieldOffset(0xD4)] public float deceleSquat; [FieldOffset(0xD8)] public float acceleSensitive; [FieldOffset(0xDC)] public float boostAnimSpeedInWater; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamRotation { [FieldOffset(0x00)] public float baseRotateForce; [FieldOffset(0x04)] public float baseRotateForce2; [FieldOffset(0x08)] public float baseRotateForceSpeed; [FieldOffset(0x0C)] public float minRotateForce; [FieldOffset(0x10)] public float maxRotateForce; [FieldOffset(0x14)] public bool angleRotateForceDecayEnabled; [FieldOffset(0x18)] public float frontRotateRatio; [FieldOffset(0x1C)] public float rotationForceDecaySpeed; [FieldOffset(0x20)] public float rotationForceDecayRate; [FieldOffset(0x24)] public float rotationForceDecayMax; [FieldOffset(0x28)] public float autorunRotateForce; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamRunning { [FieldOffset(0x00)] public float walkSpeed; [FieldOffset(0x04)] public float sneakingSpeed; [FieldOffset(0x08)] public float animSpeedSneak; [FieldOffset(0x0C)] public float animSpeedWalk; [FieldOffset(0x10)] public float animSpeedRun; [FieldOffset(0x14)] public float animSpeedBoost; [FieldOffset(0x18)] public float animLRBlendSampleTime; [FieldOffset(0x1C)] public float animLRBlendAngleMin; [FieldOffset(0x20)] public float animLRBlendAngleMax; [FieldOffset(0x24)] public float animLRBlendSpeed; [FieldOffset(0x28)] public float animLRBlendSpeedToCenter; [FieldOffset(0x2C)] public float minChangeWalkTime; [FieldOffset(0x30)] public float fallAnimationAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamBalanceData { [FieldOffset(0x00)] public float rotateSpeedMinFB; [FieldOffset(0x04)] public float rotateSpeedMaxFB; [FieldOffset(0x08)] public float rotateSpeedMinLR; [FieldOffset(0x0C)] public float rotateSpeedMaxLR; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamBalance { [FieldOffset(0x00)] public PlayerParamBalanceData standard; [FieldOffset(0x10)] public PlayerParamBalanceData loop; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBrake { [FieldOffset(0x00)] public float initialSpeedRatio; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float forceLand; [FieldOffset(0x0C)] public float forceAir; [FieldOffset(0x10)] public float endSpeed; [FieldOffset(0x14)] public float stopTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamTurn { [FieldOffset(0x00)] public float thresholdSpeed; [FieldOffset(0x04)] public float thresholdAngle; [FieldOffset(0x08)] public float turnAfterSpeed; [FieldOffset(0x0C)] public bool stopEdge; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamJump { [FieldOffset(0x00)] public float preActionTime; [FieldOffset(0x04)] public float longPressTime; [FieldOffset(0x08)] public float addForceTime; [FieldOffset(0x0C)] public float force; [FieldOffset(0x10)] public float addForce; [FieldOffset(0x14)] public float forceMin; [FieldOffset(0x18)] public float gravitySize; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamJumpSpeed { [FieldOffset(0x00)] public float acceleForce; [FieldOffset(0x04)] public float deceleForce; [FieldOffset(0x08)] public float deceleNeutralForce; [FieldOffset(0x0C)] public float deceleBackForce; [FieldOffset(0x10)] public float limitMin; [FieldOffset(0x14)] public float limitUpSpeed; [FieldOffset(0x18)] public float rotationForce; [FieldOffset(0x1C)] public float rotationForceDecaySpeed; [FieldOffset(0x20)] public float rotationForceDecayRate; [FieldOffset(0x24)] public float rotationForceDecayMax; [FieldOffset(0x28)] public float baseAirDragScaleMin; [FieldOffset(0x2C)] public float baseAirDragScaleMax; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDoubleJump { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float bounceSpeed; [FieldOffset(0x08)] public float limitSpeedMin; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamFall { [FieldOffset(0x00)] public float thresholdVertSpeed; [FieldOffset(0x04)] public float tolerateJumpTime; [FieldOffset(0x08)] public float fallEndDelayTime; [FieldOffset(0x0C)] public float fallEndFadeTime; [FieldOffset(0x10)] public float acceleForce; [FieldOffset(0x14)] public float deceleForce; [FieldOffset(0x18)] public float overSpeedDeceleForce; [FieldOffset(0x1C)] public float rotationForce; [FieldOffset(0x20)] public float rotationForceDecaySpeed; [FieldOffset(0x24)] public float rotationForceDecayRate; [FieldOffset(0x28)] public float rotationForceDecayMax; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageCommon { [FieldOffset(0x00)] public float invincibleTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamDamageNormal { [FieldOffset(0x00)] public float initialHorzSpeed; [FieldOffset(0x04)] public float initialVertSpeed; [FieldOffset(0x08)] public float deceleForce; [FieldOffset(0x0C)] public float transitFallTime; [FieldOffset(0x10)] public float gravityScale; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageTurnBack { [FieldOffset(0x00)] public float fixedTime; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamDamageBlowOff { [FieldOffset(0x00)] public float initialHorzSpeed; [FieldOffset(0x04)] public float initialVertSpeed; [FieldOffset(0x08)] public float deceleForceInAir; [FieldOffset(0x0C)] public float deceleForceOnGround; [FieldOffset(0x10)] public float gravityScale; [FieldOffset(0x14)] public float downTime; [FieldOffset(0x18)] public float transitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamDamageGuarded { [FieldOffset(0x00)] public float vertSpeed; [FieldOffset(0x04)] public float horzSpeed; [FieldOffset(0x08)] public float deceleForce; [FieldOffset(0x0C)] public float transitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamDamageRunning { [FieldOffset(0x00)] public float actionTime; [FieldOffset(0x04)] public float minSpeed; [FieldOffset(0x08)] public float lossSpeed; [FieldOffset(0x0C)] public float lossTime; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageQuake { [FieldOffset(0x00)] public float actionTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamDamageLava { [FieldOffset(0x00)] public Vector3 jumpVelocity; [FieldOffset(0x10)] public float gravitySize; [FieldOffset(0x14)] public float invincibleTime; [FieldOffset(0x18)] public float noActionTime; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerParamDamageMine { [FieldOffset(0x00)] public Vector3 jumpVelocity; [FieldOffset(0x10)] public float gravitySize; [FieldOffset(0x14)] public float invincibleTime; [FieldOffset(0x18)] public float noActionTime; [FieldOffset(0x1C)] public float gravitySizeForFall; [FieldOffset(0x20)] public float maxFallSpeed; [FieldOffset(0x28)] public UnmanagedString cameraShakeName; [FieldOffset(0x38)] public UnmanagedString vibrationName; } [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct PlayerParamDamage { [FieldOffset(0x00)] public PlayerParamDamageCommon common; [FieldOffset(0x04)] public PlayerParamDamageNormal normal; [FieldOffset(0x18)] public PlayerParamDamageTurnBack turnBack; [FieldOffset(0x1C)] public PlayerParamDamageBlowOff blowOff; [FieldOffset(0x38)] public PlayerParamDamageGuarded guarded; [FieldOffset(0x48)] public PlayerParamDamageGuarded guardedSS; [FieldOffset(0x58)] public PlayerParamDamageRunning running; [FieldOffset(0x68)] public PlayerParamDamageQuake quake; [FieldOffset(0x70)] public PlayerParamDamageLava lava; [FieldOffset(0x90)] public PlayerParamDamageMine mine; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDeadNormal { [FieldOffset(0x00)] public float invincibleTime; [FieldOffset(0x04)] public float initialHorzSpeed; [FieldOffset(0x08)] public float initialVertSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDead { [FieldOffset(0x00)] public PlayerParamDeadNormal normal; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamSliding { [FieldOffset(0x00)] public float minSpeed; [FieldOffset(0x04)] public float endSpeed; [FieldOffset(0x08)] public float deceleJerk; [FieldOffset(0x0C)] public float deceleJerkContinue; [FieldOffset(0x10)] public float deceleForceMax; [FieldOffset(0x14)] public float baseRotateForce; [FieldOffset(0x18)] public float baseRotateForceSpeed; [FieldOffset(0x1C)] public float maxRotateForce; [FieldOffset(0x20)] public float frontRotateRatio; [FieldOffset(0x24)] public float rotationForceAutoRun; [FieldOffset(0x28)] public float movableMaxSlope; [FieldOffset(0x2C)] public float gravitySize; [FieldOffset(0x30)] public float minContinueTime; [FieldOffset(0x34)] public float maxAutoRunTime; [FieldOffset(0x38)] public float endSpeedAutoRun; [FieldOffset(0x3C)] public float loopKickTransitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamStomping { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float initialAccele; [FieldOffset(0x08)] public float maxAccele; [FieldOffset(0x0C)] public float jerk; [FieldOffset(0x10)] public float maxFallSpeed; [FieldOffset(0x14)] public float angle; [FieldOffset(0x18)] public float landingCancelTime; [FieldOffset(0x1C)] public float boundStompingCollisionScale; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamGrind { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float maxBoostSpeed; [FieldOffset(0x08)] public float acceleForce; [FieldOffset(0x0C)] public float deceleForce; [FieldOffset(0x10)] public float limitSpeedMin; } [StructLayout(LayoutKind.Explicit, Size = 0x38)] public struct PlayerParamFallSlope { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float brakeAngle; [FieldOffset(0x0C)] public float highBrakeAngle; [FieldOffset(0x10)] public float brakeForce; [FieldOffset(0x14)] public float brakeForceHigh; [FieldOffset(0x18)] public float gravitySize; [FieldOffset(0x1C)] public float gravitySizeAir; [FieldOffset(0x20)] public float endSpeedFront; [FieldOffset(0x24)] public float endSpeedBack; [FieldOffset(0x28)] public float reverseFallTime; [FieldOffset(0x2C)] public float fallToSlipTime; [FieldOffset(0x30)] public float slipIdlingTime; [FieldOffset(0x34)] public float minSlipTime; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamFallFlip { [FieldOffset(0x00)] public float thresholdSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float flipAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct PlayerParamTumble { [FieldOffset(0x00)] public bool enabled; [FieldOffset(0x04)] public float sideSpinAngle; [FieldOffset(0x08)] public float initialVertSpeed; [FieldOffset(0x0C)] public float gravitySize; [FieldOffset(0x10)] public float gravitySize2; [FieldOffset(0x14)] public float deceleForceInAir; [FieldOffset(0x18)] public float minSpeedInAir; [FieldOffset(0x1C)] public float rotateEaseTimeLeftRight; [FieldOffset(0x20)] public float rotateEaseTimeFrontBack; [FieldOffset(0x24)] public float rotateSpeedMinLeftRight; [FieldOffset(0x28)] public float rotateSpeedMaxLeftRight; [FieldOffset(0x2C)] public float rotateSpeedMinFrontBack; [FieldOffset(0x30)] public float rotateSpeedMaxFrontBack; [FieldOffset(0x34)] public float angleLeftRightStagger; [FieldOffset(0x38)] public float angleLeftRightRoll; [FieldOffset(0x3C)] public float angleFrontBackRoll; [FieldOffset(0x40)] public float angleBigRoll; [FieldOffset(0x44)] public float inRunTime; [FieldOffset(0x48)] public float inAirTime; [FieldOffset(0x4C)] public float rollSpeedFront; [FieldOffset(0x50)] public float bigRollVelocityRatio; [FieldOffset(0x54)] public float dropDashHoldTime; [FieldOffset(0x58)] public float airBrakeVertSpeed; [FieldOffset(0x5C)] public float airBrakeForce; [FieldOffset(0x60)] public float airTrickHeight; [FieldOffset(0x64)] public float airTrickTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSpinAttack { [FieldOffset(0x00)] public float jumpForce; [FieldOffset(0x04)] public float jumpAddForce; [FieldOffset(0x08)] public float addTime; [FieldOffset(0x0C)] public float acceleForce; [FieldOffset(0x10)] public float deceleForce; [FieldOffset(0x14)] public float brakeForce; [FieldOffset(0x18)] public float limitSpeedMin; [FieldOffset(0x1C)] public float limitSpeedMax; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamHomingAttackData { [FieldOffset(0x00)] public float speed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamHomingBounceData { [FieldOffset(0x00)] public float bounceVertSpeed; [FieldOffset(0x04)] public float bounceHorzSpeed; [FieldOffset(0x08)] public float bounceAcceleForce; [FieldOffset(0x0C)] public float bounceDeceleForce; [FieldOffset(0x10)] public float bounceAngleWidth; [FieldOffset(0x14)] public float bounceTime; [FieldOffset(0x18)] public float attackDownTime; [FieldOffset(0x1C)] public float attackDownTimeForStomp; } [StructLayout(LayoutKind.Explicit, Size = 0xB0)] public struct PlayerParamHomingAttack { [FieldOffset(0x00)] public PlayerParamHomingAttackData sonic; [FieldOffset(0x04)] public PlayerParamHomingAttackData supersonic; [FieldOffset(0x08)] public PlayerParamHomingBounceData sonicBounce; [FieldOffset(0x28)] public PlayerParamHomingBounceData sonicBounceWeak; [FieldOffset(0x48)] public PlayerParamHomingBounceData sonicBounceStorm; [FieldOffset(0x68)] public PlayerParamHomingBounceData sonicBounceStormSwirl; [FieldOffset(0x88)] public PlayerParamHomingBounceData supersonicBounce; [FieldOffset(0xA8)] public float cameraEaseInTime; [FieldOffset(0xAC)] public float cameraEaseOutTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamHitEnemy { [FieldOffset(0x00)] public float bounceVertSpeed; [FieldOffset(0x04)] public float bounceHorzSpeed; [FieldOffset(0x08)] public float attackDownTime; [FieldOffset(0x0C)] public float enableHomingTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct SpeedParam { [FieldOffset(0x00)] public float maxVertSpeed; [FieldOffset(0x04)] public float acceleVertForce; [FieldOffset(0x08)] public float maxHorzSpeed; [FieldOffset(0x0C)] public float acceleHorzForce; } [StructLayout(LayoutKind.Explicit, Size = 0x5C)] public struct PlayerParamDiving { [FieldOffset(0x00)] public SpeedParam normal; [FieldOffset(0x10)] public SpeedParam fast; [FieldOffset(0x20)] public SpeedParam damaged; [FieldOffset(0x30)] public SpeedParam ringdash; [FieldOffset(0x40)] public float startHeight; [FieldOffset(0x44)] public float startSpeed; [FieldOffset(0x48)] public float deceleVertForce; [FieldOffset(0x4C)] public float deceleHorzForce; [FieldOffset(0x50)] public float deceleNeutralForce; [FieldOffset(0x54)] public float damageTime; [FieldOffset(0x58)] public float ringdashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamFan { [FieldOffset(0x00)] public float damperV; [FieldOffset(0x04)] public float damperH; [FieldOffset(0x08)] public float accelRate; [FieldOffset(0x0C)] public float moveForceFV; [FieldOffset(0x10)] public float moveForceSV; [FieldOffset(0x14)] public float jumpCheckSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBackflip { [FieldOffset(0x00)] public float jumpSpeed; [FieldOffset(0x04)] public float backSpeed; [FieldOffset(0x08)] public float downAccel; [FieldOffset(0x0C)] public float damperV; [FieldOffset(0x10)] public float damperH; [FieldOffset(0x14)] public float time; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSlowMove { [FieldOffset(0x00)] public float startSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float accel; [FieldOffset(0x0C)] public float brake; [FieldOffset(0x10)] public float damageSpeed; [FieldOffset(0x14)] public float damageBrake; [FieldOffset(0x18)] public float steeringSpeed; [FieldOffset(0x1C)] public float endSteeringSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSpin { [FieldOffset(0x00)] public float startSlopeAngle; [FieldOffset(0x04)] public float endSlopeAngle; [FieldOffset(0x08)] public float startSpeed; [FieldOffset(0x0C)] public float endSpeed; [FieldOffset(0x10)] public float stickAngle; [FieldOffset(0x14)] public float brake; [FieldOffset(0x18)] public float forceBrake; [FieldOffset(0x1C)] public float maxSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x88)] public struct PlayerParamWallMove { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float walkSpeed; [FieldOffset(0x08)] public float walkSpeedMax; [FieldOffset(0x0C)] public float runSpeed; [FieldOffset(0x10)] public float runSpeedMax; [FieldOffset(0x14)] public float walkSpeedOnMesh; [FieldOffset(0x18)] public float walkSpeedOnMeshMax; [FieldOffset(0x1C)] public float runSpeedOnMesh; [FieldOffset(0x20)] public float runSpeedOnMeshMax; [FieldOffset(0x24)] public float minAccessSpeed; [FieldOffset(0x28)] public float stickSpeed; [FieldOffset(0x2C)] public float gravity; [FieldOffset(0x30)] public float accel; [FieldOffset(0x34)] public float brake; [FieldOffset(0x38)] public float stopBrake; [FieldOffset(0x3C)] public float fallSpeed; [FieldOffset(0x40)] public float steeringSpeed1; [FieldOffset(0x44)] public float steeringSpeed2; [FieldOffset(0x48)] public float startSteeringSpeed; [FieldOffset(0x4C)] public float endSteeringSpeed; [FieldOffset(0x50)] public float startTime; [FieldOffset(0x54)] public float useEnergySpeedBase; [FieldOffset(0x58)] public float useEnergySpeedBaseOnMesh; [FieldOffset(0x5C)] public float useEnergySpeedVal; [FieldOffset(0x60)] public float useEnergySpeedValOnMesh; [FieldOffset(0x64)] public float useEnergyAngle; [FieldOffset(0x68)] public float useEnergyAngleOnMesh; [FieldOffset(0x6C)] public float brakeStartEnergy; [FieldOffset(0x70)] public float brakeStartEnergyOnMesh; [FieldOffset(0x74)] public float homingSearchDistanceNear; [FieldOffset(0x78)] public float homingSearchDistanceFar; [FieldOffset(0x7C)] public float wallBumpHeightUpper; [FieldOffset(0x80)] public float wallBumpHeightUnder; [FieldOffset(0x84)] public float recoveryCheckTime; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerParamWallJump { [FieldOffset(0x00)] public float gravitySize; [FieldOffset(0x04)] public float minTime; [FieldOffset(0x08)] public float maxTime; [FieldOffset(0x0C)] public float stopTime; [FieldOffset(0x10)] public float maxDownSpeed; [FieldOffset(0x14)] public float fallGroundDistance; [FieldOffset(0x18)] public float frontForce; [FieldOffset(0x1C)] public float upForce; [FieldOffset(0x20)] public float impulseTime; } [StructLayout(LayoutKind.Explicit, Size = 0x54)] public struct PlayerParamClimbing { [FieldOffset(0x00)] public float stepSpeedFront; [FieldOffset(0x04)] public float stepSpeedFrontDash; [FieldOffset(0x08)] public float stepSpeedSide; [FieldOffset(0x0C)] public float stepSpeedSideDash; [FieldOffset(0x10)] public float stepSpeedBack; [FieldOffset(0x14)] public float stepDashRate; [FieldOffset(0x18)] public float maxAnimSpeed; [FieldOffset(0x1C)] public float exhaustAngle; [FieldOffset(0x20)] public float exhaustAngleOnMesh; [FieldOffset(0x24)] public float exhaustBase; [FieldOffset(0x28)] public float exhaustBaseOnMesh; [FieldOffset(0x2C)] public float exhaustRate; [FieldOffset(0x30)] public float exhaustRateOnMesh; [FieldOffset(0x34)] public float useGrabGaugeSpeed; [FieldOffset(0x38)] public float useGrabGaugeSpeedOnMesh; [FieldOffset(0x3C)] public float useGrabGaugeTurbo; [FieldOffset(0x40)] public float useGrabGaugeTurboOnMesh; [FieldOffset(0x44)] public float homingSearchDistanceNear; [FieldOffset(0x48)] public float homingSearchDistanceFar; [FieldOffset(0x4C)] public float resetAngle; [FieldOffset(0x50)] public float recoveryCheckTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamSlideDown { [FieldOffset(0x00)] public float time; [FieldOffset(0x04)] public float speed; [FieldOffset(0x08)] public float speedOnMesh; [FieldOffset(0x0C)] public float accel; [FieldOffset(0x10)] public float brake; [FieldOffset(0x14)] public float brakeOnMesh; } [StructLayout(LayoutKind.Explicit, Size = 0x3C)] public struct PlayerParamBoost { [FieldOffset(0x00)] public float consumptionRate; [FieldOffset(0x04)] public float consumptionRateSS; [FieldOffset(0x08)] public float recoveryRate; [FieldOffset(0x0C)] public float recoveryRateSS; [FieldOffset(0x10)] public float reigniteRatio; [FieldOffset(0x14)] public float recoveryByRing; [FieldOffset(0x18)] public float recoveryByAttack; [FieldOffset(0x1C)] public unsafe fixed float blurPowers[3]; [FieldOffset(0x28)] public float blurEaseInTime; [FieldOffset(0x2C)] public float blurEaseOutTime; [FieldOffset(0x30)] public float endSpeed; [FieldOffset(0x34)] public float powerBoostCoolTime; [FieldOffset(0x38)] public float infinityBoostTime; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamAirBoost { [FieldOffset(0x00)] public float startHSpeed; [FieldOffset(0x04)] public float startHSpeedMax; [FieldOffset(0x08)] public float startVSpeed; [FieldOffset(0x0C)] public float minHSpeed; [FieldOffset(0x10)] public float minHSpeedMax; [FieldOffset(0x14)] public float brakeTime; [FieldOffset(0x18)] public float minKeepTime; [FieldOffset(0x1C)] public float maxKeepTime; [FieldOffset(0x20)] public float maxTime; [FieldOffset(0x24)] public float gravityRate; [FieldOffset(0x28)] public float steeringSpeed; [FieldOffset(0x2C)] public float additionalTransitTime; [FieldOffset(0x30)] public float supersonicTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAutorun { [FieldOffset(0x00)] public float initialSideSpeed; [FieldOffset(0x04)] public float acceleSideForce; [FieldOffset(0x08)] public float deceleSideForce; [FieldOffset(0x0C)] public float maxSideSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSideStep { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float brakeForce; [FieldOffset(0x08)] public float motionSpeedRatio; [FieldOffset(0x0C)] public float stepSpeed; [FieldOffset(0x10)] public float maxStepDistance; [FieldOffset(0x14)] public float minStepDistance; [FieldOffset(0x18)] public float maxStepSpeed; [FieldOffset(0x1C)] public float minStepSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSideStep2 { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float brakeForce; [FieldOffset(0x08)] public float motionSpeedRatio; [FieldOffset(0x0C)] public float stepSpeed; [FieldOffset(0x10)] public float maxStepDistance; [FieldOffset(0x14)] public float minStepDistance; [FieldOffset(0x18)] public float maxStepSpeed; [FieldOffset(0x1C)] public float minStepSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerParamQuickStep { [FieldOffset(0x00)] public float needSpeed; [FieldOffset(0x04)] public float acceleForce; [FieldOffset(0x08)] public float acceleSideForce; [FieldOffset(0x0C)] public float stepInitialSpeed; [FieldOffset(0x10)] public float avoidForce; [FieldOffset(0x14)] public float justBoostForce; [FieldOffset(0x18)] public float justBoostMax; [FieldOffset(0x1C)] public float justBoostTime; [FieldOffset(0x20)] public float justBoostBrake; } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct PlayerParamParry { [FieldOffset(0x00)] public float minRecieveTime; [FieldOffset(0x04)] public unsafe fixed float maxRecieveTimes[4]; [FieldOffset(0x14)] public unsafe fixed float justRecieveTimes[4]; [FieldOffset(0x24)] public float frozenTime; [FieldOffset(0x28)] public float justFrozenTime; [FieldOffset(0x2C)] public float justEffectEasein; [FieldOffset(0x30)] public float justEffectEaseout; [FieldOffset(0x34)] public float justEffectTime; [FieldOffset(0x38)] public float justEffectEasein2; [FieldOffset(0x3C)] public float justEffectEaseout2; [FieldOffset(0x40)] public float justEffectTime2; [FieldOffset(0x44)] public float justEffectEasein3; [FieldOffset(0x48)] public float justEffectEaseout3; [FieldOffset(0x4C)] public float justEffectTime3; [FieldOffset(0x50)] public UnmanagedString cameraName; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAvoidData { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float damper; [FieldOffset(0x08)] public float parryTime; [FieldOffset(0x0C)] public float invincibleTime; } [StructLayout(LayoutKind.Explicit, Size = 0x94)] public struct PlayerParamAvoid { [FieldOffset(0x00)] public float time; [FieldOffset(0x04)] public float fixedTime; [FieldOffset(0x08)] public float reentryInputPriorityTime; [FieldOffset(0x0C)] public float reentryTime; [FieldOffset(0x10)] public float frontAngle; [FieldOffset(0x14)] public float backAngle; [FieldOffset(0x18)] public float addFallSpeed; [FieldOffset(0x1C)] public unsafe fixed byte /* PlayerParamAvoidData[7] */ _data[112]; public unsafe PlayerParamAvoidData* data { get { fixed (byte* p_data = _data) return (PlayerParamAvoidData*)p_data; } } [FieldOffset(0x8C)] public float baseDistance; [FieldOffset(0x90)] public float limitAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x8F0)] public struct ModePackage { [FieldOffset(0x00)] public PlayerParamCommon common; [FieldOffset(0x30)] public PlayerParamSpeed speed; [FieldOffset(0x110)] public PlayerParamRotation rotation; [FieldOffset(0x13C)] public PlayerParamRunning running; [FieldOffset(0x170)] public PlayerParamBalance balance; [FieldOffset(0x190)] public PlayerParamBrake brake; [FieldOffset(0x1A8)] public PlayerParamTurn turn; [FieldOffset(0x1B8)] public PlayerParamJump jump; [FieldOffset(0x1D4)] public PlayerParamJumpSpeed jumpSpeed; [FieldOffset(0x204)] public PlayerParamDoubleJump doubleJump; [FieldOffset(0x210)] public PlayerParamFall fall; [FieldOffset(0x240)] public PlayerParamDamage damage; [FieldOffset(0x320)] public PlayerParamDead dead; [FieldOffset(0x32C)] public PlayerParamSliding sliding; [FieldOffset(0x36C)] public PlayerParamStomping stomping; [FieldOffset(0x38C)] public PlayerParamGrind grind; [FieldOffset(0x3A0)] public PlayerParamFallSlope fallSlope; [FieldOffset(0x3D8)] public PlayerParamFallFlip fallFlip; [FieldOffset(0x3E4)] public PlayerParamTumble tumble; [FieldOffset(0x44C)] public PlayerParamSpinAttack spinAttack; [FieldOffset(0x46C)] public PlayerParamHomingAttack homingAttack; [FieldOffset(0x51C)] public PlayerParamHitEnemy hitEnemy; [FieldOffset(0x52C)] public PlayerParamDiving diving; [FieldOffset(0x588)] public PlayerParamFan fan; [FieldOffset(0x5A0)] public PlayerParamBackflip backflip; [FieldOffset(0x5B8)] public PlayerParamSlowMove slowmove; [FieldOffset(0x5D8)] public PlayerParamSpin spin; [FieldOffset(0x5F8)] public PlayerParamWallMove wallmove; [FieldOffset(0x680)] public PlayerParamWallJump walljump; [FieldOffset(0x6A4)] public PlayerParamClimbing climbing; [FieldOffset(0x6F8)] public PlayerParamSlideDown slidedown; [FieldOffset(0x710)] public PlayerParamBoost boost; [FieldOffset(0x74C)] public PlayerParamAirBoost airboost; [FieldOffset(0x780)] public PlayerParamAutorun autorun; [FieldOffset(0x790)] public PlayerParamSideStep sidestep; [FieldOffset(0x7B0)] public PlayerParamSideStep2 sidestep2; [FieldOffset(0x7D0)] public PlayerParamQuickStep quickstep; [FieldOffset(0x7F8)] public PlayerParamParry parry; [FieldOffset(0x858)] public PlayerParamAvoid avoid; } [StructLayout(LayoutKind.Explicit, Size = 0x44)] public struct PlayerParamStorm { [FieldOffset(0x00)] public float damperV; [FieldOffset(0x04)] public float damperH; [FieldOffset(0x08)] public float brake; [FieldOffset(0x0C)] public float accelRate; [FieldOffset(0x10)] public float moveForce; [FieldOffset(0x14)] public float maxSpeedH; [FieldOffset(0x18)] public float maxSpeedV; [FieldOffset(0x1C)] public float rotateSpeed; [FieldOffset(0x20)] public float rotateAngularSpeed; [FieldOffset(0x24)] public float minDrawSpeed; [FieldOffset(0x28)] public float maxDrawSpeed; [FieldOffset(0x2C)] public float minDrawSpeedDistance; [FieldOffset(0x30)] public float maxDrawSpeedDistance; [FieldOffset(0x34)] public float damageTime; [FieldOffset(0x38)] public float damageNoBrakeTime; [FieldOffset(0x3C)] public float forceHomingReaction; [FieldOffset(0x40)] public float forceHomingReaction2; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamCloudJump { [FieldOffset(0x00)] public float acceleForce; [FieldOffset(0x04)] public float deceleForce; [FieldOffset(0x08)] public float overSpeedDeceleForce; [FieldOffset(0x0C)] public float rotationForce; [FieldOffset(0x10)] public float rotationForceDecaySpeed; [FieldOffset(0x14)] public float rotationForceDecayRate; [FieldOffset(0x18)] public float rotationForceDecayMax; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamAquaBall { [FieldOffset(0x00)] public float fallAccel; [FieldOffset(0x04)] public float damper; [FieldOffset(0x08)] public float jumpSpeed; [FieldOffset(0x0C)] public float stompingSpeed; [FieldOffset(0x10)] public float boundSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSlider { [FieldOffset(0x00)] public float frontAccel; [FieldOffset(0x04)] public float frontBrake; [FieldOffset(0x08)] public float sideBrake; [FieldOffset(0x0C)] public float damageBrake; [FieldOffset(0x10)] public float defaultRotateSpeed; [FieldOffset(0x14)] public float rotateSpeed; [FieldOffset(0x18)] public float rotateSpeedAir; [FieldOffset(0x1C)] public float gravity; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamAirTrick { [FieldOffset(0x00)] public uint amount; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct PlayerParamDrift { [FieldOffset(0x00)] public float startAngle; [FieldOffset(0x04)] public float endSpeed; [FieldOffset(0x08)] public float minSpeed; [FieldOffset(0x0C)] public float minSpeedMax; [FieldOffset(0x10)] public float maxSpeed; [FieldOffset(0x14)] public float maxSpeedMax; [FieldOffset(0x18)] public float minBoostSpeed; [FieldOffset(0x1C)] public float minBoostSpeedMax; [FieldOffset(0x20)] public float maxBoostSpeed; [FieldOffset(0x24)] public float maxBoostSpeedMax; [FieldOffset(0x28)] public float accel; [FieldOffset(0x2C)] public float brake; [FieldOffset(0x30)] public float maxSteerAngle; [FieldOffset(0x34)] public float steerAccel; [FieldOffset(0x38)] public float maxSteerSpeed; [FieldOffset(0x3C)] public float neutralSteerAccel; [FieldOffset(0x40)] public float maxNeutralSteerSpeed; [FieldOffset(0x44)] public float maxRotateSpeed; [FieldOffset(0x48)] public float recoverTime; [FieldOffset(0x4C)] public float maxChargeTime; [FieldOffset(0x50)] public float minDashSpeed; [FieldOffset(0x54)] public float maxDashSpeed; [FieldOffset(0x58)] public float minDashJumpSpeed; [FieldOffset(0x5C)] public float maxDashJumpSpeed; [FieldOffset(0x60)] public float jumpSpeed; [FieldOffset(0x64)] public float checkFallTime; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamDriftAir { [FieldOffset(0x00)] public float startAngle; [FieldOffset(0x04)] public float endSpeed; [FieldOffset(0x08)] public float minSpeed; [FieldOffset(0x0C)] public float maxSpeed; [FieldOffset(0x10)] public float accel; [FieldOffset(0x14)] public float brake; [FieldOffset(0x18)] public float maxSteerAngle; [FieldOffset(0x1C)] public float steerAccel; [FieldOffset(0x20)] public float maxSteerSpeed; [FieldOffset(0x24)] public float neutralSteerAccel; [FieldOffset(0x28)] public float maxNeutralSteerSpeed; [FieldOffset(0x2C)] public float maxRotateSpeed; [FieldOffset(0x30)] public float recoverTime; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerParamDriftDash { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float brake; [FieldOffset(0x08)] public float steeringSpeed1; [FieldOffset(0x0C)] public float steeringSpeed2; [FieldOffset(0x10)] public float startSteeringSpeed; [FieldOffset(0x14)] public float endSteeringSpeed; [FieldOffset(0x18)] public float outOfControlSpeed; [FieldOffset(0x1C)] public float checkDashSpeed; [FieldOffset(0x20)] public float checkDashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x70)] public struct PlayerParamBoarding { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float minSpeed; [FieldOffset(0x08)] public float damageSpeed; [FieldOffset(0x0C)] public float accel; [FieldOffset(0x10)] public float damageBrake; [FieldOffset(0x14)] public float damageBrakeTime; [FieldOffset(0x18)] public float damageMotionTime; [FieldOffset(0x1C)] public float damageInvicibleTime; [FieldOffset(0x20)] public float damper; [FieldOffset(0x24)] public float airDamperV; [FieldOffset(0x28)] public float airDamperH; [FieldOffset(0x2C)] public float gravity; [FieldOffset(0x30)] public float airJumpSpeed; [FieldOffset(0x34)] public float groundJumpSpeed; [FieldOffset(0x38)] public float airAccel; [FieldOffset(0x3C)] public float maxAirAddSpeed; [FieldOffset(0x40)] public float downForceRate; [FieldOffset(0x44)] public float steeringSpeed1; [FieldOffset(0x48)] public float steeringSpeed2; [FieldOffset(0x4C)] public float steeringSpeed3; [FieldOffset(0x50)] public float startSteeringSpeed; [FieldOffset(0x54)] public float endSteeringSpeed; [FieldOffset(0x58)] public float startSpeed; [FieldOffset(0x5C)] public float startSlope; [FieldOffset(0x60)] public float staticStartSlope; [FieldOffset(0x64)] public float finishSlope; [FieldOffset(0x68)] public float finishTime; [FieldOffset(0x6C)] public float bigLandTime; } [StructLayout(LayoutKind.Explicit, Size = 0x3C)] public struct PlayerParamDropDash { [FieldOffset(0x00)] public float maxChargeTime; [FieldOffset(0x04)] public float minDashSpeed; [FieldOffset(0x08)] public float minDashSpeedMax; [FieldOffset(0x0C)] public float maxDashSpeed; [FieldOffset(0x10)] public float maxDashSpeedMax; [FieldOffset(0x14)] public float tumbleDashSpeed; [FieldOffset(0x18)] public float maxSpeed; [FieldOffset(0x1C)] public float brake; [FieldOffset(0x20)] public float steeringSpeed1; [FieldOffset(0x24)] public float steeringSpeed2; [FieldOffset(0x28)] public float startSteeringSpeed; [FieldOffset(0x2C)] public float endSteeringSpeed; [FieldOffset(0x30)] public float outOfControlSpeed; [FieldOffset(0x34)] public float checkDashSpeed; [FieldOffset(0x38)] public float checkDashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamBounceJump { [FieldOffset(0x00)] public float startSpeed; [FieldOffset(0x04)] public float jumpRate1; [FieldOffset(0x08)] public float jumpRate2; [FieldOffset(0x0C)] public float jumpRate3; [FieldOffset(0x10)] public float inoperableTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamLightDash { [FieldOffset(0x00)] public float dashSpeed; [FieldOffset(0x04)] public float dashSpeedMax; [FieldOffset(0x08)] public float speed; [FieldOffset(0x0C)] public float speedMax; [FieldOffset(0x10)] public float accel; [FieldOffset(0x14)] public float brake; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamSpinDash { [FieldOffset(0x00)] public float time; [FieldOffset(0x04)] public float minSpeed; [FieldOffset(0x08)] public float deceleForce; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamSpinBoostSpeed { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public PlayerParamSpeedAcceleData accele; [FieldOffset(0x1C)] public PlayerParamSpeedAcceleData decele; [FieldOffset(0x30)] public float baseRotateForce; [FieldOffset(0x34)] public float minTurnSpeed; [FieldOffset(0x38)] public float turnDeceleAngleMin; [FieldOffset(0x3C)] public float turnDeceleAngleMax; } public enum AirAccelMode : sbyte { Alawys = 0, AirAccelMode_None = 1, Speed = 2 } [StructLayout(LayoutKind.Explicit, Size = 0xF8)] public struct PlayerParamSpinBoost { [FieldOffset(0x00)] public float forceRunTime; [FieldOffset(0x04)] public float initialRunTime; [FieldOffset(0x08)] public PlayerParamSpinBoostSpeed speedBall; [FieldOffset(0x48)] public PlayerParamSpinBoostSpeed speedBoost; [FieldOffset(0x88)] public PlayerParamSpeedAcceleData2 deceleNeutralMin; [FieldOffset(0x98)] public PlayerParamSpeedAcceleData2 deceleNeutralMax; [FieldOffset(0xA8)] public float gravitySize; [FieldOffset(0xAC)] public float gravityBeginTime; [FieldOffset(0xB0)] public float gravityMaxTime; [FieldOffset(0xB4)] public float gravitySizeMinInAir; [FieldOffset(0xB8)] public float gravitySizeMaxInAir; [FieldOffset(0xBC)] public float maxGravityAccele; [FieldOffset(0xC0)] public float maxGravityDecele; [FieldOffset(0xC4)] public float inAirTime; [FieldOffset(0xC8)] public float spinBoostEndSpeed; [FieldOffset(0xCC)] public float jumpOutAngle; [FieldOffset(0xD0)] public float jumpOutSpeed; [FieldOffset(0xD4)] public bool humpJumpOut; [FieldOffset(0xD5)] public AirAccelMode airAccelMode; [FieldOffset(0xD8)] public float airAccelVertSpeedThreshold; [FieldOffset(0xDC)] public float chargeRotateForce; [FieldOffset(0xE0)] public float chargeRotateForceMinAngle; [FieldOffset(0xE4)] public float chargeRotateForceMaxAngle; [FieldOffset(0xE8)] public UnmanagedString cameraShakeName; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamFly { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float maxDashSpeed; [FieldOffset(0x08)] public float accel; [FieldOffset(0x0C)] public float dashAccel; [FieldOffset(0x10)] public float brake; [FieldOffset(0x14)] public float minRotateSpeed; [FieldOffset(0x18)] public float maxRotateSpeed; [FieldOffset(0x1C)] public float blowOffTime; [FieldOffset(0x20)] public float blowOffAngle; [FieldOffset(0x24)] public float turnBrake; [FieldOffset(0x28)] public float turnRotateSpeed; [FieldOffset(0x2C)] public float quickTurnThresholdAngle; [FieldOffset(0x30)] public float quickTurnStartSpeed; [FieldOffset(0x34)] public float quickTurnBrake; [FieldOffset(0x38)] public float quickTurnRotateSpeed; [FieldOffset(0x3C)] public float comboTime; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamLimitedFly { [FieldOffset(0x00)] public float maxSpeed1D; [FieldOffset(0x04)] public float accel1D; [FieldOffset(0x08)] public float brake1D; [FieldOffset(0x0C)] public float fixAccel1D; [FieldOffset(0x10)] public float fixSpeed1D; [FieldOffset(0x14)] public float fixAccelQuick; [FieldOffset(0x18)] public float fixSpeedQuick; [FieldOffset(0x1C)] public float rotateSpeed1D; [FieldOffset(0x20)] public float maxSpeed2D; [FieldOffset(0x24)] public float accel2D; [FieldOffset(0x28)] public float brake2D; [FieldOffset(0x2C)] public float fixSpeed2D; [FieldOffset(0x30)] public float rotateSpeed2D; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerCyberModeSpeedParam { [FieldOffset(0x00)] public float initial; [FieldOffset(0x04)] public float min; [FieldOffset(0x08)] public float max; [FieldOffset(0x0C)] public float minTurn; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerMaxSpeedChallengeLevelParam { [FieldOffset(0x00)] public PlayerCyberModeSpeedParam speed; [FieldOffset(0x10)] public PlayerCyberModeSpeedParam speedPowerBoost; [FieldOffset(0x20)] public float recoveryRate; } [StructLayout(LayoutKind.Explicit, Size = 0x238)] public struct PlayerParamCyberMode { [FieldOffset(0x00)] public float lowGravityScale; [FieldOffset(0x04)] public float timeScale; [FieldOffset(0x08)] public float accelForce; [FieldOffset(0x0C)] public float jerk; [FieldOffset(0x10)] public float minSpeedThreshold; [FieldOffset(0x14)] public float maxSpeedThreshold; [FieldOffset(0x18)] public float recoveryRate; [FieldOffset(0x1C)] public float maxSpeed; [FieldOffset(0x20)] public float maxSpeedInBoost; [FieldOffset(0x24)] public uint numLevels; [FieldOffset(0x28)] public unsafe fixed byte /* PlayerMaxSpeedChallengeLevelParam[8] */ _levels[288]; public unsafe PlayerMaxSpeedChallengeLevelParam* levels { get { fixed (byte* p_levels = _levels) return (PlayerMaxSpeedChallengeLevelParam*)p_levels; } } [FieldOffset(0x148)] public float animalMinSpeed; [FieldOffset(0x14C)] public float animalMaxSpeed; [FieldOffset(0x150)] public float animalInitialSpeed; [FieldOffset(0x154)] public float animalMinTurnSpeed; [FieldOffset(0x158)] public float animalJumpForce; [FieldOffset(0x15C)] public float animalGravitySize; [FieldOffset(0x160)] public float nitroConsumptionRate; [FieldOffset(0x164)] public float nitroAirDragPowerMin; [FieldOffset(0x168)] public float nitroAirDragPowerMax; [FieldOffset(0x170)] public UnmanagedString nitroHitStopName; [FieldOffset(0x180)] public UnmanagedString nitroHitStopNameAir; [FieldOffset(0x190)] public UnmanagedString nitroCameraShakeName; [FieldOffset(0x1A0)] public UnmanagedString nitroCameraShakeNameAir; [FieldOffset(0x1B0)] public UnmanagedString nitroVibrationName; [FieldOffset(0x1C0)] public UnmanagedString nitroVibrationNameAir; [FieldOffset(0x1D0)] public float nitroRunEffectDelay; [FieldOffset(0x1D8)] public UnmanagedString nitroCameraShakeNameInRun; [FieldOffset(0x1E8)] public UnmanagedString nitroVibrationNameInRun; [FieldOffset(0x1F8)] public PlayerCyberModeSpeedParam nitroSpeed; [FieldOffset(0x208)] public PlayerCyberModeSpeedParam nitroSpeedLvMax; [FieldOffset(0x218)] public PlayerCyberModeSpeedParam nitroSpeedPowerBoost; [FieldOffset(0x228)] public PlayerCyberModeSpeedParam nitroSpeedLvMaxPowerBoost; } [StructLayout(LayoutKind.Explicit, Size = 0xEE0)] public struct ModePackageSonic { [FieldOffset(0)] public ModePackage modePackage; [FieldOffset(0x8F0)] public PlayerParamStorm storm; [FieldOffset(0x934)] public PlayerParamCloudJump cloudJump; [FieldOffset(0x950)] public PlayerParamAquaBall aquaball; [FieldOffset(0x964)] public PlayerParamSlider slider; [FieldOffset(0x984)] public PlayerParamAirTrick airtrick; [FieldOffset(0x988)] public PlayerParamDrift drift; [FieldOffset(0x9F0)] public PlayerParamDriftAir driftair; [FieldOffset(0xA24)] public PlayerParamDriftDash driftDash; [FieldOffset(0xA48)] public PlayerParamBoarding boarding; [FieldOffset(0xAB8)] public PlayerParamDropDash dropDash; [FieldOffset(0xAF4)] public PlayerParamBounceJump bounceJump; [FieldOffset(0xB08)] public PlayerParamLightDash lightDash; [FieldOffset(0xB20)] public PlayerParamSpinDash spindash; [FieldOffset(0xB30)] public PlayerParamSpinBoost spinBoost; [FieldOffset(0xC28)] public PlayerParamFly fly; [FieldOffset(0xC68)] public PlayerParamLimitedFly limitedfly; [FieldOffset(0xCA0)] public PlayerParamCyberMode cyberMode; } [StructLayout(LayoutKind.Explicit, Size = 0x1A8)] public struct WaterModePackage { [FieldOffset(0x00)] public PlayerParamSpeed speed; [FieldOffset(0xE0)] public PlayerParamJump jump; [FieldOffset(0xFC)] public PlayerParamJumpSpeed jumpSpeed; [FieldOffset(0x12C)] public PlayerParamDoubleJump doubleJump; [FieldOffset(0x138)] public PlayerParamBoost boost; [FieldOffset(0x174)] public PlayerParamAirBoost airboost; } [StructLayout(LayoutKind.Explicit, Size = 0xAFF0)] public struct Root { [FieldOffset(0x00)] public CommonPackageSonic common; [FieldOffset(0x81A0)] public ModePackageSonic forwardView; [FieldOffset(0x9080)] public WaterModePackage water; [FieldOffset(0x9230)] public ModePackageSonic cyberspace; [FieldOffset(0xA110)] public ModePackageSonic cyberspaceSV; } } Library "CustomMusicParameter" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct CustomMusicTransitInfo { [FieldOffset(0x00)] public float fadeOutTime; [FieldOffset(0x04)] public float delayTime; } [StructLayout(LayoutKind.Explicit, Size = 8)] public struct UnmanagedString { [FieldOffset(0)] public long pValue; public string Value { get { if (pValue == 0) return string.Empty; return Marshal.PtrToStringAnsi((nint)pValue); } set => pValue = (long)Marshal.StringToHGlobalAnsi(value); } public UnmanagedString(string in_value) { Value = in_value; } public static implicit operator UnmanagedString(string in_value) { return new UnmanagedString(in_value); } public static bool operator ==(UnmanagedString in_left, string in_right) { return in_left.Value == in_right; } public static bool operator !=(UnmanagedString in_left, string in_right) { return !(in_left == in_right); } public override bool Equals(object in_obj) { if (in_obj is string str) return Value == str; return base.Equals(in_obj); } public override int GetHashCode() { return Value.GetHashCode(); } public override string ToString() { return Value; } } public enum MusicType : sbyte { THEME_SONG = 0, OTHER = 1 } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct CustomMusicInfo { [FieldOffset(0x00)] public UnmanagedString cueName; [FieldOffset(0x10)] public float fadeOutTiming; [FieldOffset(0x14)] public bool _lock; [FieldOffset(0x15)] public MusicType musicType; } [StructLayout(LayoutKind.Explicit, Size = 0xC10)] public struct Root { [FieldOffset(0x00)] public CustomMusicTransitInfo transitInfo; [FieldOffset(0x08)] public unsafe fixed byte /* CustomMusicInfo[128] */ _musicInfos[3072]; public unsafe CustomMusicInfo* musicInfos { get { fixed (byte* p_musicInfos = _musicInfos) return (CustomMusicInfo*)p_musicInfos; } } [FieldOffset(0xC08)] public float idlingViewTime; } } Library "TailsParameters" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamOffensive { [FieldOffset(0x00)] public ushort pointMin; [FieldOffset(0x02)] public ushort pointMax; [FieldOffset(0x04)] public float damageRandomRate; [FieldOffset(0x08)] public float damageRandomRateSS; [FieldOffset(0x0C)] public float shapeDamageRate; [FieldOffset(0x10)] public float shapeStunRate; [FieldOffset(0x14)] public float shapeStaggerRate; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDefensive { [FieldOffset(0x00)] public byte rateMin; [FieldOffset(0x01)] public byte rateMax; [FieldOffset(0x02)] public ushort infimumDropRings; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamAttackCommon { [FieldOffset(0x00)] public PlayerParamOffensive offensive; [FieldOffset(0x18)] public PlayerParamDefensive defensive; [FieldOffset(0x1C)] public float criticalDamageRate; [FieldOffset(0x20)] public float criticalRate; [FieldOffset(0x24)] public float criticalRateSS; [FieldOffset(0x28)] public float downedDamageRate; } public enum HitSE : sbyte { SE_None = -1, Weak = 0, Strong = 1, VeryStrong = 2 } [StructLayout(LayoutKind.Explicit, Size = 8)] public struct UnmanagedString { [FieldOffset(0)] public long pValue; public string Value { get { if (pValue == 0) return string.Empty; return Marshal.PtrToStringAnsi((nint)pValue); } set => pValue = (long)Marshal.StringToHGlobalAnsi(value); } public UnmanagedString(string in_value) { Value = in_value; } public static implicit operator UnmanagedString(string in_value) { return new UnmanagedString(in_value); } public static bool operator ==(UnmanagedString in_left, string in_right) { return in_left.Value == in_right; } public static bool operator !=(UnmanagedString in_left, string in_right) { return !(in_left == in_right); } public override bool Equals(object in_obj) { if (in_obj is string str) return Value == str; return base.Equals(in_obj); } public override int GetHashCode() { return Value.GetHashCode(); } public override string ToString() { return Value; } } [StructLayout(LayoutKind.Explicit, Size = 0x160)] public struct PlayerParamAttackData { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float damageRateSS; [FieldOffset(0x08)] public ushort pointMin; [FieldOffset(0x0A)] public ushort pointMax; [FieldOffset(0x0C)] public float damageRateAcceleMode; [FieldOffset(0x10)] public float damageRateManual; [FieldOffset(0x14)] public float stunPoint; [FieldOffset(0x18)] public float staggerPoint; [FieldOffset(0x20)] public Vector3 velocity; [FieldOffset(0x30)] public float velocityKeepTime; [FieldOffset(0x34)] public float addComboValue; [FieldOffset(0x38)] public float addComboValueAccele; [FieldOffset(0x3C)] public float addComboValueSS; [FieldOffset(0x40)] public float addComboValueAcceleSS; [FieldOffset(0x44)] public float addQuickCyloopEnergy; [FieldOffset(0x48)] public float addQuickCyloopEnergyAccele; [FieldOffset(0x4C)] public float addQuickCyloopEnergySS; [FieldOffset(0x50)] public float addQuickCyloopEnergyAcceleSS; [FieldOffset(0x54)] public float addQuickCyloopEnergyGuard; [FieldOffset(0x58)] public float addQuickCyloopEnergyAcceleGuard; [FieldOffset(0x60)] public Vector3 gimmickVelocity; [FieldOffset(0x70)] public float ignoreTime; [FieldOffset(0x74)] public uint attributes; [FieldOffset(0x78)] public HitSE se; [FieldOffset(0x80)] public UnmanagedString hitEffectName; [FieldOffset(0x90)] public UnmanagedString hitEffectNameSS; [FieldOffset(0xA0)] public UnmanagedString hitStopName; [FieldOffset(0xB0)] public UnmanagedString hitStopNameDead; [FieldOffset(0xC0)] public UnmanagedString hitStopNameDeadBoss; [FieldOffset(0xD0)] public UnmanagedString hitStopNameSS; [FieldOffset(0xE0)] public UnmanagedString hitStopNameDeadSS; [FieldOffset(0xF0)] public UnmanagedString hitCameraShakeName; [FieldOffset(0x100)] public UnmanagedString hitCameraShakeNameDead; [FieldOffset(0x110)] public UnmanagedString hitCameraShakeNameDeadBoss; [FieldOffset(0x120)] public UnmanagedString hitCameraShakeNameSS; [FieldOffset(0x130)] public UnmanagedString hitCameraShakeNameDeadSS; [FieldOffset(0x140)] public UnmanagedString hitVibrationName; [FieldOffset(0x150)] public UnmanagedString hitVibrationNameSS; } [StructLayout(LayoutKind.Explicit, Size = 0x4A70)] public struct PlayerParamAttack { [FieldOffset(0x00)] public PlayerParamAttackCommon common; [FieldOffset(0x30)] public PlayerParamAttackData spinAttack; [FieldOffset(0x190)] public PlayerParamAttackData spinDash; [FieldOffset(0x2F0)] public PlayerParamAttackData homingAttack; [FieldOffset(0x450)] public PlayerParamAttackData homingAttackAir; [FieldOffset(0x5B0)] public PlayerParamAttackData pursuitKick; [FieldOffset(0x710)] public PlayerParamAttackData stomping; [FieldOffset(0x870)] public PlayerParamAttackData stompingAttack; [FieldOffset(0x9D0)] public PlayerParamAttackData boundStompingLast; [FieldOffset(0xB30)] public PlayerParamAttackData sliding; [FieldOffset(0xC90)] public PlayerParamAttackData loopKick; [FieldOffset(0xDF0)] public PlayerParamAttackData crasher; [FieldOffset(0xF50)] public PlayerParamAttackData spinSlashHoming; [FieldOffset(0x10B0)] public PlayerParamAttackData spinSlash; [FieldOffset(0x1210)] public PlayerParamAttackData spinSlashLast; [FieldOffset(0x1370)] public PlayerParamAttackData sonicBoom; [FieldOffset(0x14D0)] public PlayerParamAttackData crossSlash; [FieldOffset(0x1630)] public PlayerParamAttackData homingShot; [FieldOffset(0x1790)] public PlayerParamAttackData chargeAttack; [FieldOffset(0x18F0)] public PlayerParamAttackData chargeAttackLast; [FieldOffset(0x1A50)] public PlayerParamAttackData cyloop; [FieldOffset(0x1BB0)] public PlayerParamAttackData cyloopQuick; [FieldOffset(0x1D10)] public PlayerParamAttackData cyloopAerial; [FieldOffset(0x1E70)] public PlayerParamAttackData accele1; [FieldOffset(0x1FD0)] public PlayerParamAttackData accele2; [FieldOffset(0x2130)] public PlayerParamAttackData aerialAccele1; [FieldOffset(0x2290)] public PlayerParamAttackData aerialAccele2; [FieldOffset(0x23F0)] public PlayerParamAttackData comboFinish; [FieldOffset(0x2550)] public PlayerParamAttackData comboFinishF; [FieldOffset(0x26B0)] public PlayerParamAttackData comboFinishB; [FieldOffset(0x2810)] public PlayerParamAttackData comboFinishL; [FieldOffset(0x2970)] public PlayerParamAttackData comboFinishR; [FieldOffset(0x2AD0)] public PlayerParamAttackData acceleComboFinish; [FieldOffset(0x2C30)] public PlayerParamAttackData acceleComboFinishF; [FieldOffset(0x2D90)] public PlayerParamAttackData acceleComboFinishB; [FieldOffset(0x2EF0)] public PlayerParamAttackData acceleComboFinishL; [FieldOffset(0x3050)] public PlayerParamAttackData acceleComboFinishR; [FieldOffset(0x31B0)] public PlayerParamAttackData smash; [FieldOffset(0x3310)] public PlayerParamAttackData smashLast; [FieldOffset(0x3470)] public PlayerParamAttackData slingShot; [FieldOffset(0x35D0)] public PlayerParamAttackData knucklesPunch1; [FieldOffset(0x3730)] public PlayerParamAttackData knucklesPunch2; [FieldOffset(0x3890)] public PlayerParamAttackData knucklesUppercut; [FieldOffset(0x39F0)] public PlayerParamAttackData knucklesHeatKnuckle; [FieldOffset(0x3B50)] public PlayerParamAttackData knucklesHeatKnuckleLast; [FieldOffset(0x3CB0)] public PlayerParamAttackData amyTarotAttack; [FieldOffset(0x3E10)] public PlayerParamAttackData amyTarotAttack2; [FieldOffset(0x3F70)] public PlayerParamAttackData amyTarotRolling; [FieldOffset(0x40D0)] public PlayerParamAttackData amyCharmAttack; [FieldOffset(0x4230)] public PlayerParamAttackData amyTarotBoost; [FieldOffset(0x4390)] public PlayerParamAttackData tailsSpanner; [FieldOffset(0x44F0)] public PlayerParamAttackData tailsSpannerFloat; [FieldOffset(0x4650)] public PlayerParamAttackData tailsPowerBoost; [FieldOffset(0x47B0)] public PlayerParamAttackData tailsWaveCannon; [FieldOffset(0x4910)] public PlayerParamAttackData tailsWaveCannonFinish; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamWaterAct { [FieldOffset(0x00)] public float resistRate; [FieldOffset(0x04)] public float breatheBrake; [FieldOffset(0x08)] public float breatheTime; [FieldOffset(0x0C)] public float breatheGravity; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBaseJump { [FieldOffset(0x00)] public float baseSpeed; [FieldOffset(0x04)] public float upSpeed; [FieldOffset(0x08)] public float upSpeedAir; [FieldOffset(0x0C)] public float edgeSpeed; [FieldOffset(0x10)] public float airActionTime; [FieldOffset(0x14)] public float wallMoveTime; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamBallMove { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float slidePower; [FieldOffset(0x08)] public float brakeForce; [FieldOffset(0x0C)] public float slidePowerSlalom; [FieldOffset(0x10)] public float brakeForceSlalom; [FieldOffset(0x14)] public float releaseSpeed; [FieldOffset(0x18)] public bool useInput; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamLocusData { [FieldOffset(0x00)] public float width; [FieldOffset(0x04)] public float distance; [FieldOffset(0x08)] public float u0; [FieldOffset(0x0C)] public float u1; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamLocus { [FieldOffset(0x00)] public unsafe fixed byte /* PlayerParamLocusData[4] */ _data[64]; public unsafe PlayerParamLocusData* data { get { fixed (byte* p_data = _data) return (PlayerParamLocusData*)p_data; } } } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAuraTrain { [FieldOffset(0x00)] public float effectSpanTime; [FieldOffset(0x04)] public float effectLifeTime; [FieldOffset(0x08)] public float effectOffsetDistance; [FieldOffset(0x0C)] public float effectOverlapDistance; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamLevel { [FieldOffset(0x00)] public byte ringsLevel; [FieldOffset(0x01)] public byte speedLevel; [FieldOffset(0x02)] public byte offensiveLevel; [FieldOffset(0x03)] public byte defensiveLevel; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamBarrierWall { [FieldOffset(0x00)] public float coolTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamDamageRateLevel { [FieldOffset(0x00)] public unsafe fixed float rates[5]; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerParamDamageRate { [FieldOffset(0x00)] public unsafe fixed byte /* PlayerParamDamageRateLevel[4] */ _diffculties[80]; public unsafe PlayerParamDamageRateLevel* diffculties { get { fixed (byte* p_diffculties = _diffculties) return (PlayerParamDamageRateLevel*)p_diffculties; } } } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamAcceleMode { [FieldOffset(0x00)] public float declineSpeed; [FieldOffset(0x04)] public float declineSpeedAccele; [FieldOffset(0x08)] public float lossDamaged; [FieldOffset(0x0C)] public float lossDamagedAccele; [FieldOffset(0x10)] public uint comboRateAccele; } [StructLayout(LayoutKind.Explicit, Size = 0x4B70)] public struct CommonPackage { [FieldOffset(0x00)] public PlayerParamAttack attack; [FieldOffset(0x4A70)] public PlayerParamWaterAct wateract; [FieldOffset(0x4A80)] public PlayerParamBaseJump basejump; [FieldOffset(0x4A98)] public PlayerParamBallMove ballmove; [FieldOffset(0x4AB4)] public PlayerParamLocus locus; [FieldOffset(0x4AF4)] public PlayerParamAuraTrain auratrain; [FieldOffset(0x4B04)] public PlayerParamLevel level; [FieldOffset(0x4B08)] public PlayerParamBarrierWall barrierWall; [FieldOffset(0x4B0C)] public PlayerParamDamageRate damageRate; [FieldOffset(0x4B5C)] public PlayerParamAcceleMode acceleMode; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamComboCommon { [FieldOffset(0x00)] public float longPressTime; } public enum ComboMoveType : byte { Homing = 0, Step = 1, None = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamComboMove { [FieldOffset(0x00)] public ComboMoveType moveType; [FieldOffset(0x04)] public float moveInitialSpeed; [FieldOffset(0x08)] public float moveMaxSpeed; [FieldOffset(0x0C)] public float moveAccele; [FieldOffset(0x10)] public float timeout; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct PlayerParamComboMoveCorrection { [FieldOffset(0x00)] public float moveSpeed; [FieldOffset(0x04)] public float rotateSpeed; } public enum Action : sbyte { Root = 0, HomingAttack = 1, AerialHomingAttack = 2, Pursuit = 3, Stomping = 4, LoopKick = 5, Crasher = 6, SpinSlash = 7, SonicBoom = 8, CrossSlash = 9, HomingShot = 10, ChargeAttack = 11, QuickCyloop = 12, AerialQuickCyloop = 13, AcceleCombo1 = 14, AcceleCombo2 = 15, AcceleCombo3 = 16, AcceleCombo4 = 17, AerialAcceleCombo1 = 18, AerialAcceleCombo2 = 19, AerialAcceleCombo3 = 20, AerialAcceleCombo4 = 21, ComboFinish = 22, SpinJump = 23, Smash = 24, Behind = 25, Guarded = 26, Avoid = 27, AirBoost = 28, AfterAirBoost = 29, KnucklesPunch1 = 30, KnucklesPunch2 = 31, KnucklesUppercut = 32, KnucklesCyKnuckle = 33, KnucklesHeatKnuckle = 34, AmyTarotAttack = 35, AmyTarotAttack2 = 36, AmyTarotRolling = 37, AmyCyHammer = 38, AmyCharmAttack = 39, TailsSpanner = 40, ActionNum = 41 } [StructLayout(LayoutKind.Explicit, Size = 0x12)] public struct PlayerParamComboTransit { [FieldOffset(0x00)] public unsafe fixed byte /* Action[6] */ _transitExistTarget[6]; public unsafe Action* transitExistTarget { get { fixed (byte* p_transitExistTarget = _transitExistTarget) return (Action*)p_transitExistTarget; } } [FieldOffset(0x06)] public unsafe fixed byte /* Action[6] */ _transitInAir[6]; public unsafe Action* transitInAir { get { fixed (byte* p_transitInAir = _transitInAir) return (Action*)p_transitInAir; } } [FieldOffset(0x0C)] public unsafe fixed byte /* Action[6] */ _transitNotExistTarget[6]; public unsafe Action* transitNotExistTarget { get { fixed (byte* p_transitNotExistTarget = _transitNotExistTarget) return (Action*)p_transitNotExistTarget; } } } [StructLayout(LayoutKind.Explicit, Size = 0x2AC)] public struct PlayerParamComboTransitTable { [FieldOffset(0x00)] public PlayerParamComboTransit root; [FieldOffset(0x12)] public PlayerParamComboTransit homingAttack; [FieldOffset(0x24)] public PlayerParamComboTransit aerialHoming; [FieldOffset(0x36)] public PlayerParamComboTransit pursuit; [FieldOffset(0x48)] public PlayerParamComboTransit stomping; [FieldOffset(0x5A)] public PlayerParamComboTransit loopKick; [FieldOffset(0x6C)] public PlayerParamComboTransit crasher; [FieldOffset(0x7E)] public PlayerParamComboTransit spinSlash; [FieldOffset(0x90)] public PlayerParamComboTransit sonicBoom; [FieldOffset(0xA2)] public PlayerParamComboTransit crossSlash; [FieldOffset(0xB4)] public PlayerParamComboTransit homingShot; [FieldOffset(0xC6)] public PlayerParamComboTransit chargeAttack; [FieldOffset(0xD8)] public PlayerParamComboTransit quickCyloop; [FieldOffset(0xEA)] public PlayerParamComboTransit aerialQuickCyloop; [FieldOffset(0xFC)] public PlayerParamComboTransit acceleCombo1; [FieldOffset(0x10E)] public PlayerParamComboTransit acceleCombo2; [FieldOffset(0x120)] public PlayerParamComboTransit acceleCombo3; [FieldOffset(0x132)] public PlayerParamComboTransit acceleCombo4; [FieldOffset(0x144)] public PlayerParamComboTransit aerialAcceleCombo1; [FieldOffset(0x156)] public PlayerParamComboTransit aerialAcceleCombo2; [FieldOffset(0x168)] public PlayerParamComboTransit aerialAcceleCombo3; [FieldOffset(0x17A)] public PlayerParamComboTransit aerialAcceleCombo4; [FieldOffset(0x18C)] public PlayerParamComboTransit behind; [FieldOffset(0x19E)] public PlayerParamComboTransit guarded; [FieldOffset(0x1B0)] public PlayerParamComboTransit avoid; [FieldOffset(0x1C2)] public PlayerParamComboTransit airBoost; [FieldOffset(0x1D4)] public PlayerParamComboTransit afterAirBoost; [FieldOffset(0x1E6)] public PlayerParamComboTransit knucklesPunch1; [FieldOffset(0x1F8)] public PlayerParamComboTransit knucklesPunch2; [FieldOffset(0x20A)] public PlayerParamComboTransit knucklesUppercut; [FieldOffset(0x21C)] public PlayerParamComboTransit knucklesCyKnuckle; [FieldOffset(0x22E)] public PlayerParamComboTransit knucklesHeatKnuckle; [FieldOffset(0x240)] public PlayerParamComboTransit amyTarotAttack; [FieldOffset(0x252)] public PlayerParamComboTransit amyTarotAttack2; [FieldOffset(0x264)] public PlayerParamComboTransit amyTarotRolling; [FieldOffset(0x276)] public PlayerParamComboTransit amyCyHammer; [FieldOffset(0x288)] public PlayerParamComboTransit amyCharmAttack; [FieldOffset(0x29A)] public PlayerParamComboTransit tailsSpanner; } [StructLayout(LayoutKind.Explicit, Size = 0x2E0)] public struct PlayerParamCombo { [FieldOffset(0x00)] public PlayerParamComboCommon common; [FieldOffset(0x04)] public PlayerParamComboMove comboMoveSonic; [FieldOffset(0x18)] public PlayerParamComboMove comboMoveSupersonic; [FieldOffset(0x2C)] public PlayerParamComboMoveCorrection comboMoveCorrection; [FieldOffset(0x34)] public PlayerParamComboTransitTable comboTable; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct TailsParamParryDebuff { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float effectTime; } [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct CyloopSlashEffectBaseParameter { [FieldOffset(0x00)] public int m_divideCircle; [FieldOffset(0x04)] public float m_circleRadius; [FieldOffset(0x08)] public float m_circleWaveCycle; [FieldOffset(0x0C)] public float m_circleWaveWidth; [FieldOffset(0x10)] public float m_circleWaveSpeed; [FieldOffset(0x14)] public Vector2 m_scale; [FieldOffset(0x20)] public UnmanagedString m_textureName; [FieldOffset(0x30)] public float m_flowSpeed; [FieldOffset(0x34)] public float m_twistCycle; [FieldOffset(0x38)] public float m_rollCycle; [FieldOffset(0x3C)] public float m_rollPhase; [FieldOffset(0x40)] public float m_alphaHeadDistance; [FieldOffset(0x44)] public float m_alphaTailDistance; [FieldOffset(0x48)] public float m_offsetCycle; [FieldOffset(0x4C)] public float m_offsetPhase; [FieldOffset(0x50)] public float m_offsetRadius; } public struct ColorF { public float A; public float R; public float G; public float B; } [StructLayout(LayoutKind.Explicit, Size = 0xA8)] public struct CyloopTransparentLocusParameter { [FieldOffset(0)] public CyloopSlashEffectBaseParameter cyloopSlashEffectBaseParameter; [FieldOffset(0x58)] public ColorF m_color0; [FieldOffset(0x68)] public ColorF m_color1; [FieldOffset(0x78)] public float m_luminance; [FieldOffset(0x7C)] public ColorF m_flashColor0; [FieldOffset(0x8C)] public ColorF m_flashColor1; [FieldOffset(0x9C)] public float m_flashLuminance; [FieldOffset(0xA0)] public float m_flashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct OpaqueLineUvCell { [FieldOffset(0x00)] public float scale; [FieldOffset(0x04)] public float speedX; [FieldOffset(0x08)] public float speedY; } [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct CyloopOpaqueLocusParameter { [FieldOffset(0)] public CyloopSlashEffectBaseParameter cyloopSlashEffectBaseParameter; [FieldOffset(0x58)] public ColorF m_color; [FieldOffset(0x68)] public float m_alphaThreshold; [FieldOffset(0x6C)] public unsafe fixed byte /* OpaqueLineUvCell[2] */ _m_uvCells[24]; public unsafe OpaqueLineUvCell* m_uvCells { get { fixed (byte* p_m_uvCells = _m_uvCells) return (OpaqueLineUvCell*)p_m_uvCells; } } [FieldOffset(0x84)] public float m_uvLineScaleX; [FieldOffset(0x88)] public float m_uvLineScaleY; [FieldOffset(0x8C)] public ColorF m_flashColor; [FieldOffset(0x9C)] public float m_flashTime; } [StructLayout(LayoutKind.Explicit, Size = 0xF0)] public struct CyloopCrossLineParameter { [FieldOffset(0x00)] public UnmanagedString m_textureNamePattern; [FieldOffset(0x10)] public UnmanagedString m_textureNameDist; [FieldOffset(0x20)] public ColorF startColor; [FieldOffset(0x30)] public ColorF endColor; [FieldOffset(0x40)] public float startColorLuminance; [FieldOffset(0x44)] public float endColorLuminance; [FieldOffset(0x48)] public ColorF startColorFlash; [FieldOffset(0x58)] public ColorF endColorFlash; [FieldOffset(0x68)] public float startColorLuminanceFlash; [FieldOffset(0x6C)] public float endColorLuminanceFlash; [FieldOffset(0x70)] public float flashTime; [FieldOffset(0x74)] public float patternDepth; [FieldOffset(0x78)] public float patternScrollSpeed; [FieldOffset(0x7C)] public float patternDarkness; [FieldOffset(0x80)] public float patternScale; [FieldOffset(0x84)] public float glitchResX; [FieldOffset(0x88)] public float glitchResY; [FieldOffset(0x8C)] public float glitchOffset; [FieldOffset(0x90)] public float glitchMaxLength; [FieldOffset(0x94)] public float startGlitchScrollSpeed; [FieldOffset(0x98)] public float startGlitchChangeSpeed; [FieldOffset(0x9C)] public float startGlitchShift; [FieldOffset(0xA0)] public float startGlitchContrust; [FieldOffset(0xA4)] public float endGlitchScrollSpeed; [FieldOffset(0xA8)] public float endGlitchChangeSpeed; [FieldOffset(0xAC)] public float endGlitchShift; [FieldOffset(0xB0)] public float endGlitchContrust; [FieldOffset(0xB4)] public float lineWidth; [FieldOffset(0xB8)] public float lineDisplayWidth; [FieldOffset(0xBC)] public float lineBlackEdgeWidth; [FieldOffset(0xC0)] public float lineBlackEdgeIntensity; [FieldOffset(0xC4)] public float lineBlackEdgeNormalFade; [FieldOffset(0xC8)] public float distNoiseScale; [FieldOffset(0xCC)] public float distLowNoiseScale; [FieldOffset(0xD0)] public float distHighNoiseScale; [FieldOffset(0xD4)] public float distNoiseRate; [FieldOffset(0xD8)] public float distScrollSpeed; [FieldOffset(0xDC)] public float distIntensity; [FieldOffset(0xE0)] public float dissolve; [FieldOffset(0xE4)] public float dissolveRate; [FieldOffset(0xE8)] public float heightOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x4E0)] public struct CyloopLocusParameter { [FieldOffset(0x00)] public int m_numTransparentLines; [FieldOffset(0x08)] public unsafe fixed byte /* CyloopTransparentLocusParameter[3] */ _m_transparentLines[504]; public unsafe CyloopTransparentLocusParameter* m_transparentLines { get { fixed (byte* p_m_transparentLines = _m_transparentLines) return (CyloopTransparentLocusParameter*)p_m_transparentLines; } } [FieldOffset(0x200)] public int m_numOpaqueLines; [FieldOffset(0x208)] public unsafe fixed byte /* CyloopOpaqueLocusParameter[3] */ _m_opaqueLines[480]; public unsafe CyloopOpaqueLocusParameter* m_opaqueLines { get { fixed (byte* p_m_opaqueLines = _m_opaqueLines) return (CyloopOpaqueLocusParameter*)p_m_opaqueLines; } } [FieldOffset(0x3E8)] public int m_numCrossLines; [FieldOffset(0x3F0)] public CyloopCrossLineParameter m_crossline; } [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct CyloopDropItemWeightParameter { [FieldOffset(0x00)] public uint noneWeight; [FieldOffset(0x04)] public uint ring10Weight; [FieldOffset(0x08)] public uint powerSeedWeight; [FieldOffset(0x0C)] public uint guardSeedWeight; [FieldOffset(0x10)] public uint sequenceItemWeight; [FieldOffset(0x14)] public uint portalBitWeight; [FieldOffset(0x18)] public uint skillPieceWeight; [FieldOffset(0x1C)] public uint skillPieceAmyWeight; [FieldOffset(0x20)] public uint skillPieceKnucklesWeight; [FieldOffset(0x24)] public uint skillPieceTailsWeight; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct CyloopDropItemParameter { [FieldOffset(0x00)] public CyloopDropItemWeightParameter weight; [FieldOffset(0x28)] public CyloopDropItemWeightParameter weight2; [FieldOffset(0x50)] public uint numRings; [FieldOffset(0x54)] public uint numRings2; [FieldOffset(0x58)] public uint num10Rings; [FieldOffset(0x5C)] public uint numSkillPieces; [FieldOffset(0x60)] public uint skillPieceExp; [FieldOffset(0x64)] public float rareDropCoolTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct CyloopShapeWindCountParameter { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float stunRate; [FieldOffset(0x08)] public float staggerRate; [FieldOffset(0x0C)] public float velocityRate; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct CyloopShapeWindEffectParaemter { [FieldOffset(0x00)] public unsafe fixed byte /* CyloopShapeWindCountParameter[5] */ _param[80]; public unsafe CyloopShapeWindCountParameter* param { get { fixed (byte* p_param = _param) return (CyloopShapeWindCountParameter*)p_param; } } } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct CyloopShapeEffectParameter { [FieldOffset(0x00)] public CyloopShapeWindEffectParaemter wind; } [StructLayout(LayoutKind.Explicit, Size = 0x1460)] public struct PlayerParamCyloop { [FieldOffset(0x00)] public CyloopLocusParameter locus; [FieldOffset(0x4E0)] public CyloopLocusParameter locusQuick; [FieldOffset(0x9C0)] public CyloopLocusParameter locusSuperSonic; [FieldOffset(0xEA0)] public CyloopLocusParameter locusSuperSonicQuick; [FieldOffset(0x1380)] public ColorF auraColor; [FieldOffset(0x1390)] public CyloopDropItemParameter dropItem; [FieldOffset(0x13F8)] public float needSpeed; [FieldOffset(0x13FC)] public CyloopShapeEffectParameter shapeEffect; [FieldOffset(0x144C)] public float lossQuickCyloopEnergy; [FieldOffset(0x1450)] public float recoveryQuickCyloopEnergyByTime; [FieldOffset(0x1454)] public float recoveryQuickCyloopEnergyByTimeInMinigame; [FieldOffset(0x1458)] public float recoveryFriendsQuickCyloopEnergyByRing; } [StructLayout(LayoutKind.Explicit, Size = 0x62C0)] public struct CommonPackageTails { [FieldOffset(0)] public CommonPackage commonPackage; [FieldOffset(0x4B70)] public PlayerParamCombo combo; [FieldOffset(0x4E50)] public TailsParamParryDebuff parryDebuff; [FieldOffset(0x4E58)] public PlayerParamCyloop cyloop; } public enum SupportedPlane : sbyte { Flat = 0, Slope = 1, Wall = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamCommon { [FieldOffset(0x00)] public float movableMaxSlope; [FieldOffset(0x04)] public float activeLandingSlope; [FieldOffset(0x08)] public float activeLandingSlopeInBoost; [FieldOffset(0x0C)] public float landingMaxSlope; [FieldOffset(0x10)] public float slidingMaxSlope; [FieldOffset(0x14)] public float wallAngleMaxSlope; [FieldOffset(0x18)] public SupportedPlane onStand; [FieldOffset(0x19)] public SupportedPlane onRunInAir; [FieldOffset(0x1A)] public SupportedPlane onRun; [FieldOffset(0x1B)] public bool moveHolding; [FieldOffset(0x1C)] public bool wallSlideSlowInBoost; [FieldOffset(0x1D)] public bool attrWallOnGround; [FieldOffset(0x20)] public float priorityInputTime; [FieldOffset(0x24)] public int capacityRings; [FieldOffset(0x28)] public int capacityRingsLvMax; [FieldOffset(0x2C)] public float collectRingRange; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamSpeedData { [FieldOffset(0x00)] public float initial; [FieldOffset(0x04)] public float min; [FieldOffset(0x08)] public float max; [FieldOffset(0x0C)] public float minTurn; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamSpeedAcceleData { [FieldOffset(0x00)] public float force; [FieldOffset(0x04)] public float force2; [FieldOffset(0x08)] public float damperRange; [FieldOffset(0x0C)] public float jerkMin; [FieldOffset(0x10)] public float jerkMax; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamSpeedAcceleData2 { [FieldOffset(0x00)] public float force; [FieldOffset(0x04)] public float damperRange; [FieldOffset(0x08)] public float jerkMin; [FieldOffset(0x0C)] public float jerkMax; } [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct PlayerParamSpeed { [FieldOffset(0x00)] public PlayerParamSpeedData normal; [FieldOffset(0x10)] public PlayerParamSpeedData normal2; [FieldOffset(0x20)] public PlayerParamSpeedData boost; [FieldOffset(0x30)] public PlayerParamSpeedData boost2; [FieldOffset(0x40)] public PlayerParamSpeedData boostLvMax; [FieldOffset(0x50)] public PlayerParamSpeedData boostLvMax2; [FieldOffset(0x60)] public float maxSpeedOver; [FieldOffset(0x64)] public float opitonMaxSpeedLimitMin; [FieldOffset(0x68)] public float opitonMaxSpeedLimitMax; [FieldOffset(0x6C)] public float thresholdStopSpeed; [FieldOffset(0x70)] public float maxFallSpeed; [FieldOffset(0x74)] public PlayerParamSpeedAcceleData accele; [FieldOffset(0x88)] public PlayerParamSpeedAcceleData decele; [FieldOffset(0x9C)] public PlayerParamSpeedAcceleData2 deceleNeutralMin; [FieldOffset(0xAC)] public PlayerParamSpeedAcceleData2 deceleNeutralMax; [FieldOffset(0xBC)] public float acceleAuto; [FieldOffset(0xC0)] public float deceleAuto; [FieldOffset(0xC4)] public float turnDeceleAngleMin; [FieldOffset(0xC8)] public float turnDeceleAngleMax; [FieldOffset(0xCC)] public float maxGravityAccele; [FieldOffset(0xD0)] public float maxGravityDecele; [FieldOffset(0xD4)] public float deceleSquat; [FieldOffset(0xD8)] public float acceleSensitive; [FieldOffset(0xDC)] public float boostAnimSpeedInWater; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamRotation { [FieldOffset(0x00)] public float baseRotateForce; [FieldOffset(0x04)] public float baseRotateForce2; [FieldOffset(0x08)] public float baseRotateForceSpeed; [FieldOffset(0x0C)] public float minRotateForce; [FieldOffset(0x10)] public float maxRotateForce; [FieldOffset(0x14)] public bool angleRotateForceDecayEnabled; [FieldOffset(0x18)] public float frontRotateRatio; [FieldOffset(0x1C)] public float rotationForceDecaySpeed; [FieldOffset(0x20)] public float rotationForceDecayRate; [FieldOffset(0x24)] public float rotationForceDecayMax; [FieldOffset(0x28)] public float autorunRotateForce; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamRunning { [FieldOffset(0x00)] public float walkSpeed; [FieldOffset(0x04)] public float sneakingSpeed; [FieldOffset(0x08)] public float animSpeedSneak; [FieldOffset(0x0C)] public float animSpeedWalk; [FieldOffset(0x10)] public float animSpeedRun; [FieldOffset(0x14)] public float animSpeedBoost; [FieldOffset(0x18)] public float animLRBlendSampleTime; [FieldOffset(0x1C)] public float animLRBlendAngleMin; [FieldOffset(0x20)] public float animLRBlendAngleMax; [FieldOffset(0x24)] public float animLRBlendSpeed; [FieldOffset(0x28)] public float animLRBlendSpeedToCenter; [FieldOffset(0x2C)] public float minChangeWalkTime; [FieldOffset(0x30)] public float fallAnimationAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamBalanceData { [FieldOffset(0x00)] public float rotateSpeedMinFB; [FieldOffset(0x04)] public float rotateSpeedMaxFB; [FieldOffset(0x08)] public float rotateSpeedMinLR; [FieldOffset(0x0C)] public float rotateSpeedMaxLR; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamBalance { [FieldOffset(0x00)] public PlayerParamBalanceData standard; [FieldOffset(0x10)] public PlayerParamBalanceData loop; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBrake { [FieldOffset(0x00)] public float initialSpeedRatio; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float forceLand; [FieldOffset(0x0C)] public float forceAir; [FieldOffset(0x10)] public float endSpeed; [FieldOffset(0x14)] public float stopTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamTurn { [FieldOffset(0x00)] public float thresholdSpeed; [FieldOffset(0x04)] public float thresholdAngle; [FieldOffset(0x08)] public float turnAfterSpeed; [FieldOffset(0x0C)] public bool stopEdge; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamJump { [FieldOffset(0x00)] public float preActionTime; [FieldOffset(0x04)] public float longPressTime; [FieldOffset(0x08)] public float addForceTime; [FieldOffset(0x0C)] public float force; [FieldOffset(0x10)] public float addForce; [FieldOffset(0x14)] public float forceMin; [FieldOffset(0x18)] public float gravitySize; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamJumpSpeed { [FieldOffset(0x00)] public float acceleForce; [FieldOffset(0x04)] public float deceleForce; [FieldOffset(0x08)] public float deceleNeutralForce; [FieldOffset(0x0C)] public float deceleBackForce; [FieldOffset(0x10)] public float limitMin; [FieldOffset(0x14)] public float limitUpSpeed; [FieldOffset(0x18)] public float rotationForce; [FieldOffset(0x1C)] public float rotationForceDecaySpeed; [FieldOffset(0x20)] public float rotationForceDecayRate; [FieldOffset(0x24)] public float rotationForceDecayMax; [FieldOffset(0x28)] public float baseAirDragScaleMin; [FieldOffset(0x2C)] public float baseAirDragScaleMax; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDoubleJump { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float bounceSpeed; [FieldOffset(0x08)] public float limitSpeedMin; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamFall { [FieldOffset(0x00)] public float thresholdVertSpeed; [FieldOffset(0x04)] public float tolerateJumpTime; [FieldOffset(0x08)] public float fallEndDelayTime; [FieldOffset(0x0C)] public float fallEndFadeTime; [FieldOffset(0x10)] public float acceleForce; [FieldOffset(0x14)] public float deceleForce; [FieldOffset(0x18)] public float overSpeedDeceleForce; [FieldOffset(0x1C)] public float rotationForce; [FieldOffset(0x20)] public float rotationForceDecaySpeed; [FieldOffset(0x24)] public float rotationForceDecayRate; [FieldOffset(0x28)] public float rotationForceDecayMax; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageCommon { [FieldOffset(0x00)] public float invincibleTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamDamageNormal { [FieldOffset(0x00)] public float initialHorzSpeed; [FieldOffset(0x04)] public float initialVertSpeed; [FieldOffset(0x08)] public float deceleForce; [FieldOffset(0x0C)] public float transitFallTime; [FieldOffset(0x10)] public float gravityScale; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageTurnBack { [FieldOffset(0x00)] public float fixedTime; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamDamageBlowOff { [FieldOffset(0x00)] public float initialHorzSpeed; [FieldOffset(0x04)] public float initialVertSpeed; [FieldOffset(0x08)] public float deceleForceInAir; [FieldOffset(0x0C)] public float deceleForceOnGround; [FieldOffset(0x10)] public float gravityScale; [FieldOffset(0x14)] public float downTime; [FieldOffset(0x18)] public float transitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamDamageGuarded { [FieldOffset(0x00)] public float vertSpeed; [FieldOffset(0x04)] public float horzSpeed; [FieldOffset(0x08)] public float deceleForce; [FieldOffset(0x0C)] public float transitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamDamageRunning { [FieldOffset(0x00)] public float actionTime; [FieldOffset(0x04)] public float minSpeed; [FieldOffset(0x08)] public float lossSpeed; [FieldOffset(0x0C)] public float lossTime; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageQuake { [FieldOffset(0x00)] public float actionTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamDamageLava { [FieldOffset(0x00)] public Vector3 jumpVelocity; [FieldOffset(0x10)] public float gravitySize; [FieldOffset(0x14)] public float invincibleTime; [FieldOffset(0x18)] public float noActionTime; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerParamDamageMine { [FieldOffset(0x00)] public Vector3 jumpVelocity; [FieldOffset(0x10)] public float gravitySize; [FieldOffset(0x14)] public float invincibleTime; [FieldOffset(0x18)] public float noActionTime; [FieldOffset(0x1C)] public float gravitySizeForFall; [FieldOffset(0x20)] public float maxFallSpeed; [FieldOffset(0x28)] public UnmanagedString cameraShakeName; [FieldOffset(0x38)] public UnmanagedString vibrationName; } [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct PlayerParamDamage { [FieldOffset(0x00)] public PlayerParamDamageCommon common; [FieldOffset(0x04)] public PlayerParamDamageNormal normal; [FieldOffset(0x18)] public PlayerParamDamageTurnBack turnBack; [FieldOffset(0x1C)] public PlayerParamDamageBlowOff blowOff; [FieldOffset(0x38)] public PlayerParamDamageGuarded guarded; [FieldOffset(0x48)] public PlayerParamDamageGuarded guardedSS; [FieldOffset(0x58)] public PlayerParamDamageRunning running; [FieldOffset(0x68)] public PlayerParamDamageQuake quake; [FieldOffset(0x70)] public PlayerParamDamageLava lava; [FieldOffset(0x90)] public PlayerParamDamageMine mine; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDeadNormal { [FieldOffset(0x00)] public float invincibleTime; [FieldOffset(0x04)] public float initialHorzSpeed; [FieldOffset(0x08)] public float initialVertSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDead { [FieldOffset(0x00)] public PlayerParamDeadNormal normal; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamSliding { [FieldOffset(0x00)] public float minSpeed; [FieldOffset(0x04)] public float endSpeed; [FieldOffset(0x08)] public float deceleJerk; [FieldOffset(0x0C)] public float deceleJerkContinue; [FieldOffset(0x10)] public float deceleForceMax; [FieldOffset(0x14)] public float baseRotateForce; [FieldOffset(0x18)] public float baseRotateForceSpeed; [FieldOffset(0x1C)] public float maxRotateForce; [FieldOffset(0x20)] public float frontRotateRatio; [FieldOffset(0x24)] public float rotationForceAutoRun; [FieldOffset(0x28)] public float movableMaxSlope; [FieldOffset(0x2C)] public float gravitySize; [FieldOffset(0x30)] public float minContinueTime; [FieldOffset(0x34)] public float maxAutoRunTime; [FieldOffset(0x38)] public float endSpeedAutoRun; [FieldOffset(0x3C)] public float loopKickTransitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamStomping { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float initialAccele; [FieldOffset(0x08)] public float maxAccele; [FieldOffset(0x0C)] public float jerk; [FieldOffset(0x10)] public float maxFallSpeed; [FieldOffset(0x14)] public float angle; [FieldOffset(0x18)] public float landingCancelTime; [FieldOffset(0x1C)] public float boundStompingCollisionScale; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamGrind { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float maxBoostSpeed; [FieldOffset(0x08)] public float acceleForce; [FieldOffset(0x0C)] public float deceleForce; [FieldOffset(0x10)] public float limitSpeedMin; } [StructLayout(LayoutKind.Explicit, Size = 0x38)] public struct PlayerParamFallSlope { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float brakeAngle; [FieldOffset(0x0C)] public float highBrakeAngle; [FieldOffset(0x10)] public float brakeForce; [FieldOffset(0x14)] public float brakeForceHigh; [FieldOffset(0x18)] public float gravitySize; [FieldOffset(0x1C)] public float gravitySizeAir; [FieldOffset(0x20)] public float endSpeedFront; [FieldOffset(0x24)] public float endSpeedBack; [FieldOffset(0x28)] public float reverseFallTime; [FieldOffset(0x2C)] public float fallToSlipTime; [FieldOffset(0x30)] public float slipIdlingTime; [FieldOffset(0x34)] public float minSlipTime; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamFallFlip { [FieldOffset(0x00)] public float thresholdSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float flipAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct PlayerParamTumble { [FieldOffset(0x00)] public bool enabled; [FieldOffset(0x04)] public float sideSpinAngle; [FieldOffset(0x08)] public float initialVertSpeed; [FieldOffset(0x0C)] public float gravitySize; [FieldOffset(0x10)] public float gravitySize2; [FieldOffset(0x14)] public float deceleForceInAir; [FieldOffset(0x18)] public float minSpeedInAir; [FieldOffset(0x1C)] public float rotateEaseTimeLeftRight; [FieldOffset(0x20)] public float rotateEaseTimeFrontBack; [FieldOffset(0x24)] public float rotateSpeedMinLeftRight; [FieldOffset(0x28)] public float rotateSpeedMaxLeftRight; [FieldOffset(0x2C)] public float rotateSpeedMinFrontBack; [FieldOffset(0x30)] public float rotateSpeedMaxFrontBack; [FieldOffset(0x34)] public float angleLeftRightStagger; [FieldOffset(0x38)] public float angleLeftRightRoll; [FieldOffset(0x3C)] public float angleFrontBackRoll; [FieldOffset(0x40)] public float angleBigRoll; [FieldOffset(0x44)] public float inRunTime; [FieldOffset(0x48)] public float inAirTime; [FieldOffset(0x4C)] public float rollSpeedFront; [FieldOffset(0x50)] public float bigRollVelocityRatio; [FieldOffset(0x54)] public float dropDashHoldTime; [FieldOffset(0x58)] public float airBrakeVertSpeed; [FieldOffset(0x5C)] public float airBrakeForce; [FieldOffset(0x60)] public float airTrickHeight; [FieldOffset(0x64)] public float airTrickTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSpinAttack { [FieldOffset(0x00)] public float jumpForce; [FieldOffset(0x04)] public float jumpAddForce; [FieldOffset(0x08)] public float addTime; [FieldOffset(0x0C)] public float acceleForce; [FieldOffset(0x10)] public float deceleForce; [FieldOffset(0x14)] public float brakeForce; [FieldOffset(0x18)] public float limitSpeedMin; [FieldOffset(0x1C)] public float limitSpeedMax; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamHomingAttackData { [FieldOffset(0x00)] public float speed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamHomingBounceData { [FieldOffset(0x00)] public float bounceVertSpeed; [FieldOffset(0x04)] public float bounceHorzSpeed; [FieldOffset(0x08)] public float bounceAcceleForce; [FieldOffset(0x0C)] public float bounceDeceleForce; [FieldOffset(0x10)] public float bounceAngleWidth; [FieldOffset(0x14)] public float bounceTime; [FieldOffset(0x18)] public float attackDownTime; [FieldOffset(0x1C)] public float attackDownTimeForStomp; } [StructLayout(LayoutKind.Explicit, Size = 0xB0)] public struct PlayerParamHomingAttack { [FieldOffset(0x00)] public PlayerParamHomingAttackData sonic; [FieldOffset(0x04)] public PlayerParamHomingAttackData supersonic; [FieldOffset(0x08)] public PlayerParamHomingBounceData sonicBounce; [FieldOffset(0x28)] public PlayerParamHomingBounceData sonicBounceWeak; [FieldOffset(0x48)] public PlayerParamHomingBounceData sonicBounceStorm; [FieldOffset(0x68)] public PlayerParamHomingBounceData sonicBounceStormSwirl; [FieldOffset(0x88)] public PlayerParamHomingBounceData supersonicBounce; [FieldOffset(0xA8)] public float cameraEaseInTime; [FieldOffset(0xAC)] public float cameraEaseOutTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamHitEnemy { [FieldOffset(0x00)] public float bounceVertSpeed; [FieldOffset(0x04)] public float bounceHorzSpeed; [FieldOffset(0x08)] public float attackDownTime; [FieldOffset(0x0C)] public float enableHomingTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct SpeedParam { [FieldOffset(0x00)] public float maxVertSpeed; [FieldOffset(0x04)] public float acceleVertForce; [FieldOffset(0x08)] public float maxHorzSpeed; [FieldOffset(0x0C)] public float acceleHorzForce; } [StructLayout(LayoutKind.Explicit, Size = 0x5C)] public struct PlayerParamDiving { [FieldOffset(0x00)] public SpeedParam normal; [FieldOffset(0x10)] public SpeedParam fast; [FieldOffset(0x20)] public SpeedParam damaged; [FieldOffset(0x30)] public SpeedParam ringdash; [FieldOffset(0x40)] public float startHeight; [FieldOffset(0x44)] public float startSpeed; [FieldOffset(0x48)] public float deceleVertForce; [FieldOffset(0x4C)] public float deceleHorzForce; [FieldOffset(0x50)] public float deceleNeutralForce; [FieldOffset(0x54)] public float damageTime; [FieldOffset(0x58)] public float ringdashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamFan { [FieldOffset(0x00)] public float damperV; [FieldOffset(0x04)] public float damperH; [FieldOffset(0x08)] public float accelRate; [FieldOffset(0x0C)] public float moveForceFV; [FieldOffset(0x10)] public float moveForceSV; [FieldOffset(0x14)] public float jumpCheckSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBackflip { [FieldOffset(0x00)] public float jumpSpeed; [FieldOffset(0x04)] public float backSpeed; [FieldOffset(0x08)] public float downAccel; [FieldOffset(0x0C)] public float damperV; [FieldOffset(0x10)] public float damperH; [FieldOffset(0x14)] public float time; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSlowMove { [FieldOffset(0x00)] public float startSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float accel; [FieldOffset(0x0C)] public float brake; [FieldOffset(0x10)] public float damageSpeed; [FieldOffset(0x14)] public float damageBrake; [FieldOffset(0x18)] public float steeringSpeed; [FieldOffset(0x1C)] public float endSteeringSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSpin { [FieldOffset(0x00)] public float startSlopeAngle; [FieldOffset(0x04)] public float endSlopeAngle; [FieldOffset(0x08)] public float startSpeed; [FieldOffset(0x0C)] public float endSpeed; [FieldOffset(0x10)] public float stickAngle; [FieldOffset(0x14)] public float brake; [FieldOffset(0x18)] public float forceBrake; [FieldOffset(0x1C)] public float maxSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x88)] public struct PlayerParamWallMove { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float walkSpeed; [FieldOffset(0x08)] public float walkSpeedMax; [FieldOffset(0x0C)] public float runSpeed; [FieldOffset(0x10)] public float runSpeedMax; [FieldOffset(0x14)] public float walkSpeedOnMesh; [FieldOffset(0x18)] public float walkSpeedOnMeshMax; [FieldOffset(0x1C)] public float runSpeedOnMesh; [FieldOffset(0x20)] public float runSpeedOnMeshMax; [FieldOffset(0x24)] public float minAccessSpeed; [FieldOffset(0x28)] public float stickSpeed; [FieldOffset(0x2C)] public float gravity; [FieldOffset(0x30)] public float accel; [FieldOffset(0x34)] public float brake; [FieldOffset(0x38)] public float stopBrake; [FieldOffset(0x3C)] public float fallSpeed; [FieldOffset(0x40)] public float steeringSpeed1; [FieldOffset(0x44)] public float steeringSpeed2; [FieldOffset(0x48)] public float startSteeringSpeed; [FieldOffset(0x4C)] public float endSteeringSpeed; [FieldOffset(0x50)] public float startTime; [FieldOffset(0x54)] public float useEnergySpeedBase; [FieldOffset(0x58)] public float useEnergySpeedBaseOnMesh; [FieldOffset(0x5C)] public float useEnergySpeedVal; [FieldOffset(0x60)] public float useEnergySpeedValOnMesh; [FieldOffset(0x64)] public float useEnergyAngle; [FieldOffset(0x68)] public float useEnergyAngleOnMesh; [FieldOffset(0x6C)] public float brakeStartEnergy; [FieldOffset(0x70)] public float brakeStartEnergyOnMesh; [FieldOffset(0x74)] public float homingSearchDistanceNear; [FieldOffset(0x78)] public float homingSearchDistanceFar; [FieldOffset(0x7C)] public float wallBumpHeightUpper; [FieldOffset(0x80)] public float wallBumpHeightUnder; [FieldOffset(0x84)] public float recoveryCheckTime; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerParamWallJump { [FieldOffset(0x00)] public float gravitySize; [FieldOffset(0x04)] public float minTime; [FieldOffset(0x08)] public float maxTime; [FieldOffset(0x0C)] public float stopTime; [FieldOffset(0x10)] public float maxDownSpeed; [FieldOffset(0x14)] public float fallGroundDistance; [FieldOffset(0x18)] public float frontForce; [FieldOffset(0x1C)] public float upForce; [FieldOffset(0x20)] public float impulseTime; } [StructLayout(LayoutKind.Explicit, Size = 0x54)] public struct PlayerParamClimbing { [FieldOffset(0x00)] public float stepSpeedFront; [FieldOffset(0x04)] public float stepSpeedFrontDash; [FieldOffset(0x08)] public float stepSpeedSide; [FieldOffset(0x0C)] public float stepSpeedSideDash; [FieldOffset(0x10)] public float stepSpeedBack; [FieldOffset(0x14)] public float stepDashRate; [FieldOffset(0x18)] public float maxAnimSpeed; [FieldOffset(0x1C)] public float exhaustAngle; [FieldOffset(0x20)] public float exhaustAngleOnMesh; [FieldOffset(0x24)] public float exhaustBase; [FieldOffset(0x28)] public float exhaustBaseOnMesh; [FieldOffset(0x2C)] public float exhaustRate; [FieldOffset(0x30)] public float exhaustRateOnMesh; [FieldOffset(0x34)] public float useGrabGaugeSpeed; [FieldOffset(0x38)] public float useGrabGaugeSpeedOnMesh; [FieldOffset(0x3C)] public float useGrabGaugeTurbo; [FieldOffset(0x40)] public float useGrabGaugeTurboOnMesh; [FieldOffset(0x44)] public float homingSearchDistanceNear; [FieldOffset(0x48)] public float homingSearchDistanceFar; [FieldOffset(0x4C)] public float resetAngle; [FieldOffset(0x50)] public float recoveryCheckTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamSlideDown { [FieldOffset(0x00)] public float time; [FieldOffset(0x04)] public float speed; [FieldOffset(0x08)] public float speedOnMesh; [FieldOffset(0x0C)] public float accel; [FieldOffset(0x10)] public float brake; [FieldOffset(0x14)] public float brakeOnMesh; } [StructLayout(LayoutKind.Explicit, Size = 0x3C)] public struct PlayerParamBoost { [FieldOffset(0x00)] public float consumptionRate; [FieldOffset(0x04)] public float consumptionRateSS; [FieldOffset(0x08)] public float recoveryRate; [FieldOffset(0x0C)] public float recoveryRateSS; [FieldOffset(0x10)] public float reigniteRatio; [FieldOffset(0x14)] public float recoveryByRing; [FieldOffset(0x18)] public float recoveryByAttack; [FieldOffset(0x1C)] public unsafe fixed float blurPowers[3]; [FieldOffset(0x28)] public float blurEaseInTime; [FieldOffset(0x2C)] public float blurEaseOutTime; [FieldOffset(0x30)] public float endSpeed; [FieldOffset(0x34)] public float powerBoostCoolTime; [FieldOffset(0x38)] public float infinityBoostTime; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamAirBoost { [FieldOffset(0x00)] public float startHSpeed; [FieldOffset(0x04)] public float startHSpeedMax; [FieldOffset(0x08)] public float startVSpeed; [FieldOffset(0x0C)] public float minHSpeed; [FieldOffset(0x10)] public float minHSpeedMax; [FieldOffset(0x14)] public float brakeTime; [FieldOffset(0x18)] public float minKeepTime; [FieldOffset(0x1C)] public float maxKeepTime; [FieldOffset(0x20)] public float maxTime; [FieldOffset(0x24)] public float gravityRate; [FieldOffset(0x28)] public float steeringSpeed; [FieldOffset(0x2C)] public float additionalTransitTime; [FieldOffset(0x30)] public float supersonicTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAutorun { [FieldOffset(0x00)] public float initialSideSpeed; [FieldOffset(0x04)] public float acceleSideForce; [FieldOffset(0x08)] public float deceleSideForce; [FieldOffset(0x0C)] public float maxSideSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSideStep { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float brakeForce; [FieldOffset(0x08)] public float motionSpeedRatio; [FieldOffset(0x0C)] public float stepSpeed; [FieldOffset(0x10)] public float maxStepDistance; [FieldOffset(0x14)] public float minStepDistance; [FieldOffset(0x18)] public float maxStepSpeed; [FieldOffset(0x1C)] public float minStepSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSideStep2 { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float brakeForce; [FieldOffset(0x08)] public float motionSpeedRatio; [FieldOffset(0x0C)] public float stepSpeed; [FieldOffset(0x10)] public float maxStepDistance; [FieldOffset(0x14)] public float minStepDistance; [FieldOffset(0x18)] public float maxStepSpeed; [FieldOffset(0x1C)] public float minStepSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerParamQuickStep { [FieldOffset(0x00)] public float needSpeed; [FieldOffset(0x04)] public float acceleForce; [FieldOffset(0x08)] public float acceleSideForce; [FieldOffset(0x0C)] public float stepInitialSpeed; [FieldOffset(0x10)] public float avoidForce; [FieldOffset(0x14)] public float justBoostForce; [FieldOffset(0x18)] public float justBoostMax; [FieldOffset(0x1C)] public float justBoostTime; [FieldOffset(0x20)] public float justBoostBrake; } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct PlayerParamParry { [FieldOffset(0x00)] public float minRecieveTime; [FieldOffset(0x04)] public unsafe fixed float maxRecieveTimes[4]; [FieldOffset(0x14)] public unsafe fixed float justRecieveTimes[4]; [FieldOffset(0x24)] public float frozenTime; [FieldOffset(0x28)] public float justFrozenTime; [FieldOffset(0x2C)] public float justEffectEasein; [FieldOffset(0x30)] public float justEffectEaseout; [FieldOffset(0x34)] public float justEffectTime; [FieldOffset(0x38)] public float justEffectEasein2; [FieldOffset(0x3C)] public float justEffectEaseout2; [FieldOffset(0x40)] public float justEffectTime2; [FieldOffset(0x44)] public float justEffectEasein3; [FieldOffset(0x48)] public float justEffectEaseout3; [FieldOffset(0x4C)] public float justEffectTime3; [FieldOffset(0x50)] public UnmanagedString cameraName; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAvoidData { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float damper; [FieldOffset(0x08)] public float parryTime; [FieldOffset(0x0C)] public float invincibleTime; } [StructLayout(LayoutKind.Explicit, Size = 0x94)] public struct PlayerParamAvoid { [FieldOffset(0x00)] public float time; [FieldOffset(0x04)] public float fixedTime; [FieldOffset(0x08)] public float reentryInputPriorityTime; [FieldOffset(0x0C)] public float reentryTime; [FieldOffset(0x10)] public float frontAngle; [FieldOffset(0x14)] public float backAngle; [FieldOffset(0x18)] public float addFallSpeed; [FieldOffset(0x1C)] public unsafe fixed byte /* PlayerParamAvoidData[7] */ _data[112]; public unsafe PlayerParamAvoidData* data { get { fixed (byte* p_data = _data) return (PlayerParamAvoidData*)p_data; } } [FieldOffset(0x8C)] public float baseDistance; [FieldOffset(0x90)] public float limitAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x8F0)] public struct ModePackage { [FieldOffset(0x00)] public PlayerParamCommon common; [FieldOffset(0x30)] public PlayerParamSpeed speed; [FieldOffset(0x110)] public PlayerParamRotation rotation; [FieldOffset(0x13C)] public PlayerParamRunning running; [FieldOffset(0x170)] public PlayerParamBalance balance; [FieldOffset(0x190)] public PlayerParamBrake brake; [FieldOffset(0x1A8)] public PlayerParamTurn turn; [FieldOffset(0x1B8)] public PlayerParamJump jump; [FieldOffset(0x1D4)] public PlayerParamJumpSpeed jumpSpeed; [FieldOffset(0x204)] public PlayerParamDoubleJump doubleJump; [FieldOffset(0x210)] public PlayerParamFall fall; [FieldOffset(0x240)] public PlayerParamDamage damage; [FieldOffset(0x320)] public PlayerParamDead dead; [FieldOffset(0x32C)] public PlayerParamSliding sliding; [FieldOffset(0x36C)] public PlayerParamStomping stomping; [FieldOffset(0x38C)] public PlayerParamGrind grind; [FieldOffset(0x3A0)] public PlayerParamFallSlope fallSlope; [FieldOffset(0x3D8)] public PlayerParamFallFlip fallFlip; [FieldOffset(0x3E4)] public PlayerParamTumble tumble; [FieldOffset(0x44C)] public PlayerParamSpinAttack spinAttack; [FieldOffset(0x46C)] public PlayerParamHomingAttack homingAttack; [FieldOffset(0x51C)] public PlayerParamHitEnemy hitEnemy; [FieldOffset(0x52C)] public PlayerParamDiving diving; [FieldOffset(0x588)] public PlayerParamFan fan; [FieldOffset(0x5A0)] public PlayerParamBackflip backflip; [FieldOffset(0x5B8)] public PlayerParamSlowMove slowmove; [FieldOffset(0x5D8)] public PlayerParamSpin spin; [FieldOffset(0x5F8)] public PlayerParamWallMove wallmove; [FieldOffset(0x680)] public PlayerParamWallJump walljump; [FieldOffset(0x6A4)] public PlayerParamClimbing climbing; [FieldOffset(0x6F8)] public PlayerParamSlideDown slidedown; [FieldOffset(0x710)] public PlayerParamBoost boost; [FieldOffset(0x74C)] public PlayerParamAirBoost airboost; [FieldOffset(0x780)] public PlayerParamAutorun autorun; [FieldOffset(0x790)] public PlayerParamSideStep sidestep; [FieldOffset(0x7B0)] public PlayerParamSideStep2 sidestep2; [FieldOffset(0x7D0)] public PlayerParamQuickStep quickstep; [FieldOffset(0x7F8)] public PlayerParamParry parry; [FieldOffset(0x858)] public PlayerParamAvoid avoid; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct TailsParamFlyStart { [FieldOffset(0x00)] public float decY; [FieldOffset(0x04)] public float duration; [FieldOffset(0x08)] public float moveMaxSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct TailsParamFlyRise { [FieldOffset(0x00)] public float speedYStart; [FieldOffset(0x04)] public float speedYMax; [FieldOffset(0x08)] public float accY; [FieldOffset(0x0C)] public float height; [FieldOffset(0x10)] public int riseNum; [FieldOffset(0x14)] public unsafe fixed float heightRatio[4]; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct TailsParamFlyCruise { [FieldOffset(0x00)] public float decY; [FieldOffset(0x04)] public float duration; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct TailsParamFlyDescend { [FieldOffset(0x00)] public float speedYMax; [FieldOffset(0x04)] public float accY; [FieldOffset(0x08)] public float moveMaxSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct TailsParamFlyCamera { [FieldOffset(0x00)] public float azimuthSensitivity; [FieldOffset(0x04)] public float elevationOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x78)] public struct TailsParamFly { [FieldOffset(0x00)] public TailsParamFlyStart start; [FieldOffset(0x0C)] public TailsParamFlyRise rise; [FieldOffset(0x30)] public TailsParamFlyCruise cruise; [FieldOffset(0x38)] public TailsParamFlyDescend descend; [FieldOffset(0x44)] public float maxSpeed; [FieldOffset(0x48)] public float acc; [FieldOffset(0x4C)] public float dec; [FieldOffset(0x50)] public float maxSteerSpeed; [FieldOffset(0x54)] public float rollSpeed; [FieldOffset(0x58)] public float neutralRollSpeed; [FieldOffset(0x5C)] public float yawSpeed; [FieldOffset(0x60)] public float maxRollAngle; [FieldOffset(0x64)] public float height; [FieldOffset(0x68)] public float heightLimit; [FieldOffset(0x6C)] public TailsParamFlyCamera camera; [FieldOffset(0x74)] public float practiceTime; } [StructLayout(LayoutKind.Explicit, Size = 0x70)] public struct TailsParamSpannerShot { [FieldOffset(0x00)] public float archSpeed; [FieldOffset(0x04)] public float archHomingMinSpeed; [FieldOffset(0x08)] public float archHomingMaxSpeed; [FieldOffset(0x0C)] public float archHomingMinSpeedDistance; [FieldOffset(0x10)] public float archHomingMaxSpeedDistance; [FieldOffset(0x14)] public float archRange; [FieldOffset(0x18)] public float archHeight; [FieldOffset(0x1C)] public float archHomingMinHeight; [FieldOffset(0x20)] public float archHomingMaxHeight; [FieldOffset(0x24)] public float archHomingMinHeightDistance; [FieldOffset(0x28)] public float archHomingMaxHeightDistance; [FieldOffset(0x2C)] public float archModelScale; [FieldOffset(0x30)] public float archColliderRadius; [FieldOffset(0x34)] public float archSpinSpeed; [FieldOffset(0x38)] public float floatSpeed; [FieldOffset(0x3C)] public float floatSpeedMinHoming; [FieldOffset(0x40)] public float floatRange; [FieldOffset(0x44)] public float floatAirYOffset; [FieldOffset(0x48)] public float floatDuration; [FieldOffset(0x4C)] public float floatDamageInterval; [FieldOffset(0x50)] public float floatModelScale; [FieldOffset(0x54)] public float floatColliderRadius; [FieldOffset(0x58)] public float floatSpinSpeed; [FieldOffset(0x5C)] public float floatOrbitRadius; [FieldOffset(0x60)] public float floatOrbitSpeed; [FieldOffset(0x64)] public float floatOrbitSpinSpeed; [FieldOffset(0x68)] public float addMoveSpeedRatio; [FieldOffset(0x6C)] public float modelExtendDuration; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct TailsParamSpannerCombo { [FieldOffset(0x00)] public float initialTime; [FieldOffset(0x04)] public float continueTime; [FieldOffset(0x08)] public float fallSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x7C)] public struct TailsParamSpanner { [FieldOffset(0x00)] public TailsParamSpannerShot shot; [FieldOffset(0x70)] public TailsParamSpannerCombo combo; } [StructLayout(LayoutKind.Explicit, Size = 0x38)] public struct TailsParamCyBlasterShot { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float range; [FieldOffset(0x08)] public float colliderRadius; [FieldOffset(0x0C)] public float colliderHeight; [FieldOffset(0x10)] public float splineHeight; [FieldOffset(0x14)] public float lifetime; [FieldOffset(0x18)] public float readyDuration; [FieldOffset(0x1C)] public float readyRotateSpeed; [FieldOffset(0x20)] public float readyFallSpeed; [FieldOffset(0x24)] public float addMoveSpeedRatio; [FieldOffset(0x28)] public bool explodeOnMoveFinish; [FieldOffset(0x2C)] public float cyLineRadius; [FieldOffset(0x30)] public float cyLineRotateCycleTime; [FieldOffset(0x34)] public float cyLineLifeTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct TailsParamCyBlasterLiftRun { [FieldOffset(0x00)] public float initial; [FieldOffset(0x04)] public float min; [FieldOffset(0x08)] public float max; [FieldOffset(0x0C)] public float minTurn; [FieldOffset(0x10)] public float acceleForce; [FieldOffset(0x14)] public float rotateForce; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct TailsParamCyBlasterLiftAir { [FieldOffset(0x00)] public float jumpForce; [FieldOffset(0x04)] public float gravitySize; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct TailsParamCyBlasterLift { [FieldOffset(0x00)] public TailsParamCyBlasterLiftRun run; [FieldOffset(0x18)] public TailsParamCyBlasterLiftAir air; [FieldOffset(0x20)] public float liftUpTime; [FieldOffset(0x30)] public Vector3 liftOffset; } [StructLayout(LayoutKind.Explicit, Size = 0xF0)] public struct TailsParamCyBlaster { [FieldOffset(0x00)] public TailsParamCyBlasterShot shot; [FieldOffset(0x40)] public TailsParamCyBlasterLift lift; [FieldOffset(0x80)] public CyloopDropItemParameter dropItem; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct TailsParamStomping { [FieldOffset(0x00)] public float landAttackScale; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct TailsParamCycloneBoostCamera { [FieldOffset(0x00)] public float azimuthSensitivity; [FieldOffset(0x04)] public float elevationOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct TailsParamCycloneBoost { [FieldOffset(0x00)] public float startHSpeed; [FieldOffset(0x04)] public float yawSpeedMax; [FieldOffset(0x08)] public float yawAcc; [FieldOffset(0x0C)] public float neutralYawDec; [FieldOffset(0x10)] public float attackScale; [FieldOffset(0x14)] public TailsParamCycloneBoostCamera camera; [FieldOffset(0x1C)] public float practiceTime; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct TailsParamAirBoostCycloneCamera { [FieldOffset(0x00)] public float azimuthSensitivity; [FieldOffset(0x04)] public float elevationOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct TailsParamAirBoostCycloneTakeOff { [FieldOffset(0x00)] public float vSpeedStart; [FieldOffset(0x04)] public float heightMin; } [StructLayout(LayoutKind.Explicit, Size = 0x48)] public struct TailsParamAirBoostCyclone { [FieldOffset(0x00)] public float startHSpeed; [FieldOffset(0x04)] public float vSpeedMax; [FieldOffset(0x08)] public float vSpeedAcc; [FieldOffset(0x0C)] public float vSpeedDec; [FieldOffset(0x10)] public float heightMax; [FieldOffset(0x14)] public float yawSpeedMax; [FieldOffset(0x18)] public float rollSpeed; [FieldOffset(0x1C)] public float neutralRollSpeed; [FieldOffset(0x20)] public float maxRollAngle; [FieldOffset(0x24)] public float maxPitchAngle; [FieldOffset(0x28)] public float maxPitchVSpeed; [FieldOffset(0x2C)] public float barrelRollDuration; [FieldOffset(0x30)] public float additionalTransitTime; [FieldOffset(0x34)] public float attackScale; [FieldOffset(0x38)] public TailsParamAirBoostCycloneCamera camera; [FieldOffset(0x40)] public TailsParamAirBoostCycloneTakeOff takeOff; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct TailsParamStepCyclone { [FieldOffset(0x00)] public float stepSpeed; [FieldOffset(0x04)] public float stepDistance; [FieldOffset(0x08)] public float barrelRollDuration; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamSpinBoostSpeed { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public PlayerParamSpeedAcceleData accele; [FieldOffset(0x1C)] public PlayerParamSpeedAcceleData decele; [FieldOffset(0x30)] public float baseRotateForce; [FieldOffset(0x34)] public float minTurnSpeed; [FieldOffset(0x38)] public float turnDeceleAngleMin; [FieldOffset(0x3C)] public float turnDeceleAngleMax; } public enum AirAccelMode : sbyte { Alawys = 0, AirAccelMode_None = 1, Speed = 2 } [StructLayout(LayoutKind.Explicit, Size = 0xF8)] public struct PlayerParamSpinBoost { [FieldOffset(0x00)] public float forceRunTime; [FieldOffset(0x04)] public float initialRunTime; [FieldOffset(0x08)] public PlayerParamSpinBoostSpeed speedBall; [FieldOffset(0x48)] public PlayerParamSpinBoostSpeed speedBoost; [FieldOffset(0x88)] public PlayerParamSpeedAcceleData2 deceleNeutralMin; [FieldOffset(0x98)] public PlayerParamSpeedAcceleData2 deceleNeutralMax; [FieldOffset(0xA8)] public float gravitySize; [FieldOffset(0xAC)] public float gravityBeginTime; [FieldOffset(0xB0)] public float gravityMaxTime; [FieldOffset(0xB4)] public float gravitySizeMinInAir; [FieldOffset(0xB8)] public float gravitySizeMaxInAir; [FieldOffset(0xBC)] public float maxGravityAccele; [FieldOffset(0xC0)] public float maxGravityDecele; [FieldOffset(0xC4)] public float inAirTime; [FieldOffset(0xC8)] public float spinBoostEndSpeed; [FieldOffset(0xCC)] public float jumpOutAngle; [FieldOffset(0xD0)] public float jumpOutSpeed; [FieldOffset(0xD4)] public bool humpJumpOut; [FieldOffset(0xD5)] public AirAccelMode airAccelMode; [FieldOffset(0xD8)] public float airAccelVertSpeedThreshold; [FieldOffset(0xDC)] public float chargeRotateForce; [FieldOffset(0xE0)] public float chargeRotateForceMinAngle; [FieldOffset(0xE4)] public float chargeRotateForceMaxAngle; [FieldOffset(0xE8)] public UnmanagedString cameraShakeName; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct TailsParamWaveCannonCamera { [FieldOffset(0x00)] public Vector3 frameOffset; [FieldOffset(0x10)] public float elevation; [FieldOffset(0x14)] public float distance; [FieldOffset(0x18)] public float fovy; [FieldOffset(0x1C)] public float interpolateBegin; [FieldOffset(0x20)] public float interpolateEnd; } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct TailsParamWaveCannon { [FieldOffset(0x00)] public float chargeDuration; [FieldOffset(0x04)] public float chargeTurnSpeed; [FieldOffset(0x08)] public float shotDuration; [FieldOffset(0x0C)] public float shotTurnSpeed; [FieldOffset(0x10)] public float turnLimit; [FieldOffset(0x14)] public float colliderLengthMax; [FieldOffset(0x18)] public float colliderRadius; [FieldOffset(0x1C)] public float colliderExtendSpeed; [FieldOffset(0x20)] public float damageInterval; [FieldOffset(0x24)] public float hitEffectInterval; [FieldOffset(0x30)] public TailsParamWaveCannonCamera camera; } [StructLayout(LayoutKind.Explicit, Size = 0xCB0)] public struct ModePackageTails { [FieldOffset(0)] public ModePackage modePackage; [FieldOffset(0x8F0)] public TailsParamFly tailsFly; [FieldOffset(0x968)] public TailsParamSpanner spanner; [FieldOffset(0x9F0)] public TailsParamCyBlaster cyBlaster; [FieldOffset(0xAE0)] public TailsParamStomping stomping; [FieldOffset(0xAE4)] public TailsParamCycloneBoost cycloneBoost; [FieldOffset(0xB04)] public TailsParamAirBoostCyclone airBoostCyclone; [FieldOffset(0xB4C)] public TailsParamStepCyclone stepCyclone; [FieldOffset(0xB58)] public PlayerParamSpinBoost spinBoost; [FieldOffset(0xC50)] public TailsParamWaveCannon waveCannon; } [StructLayout(LayoutKind.Explicit, Size = 0x1A8)] public struct WaterModePackage { [FieldOffset(0x00)] public PlayerParamSpeed speed; [FieldOffset(0xE0)] public PlayerParamJump jump; [FieldOffset(0xFC)] public PlayerParamJumpSpeed jumpSpeed; [FieldOffset(0x12C)] public PlayerParamDoubleJump doubleJump; [FieldOffset(0x138)] public PlayerParamBoost boost; [FieldOffset(0x174)] public PlayerParamAirBoost airboost; } [StructLayout(LayoutKind.Explicit, Size = 0x7DD0)] public struct Root { [FieldOffset(0x00)] public CommonPackageTails common; [FieldOffset(0x62C0)] public ModePackageTails forwardView; [FieldOffset(0x6F70)] public WaterModePackage water; [FieldOffset(0x7120)] public ModePackageTails cyberspaceSV; } } Library "AmyParameters" { #load "System.Numerics.dll" using System.Numerics; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamOffensive { [FieldOffset(0x00)] public ushort pointMin; [FieldOffset(0x02)] public ushort pointMax; [FieldOffset(0x04)] public float damageRandomRate; [FieldOffset(0x08)] public float damageRandomRateSS; [FieldOffset(0x0C)] public float shapeDamageRate; [FieldOffset(0x10)] public float shapeStunRate; [FieldOffset(0x14)] public float shapeStaggerRate; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDefensive { [FieldOffset(0x00)] public byte rateMin; [FieldOffset(0x01)] public byte rateMax; [FieldOffset(0x02)] public ushort infimumDropRings; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamAttackCommon { [FieldOffset(0x00)] public PlayerParamOffensive offensive; [FieldOffset(0x18)] public PlayerParamDefensive defensive; [FieldOffset(0x1C)] public float criticalDamageRate; [FieldOffset(0x20)] public float criticalRate; [FieldOffset(0x24)] public float criticalRateSS; [FieldOffset(0x28)] public float downedDamageRate; } public enum HitSE : sbyte { SE_None = -1, Weak = 0, Strong = 1, VeryStrong = 2 } [StructLayout(LayoutKind.Explicit, Size = 8)] public struct UnmanagedString { [FieldOffset(0)] public long pValue; public string Value { get { if (pValue == 0) return string.Empty; return Marshal.PtrToStringAnsi((nint)pValue); } set => pValue = (long)Marshal.StringToHGlobalAnsi(value); } public UnmanagedString(string in_value) { Value = in_value; } public static implicit operator UnmanagedString(string in_value) { return new UnmanagedString(in_value); } public static bool operator ==(UnmanagedString in_left, string in_right) { return in_left.Value == in_right; } public static bool operator !=(UnmanagedString in_left, string in_right) { return !(in_left == in_right); } public override bool Equals(object in_obj) { if (in_obj is string str) return Value == str; return base.Equals(in_obj); } public override int GetHashCode() { return Value.GetHashCode(); } public override string ToString() { return Value; } } [StructLayout(LayoutKind.Explicit, Size = 0x160)] public struct PlayerParamAttackData { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float damageRateSS; [FieldOffset(0x08)] public ushort pointMin; [FieldOffset(0x0A)] public ushort pointMax; [FieldOffset(0x0C)] public float damageRateAcceleMode; [FieldOffset(0x10)] public float damageRateManual; [FieldOffset(0x14)] public float stunPoint; [FieldOffset(0x18)] public float staggerPoint; [FieldOffset(0x20)] public Vector3 velocity; [FieldOffset(0x30)] public float velocityKeepTime; [FieldOffset(0x34)] public float addComboValue; [FieldOffset(0x38)] public float addComboValueAccele; [FieldOffset(0x3C)] public float addComboValueSS; [FieldOffset(0x40)] public float addComboValueAcceleSS; [FieldOffset(0x44)] public float addQuickCyloopEnergy; [FieldOffset(0x48)] public float addQuickCyloopEnergyAccele; [FieldOffset(0x4C)] public float addQuickCyloopEnergySS; [FieldOffset(0x50)] public float addQuickCyloopEnergyAcceleSS; [FieldOffset(0x54)] public float addQuickCyloopEnergyGuard; [FieldOffset(0x58)] public float addQuickCyloopEnergyAcceleGuard; [FieldOffset(0x60)] public Vector3 gimmickVelocity; [FieldOffset(0x70)] public float ignoreTime; [FieldOffset(0x74)] public uint attributes; [FieldOffset(0x78)] public HitSE se; [FieldOffset(0x80)] public UnmanagedString hitEffectName; [FieldOffset(0x90)] public UnmanagedString hitEffectNameSS; [FieldOffset(0xA0)] public UnmanagedString hitStopName; [FieldOffset(0xB0)] public UnmanagedString hitStopNameDead; [FieldOffset(0xC0)] public UnmanagedString hitStopNameDeadBoss; [FieldOffset(0xD0)] public UnmanagedString hitStopNameSS; [FieldOffset(0xE0)] public UnmanagedString hitStopNameDeadSS; [FieldOffset(0xF0)] public UnmanagedString hitCameraShakeName; [FieldOffset(0x100)] public UnmanagedString hitCameraShakeNameDead; [FieldOffset(0x110)] public UnmanagedString hitCameraShakeNameDeadBoss; [FieldOffset(0x120)] public UnmanagedString hitCameraShakeNameSS; [FieldOffset(0x130)] public UnmanagedString hitCameraShakeNameDeadSS; [FieldOffset(0x140)] public UnmanagedString hitVibrationName; [FieldOffset(0x150)] public UnmanagedString hitVibrationNameSS; } [StructLayout(LayoutKind.Explicit, Size = 0x4A70)] public struct PlayerParamAttack { [FieldOffset(0x00)] public PlayerParamAttackCommon common; [FieldOffset(0x30)] public PlayerParamAttackData spinAttack; [FieldOffset(0x190)] public PlayerParamAttackData spinDash; [FieldOffset(0x2F0)] public PlayerParamAttackData homingAttack; [FieldOffset(0x450)] public PlayerParamAttackData homingAttackAir; [FieldOffset(0x5B0)] public PlayerParamAttackData pursuitKick; [FieldOffset(0x710)] public PlayerParamAttackData stomping; [FieldOffset(0x870)] public PlayerParamAttackData stompingAttack; [FieldOffset(0x9D0)] public PlayerParamAttackData boundStompingLast; [FieldOffset(0xB30)] public PlayerParamAttackData sliding; [FieldOffset(0xC90)] public PlayerParamAttackData loopKick; [FieldOffset(0xDF0)] public PlayerParamAttackData crasher; [FieldOffset(0xF50)] public PlayerParamAttackData spinSlashHoming; [FieldOffset(0x10B0)] public PlayerParamAttackData spinSlash; [FieldOffset(0x1210)] public PlayerParamAttackData spinSlashLast; [FieldOffset(0x1370)] public PlayerParamAttackData sonicBoom; [FieldOffset(0x14D0)] public PlayerParamAttackData crossSlash; [FieldOffset(0x1630)] public PlayerParamAttackData homingShot; [FieldOffset(0x1790)] public PlayerParamAttackData chargeAttack; [FieldOffset(0x18F0)] public PlayerParamAttackData chargeAttackLast; [FieldOffset(0x1A50)] public PlayerParamAttackData cyloop; [FieldOffset(0x1BB0)] public PlayerParamAttackData cyloopQuick; [FieldOffset(0x1D10)] public PlayerParamAttackData cyloopAerial; [FieldOffset(0x1E70)] public PlayerParamAttackData accele1; [FieldOffset(0x1FD0)] public PlayerParamAttackData accele2; [FieldOffset(0x2130)] public PlayerParamAttackData aerialAccele1; [FieldOffset(0x2290)] public PlayerParamAttackData aerialAccele2; [FieldOffset(0x23F0)] public PlayerParamAttackData comboFinish; [FieldOffset(0x2550)] public PlayerParamAttackData comboFinishF; [FieldOffset(0x26B0)] public PlayerParamAttackData comboFinishB; [FieldOffset(0x2810)] public PlayerParamAttackData comboFinishL; [FieldOffset(0x2970)] public PlayerParamAttackData comboFinishR; [FieldOffset(0x2AD0)] public PlayerParamAttackData acceleComboFinish; [FieldOffset(0x2C30)] public PlayerParamAttackData acceleComboFinishF; [FieldOffset(0x2D90)] public PlayerParamAttackData acceleComboFinishB; [FieldOffset(0x2EF0)] public PlayerParamAttackData acceleComboFinishL; [FieldOffset(0x3050)] public PlayerParamAttackData acceleComboFinishR; [FieldOffset(0x31B0)] public PlayerParamAttackData smash; [FieldOffset(0x3310)] public PlayerParamAttackData smashLast; [FieldOffset(0x3470)] public PlayerParamAttackData slingShot; [FieldOffset(0x35D0)] public PlayerParamAttackData knucklesPunch1; [FieldOffset(0x3730)] public PlayerParamAttackData knucklesPunch2; [FieldOffset(0x3890)] public PlayerParamAttackData knucklesUppercut; [FieldOffset(0x39F0)] public PlayerParamAttackData knucklesHeatKnuckle; [FieldOffset(0x3B50)] public PlayerParamAttackData knucklesHeatKnuckleLast; [FieldOffset(0x3CB0)] public PlayerParamAttackData amyTarotAttack; [FieldOffset(0x3E10)] public PlayerParamAttackData amyTarotAttack2; [FieldOffset(0x3F70)] public PlayerParamAttackData amyTarotRolling; [FieldOffset(0x40D0)] public PlayerParamAttackData amyCharmAttack; [FieldOffset(0x4230)] public PlayerParamAttackData amyTarotBoost; [FieldOffset(0x4390)] public PlayerParamAttackData tailsSpanner; [FieldOffset(0x44F0)] public PlayerParamAttackData tailsSpannerFloat; [FieldOffset(0x4650)] public PlayerParamAttackData tailsPowerBoost; [FieldOffset(0x47B0)] public PlayerParamAttackData tailsWaveCannon; [FieldOffset(0x4910)] public PlayerParamAttackData tailsWaveCannonFinish; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamWaterAct { [FieldOffset(0x00)] public float resistRate; [FieldOffset(0x04)] public float breatheBrake; [FieldOffset(0x08)] public float breatheTime; [FieldOffset(0x0C)] public float breatheGravity; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBaseJump { [FieldOffset(0x00)] public float baseSpeed; [FieldOffset(0x04)] public float upSpeed; [FieldOffset(0x08)] public float upSpeedAir; [FieldOffset(0x0C)] public float edgeSpeed; [FieldOffset(0x10)] public float airActionTime; [FieldOffset(0x14)] public float wallMoveTime; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamBallMove { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float slidePower; [FieldOffset(0x08)] public float brakeForce; [FieldOffset(0x0C)] public float slidePowerSlalom; [FieldOffset(0x10)] public float brakeForceSlalom; [FieldOffset(0x14)] public float releaseSpeed; [FieldOffset(0x18)] public bool useInput; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamLocusData { [FieldOffset(0x00)] public float width; [FieldOffset(0x04)] public float distance; [FieldOffset(0x08)] public float u0; [FieldOffset(0x0C)] public float u1; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamLocus { [FieldOffset(0x00)] public unsafe fixed byte /* PlayerParamLocusData[4] */ _data[64]; public unsafe PlayerParamLocusData* data { get { fixed (byte* p_data = _data) return (PlayerParamLocusData*)p_data; } } } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAuraTrain { [FieldOffset(0x00)] public float effectSpanTime; [FieldOffset(0x04)] public float effectLifeTime; [FieldOffset(0x08)] public float effectOffsetDistance; [FieldOffset(0x0C)] public float effectOverlapDistance; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamLevel { [FieldOffset(0x00)] public byte ringsLevel; [FieldOffset(0x01)] public byte speedLevel; [FieldOffset(0x02)] public byte offensiveLevel; [FieldOffset(0x03)] public byte defensiveLevel; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamBarrierWall { [FieldOffset(0x00)] public float coolTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamDamageRateLevel { [FieldOffset(0x00)] public unsafe fixed float rates[5]; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerParamDamageRate { [FieldOffset(0x00)] public unsafe fixed byte /* PlayerParamDamageRateLevel[4] */ _diffculties[80]; public unsafe PlayerParamDamageRateLevel* diffculties { get { fixed (byte* p_diffculties = _diffculties) return (PlayerParamDamageRateLevel*)p_diffculties; } } } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamAcceleMode { [FieldOffset(0x00)] public float declineSpeed; [FieldOffset(0x04)] public float declineSpeedAccele; [FieldOffset(0x08)] public float lossDamaged; [FieldOffset(0x0C)] public float lossDamagedAccele; [FieldOffset(0x10)] public uint comboRateAccele; } [StructLayout(LayoutKind.Explicit, Size = 0x4B70)] public struct CommonPackage { [FieldOffset(0x00)] public PlayerParamAttack attack; [FieldOffset(0x4A70)] public PlayerParamWaterAct wateract; [FieldOffset(0x4A80)] public PlayerParamBaseJump basejump; [FieldOffset(0x4A98)] public PlayerParamBallMove ballmove; [FieldOffset(0x4AB4)] public PlayerParamLocus locus; [FieldOffset(0x4AF4)] public PlayerParamAuraTrain auratrain; [FieldOffset(0x4B04)] public PlayerParamLevel level; [FieldOffset(0x4B08)] public PlayerParamBarrierWall barrierWall; [FieldOffset(0x4B0C)] public PlayerParamDamageRate damageRate; [FieldOffset(0x4B5C)] public PlayerParamAcceleMode acceleMode; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamComboCommon { [FieldOffset(0x00)] public float longPressTime; } public enum ComboMoveType : byte { Homing = 0, Step = 1, None = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamComboMove { [FieldOffset(0x00)] public ComboMoveType moveType; [FieldOffset(0x04)] public float moveInitialSpeed; [FieldOffset(0x08)] public float moveMaxSpeed; [FieldOffset(0x0C)] public float moveAccele; [FieldOffset(0x10)] public float timeout; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct PlayerParamComboMoveCorrection { [FieldOffset(0x00)] public float moveSpeed; [FieldOffset(0x04)] public float rotateSpeed; } public enum Action : sbyte { Root = 0, HomingAttack = 1, AerialHomingAttack = 2, Pursuit = 3, Stomping = 4, LoopKick = 5, Crasher = 6, SpinSlash = 7, SonicBoom = 8, CrossSlash = 9, HomingShot = 10, ChargeAttack = 11, QuickCyloop = 12, AerialQuickCyloop = 13, AcceleCombo1 = 14, AcceleCombo2 = 15, AcceleCombo3 = 16, AcceleCombo4 = 17, AerialAcceleCombo1 = 18, AerialAcceleCombo2 = 19, AerialAcceleCombo3 = 20, AerialAcceleCombo4 = 21, ComboFinish = 22, SpinJump = 23, Smash = 24, Behind = 25, Guarded = 26, Avoid = 27, AirBoost = 28, AfterAirBoost = 29, KnucklesPunch1 = 30, KnucklesPunch2 = 31, KnucklesUppercut = 32, KnucklesCyKnuckle = 33, KnucklesHeatKnuckle = 34, AmyTarotAttack = 35, AmyTarotAttack2 = 36, AmyTarotRolling = 37, AmyCyHammer = 38, AmyCharmAttack = 39, TailsSpanner = 40, ActionNum = 41 } [StructLayout(LayoutKind.Explicit, Size = 0x12)] public struct PlayerParamComboTransit { [FieldOffset(0x00)] public unsafe fixed byte /* Action[6] */ _transitExistTarget[6]; public unsafe Action* transitExistTarget { get { fixed (byte* p_transitExistTarget = _transitExistTarget) return (Action*)p_transitExistTarget; } } [FieldOffset(0x06)] public unsafe fixed byte /* Action[6] */ _transitInAir[6]; public unsafe Action* transitInAir { get { fixed (byte* p_transitInAir = _transitInAir) return (Action*)p_transitInAir; } } [FieldOffset(0x0C)] public unsafe fixed byte /* Action[6] */ _transitNotExistTarget[6]; public unsafe Action* transitNotExistTarget { get { fixed (byte* p_transitNotExistTarget = _transitNotExistTarget) return (Action*)p_transitNotExistTarget; } } } [StructLayout(LayoutKind.Explicit, Size = 0x2AC)] public struct PlayerParamComboTransitTable { [FieldOffset(0x00)] public PlayerParamComboTransit root; [FieldOffset(0x12)] public PlayerParamComboTransit homingAttack; [FieldOffset(0x24)] public PlayerParamComboTransit aerialHoming; [FieldOffset(0x36)] public PlayerParamComboTransit pursuit; [FieldOffset(0x48)] public PlayerParamComboTransit stomping; [FieldOffset(0x5A)] public PlayerParamComboTransit loopKick; [FieldOffset(0x6C)] public PlayerParamComboTransit crasher; [FieldOffset(0x7E)] public PlayerParamComboTransit spinSlash; [FieldOffset(0x90)] public PlayerParamComboTransit sonicBoom; [FieldOffset(0xA2)] public PlayerParamComboTransit crossSlash; [FieldOffset(0xB4)] public PlayerParamComboTransit homingShot; [FieldOffset(0xC6)] public PlayerParamComboTransit chargeAttack; [FieldOffset(0xD8)] public PlayerParamComboTransit quickCyloop; [FieldOffset(0xEA)] public PlayerParamComboTransit aerialQuickCyloop; [FieldOffset(0xFC)] public PlayerParamComboTransit acceleCombo1; [FieldOffset(0x10E)] public PlayerParamComboTransit acceleCombo2; [FieldOffset(0x120)] public PlayerParamComboTransit acceleCombo3; [FieldOffset(0x132)] public PlayerParamComboTransit acceleCombo4; [FieldOffset(0x144)] public PlayerParamComboTransit aerialAcceleCombo1; [FieldOffset(0x156)] public PlayerParamComboTransit aerialAcceleCombo2; [FieldOffset(0x168)] public PlayerParamComboTransit aerialAcceleCombo3; [FieldOffset(0x17A)] public PlayerParamComboTransit aerialAcceleCombo4; [FieldOffset(0x18C)] public PlayerParamComboTransit behind; [FieldOffset(0x19E)] public PlayerParamComboTransit guarded; [FieldOffset(0x1B0)] public PlayerParamComboTransit avoid; [FieldOffset(0x1C2)] public PlayerParamComboTransit airBoost; [FieldOffset(0x1D4)] public PlayerParamComboTransit afterAirBoost; [FieldOffset(0x1E6)] public PlayerParamComboTransit knucklesPunch1; [FieldOffset(0x1F8)] public PlayerParamComboTransit knucklesPunch2; [FieldOffset(0x20A)] public PlayerParamComboTransit knucklesUppercut; [FieldOffset(0x21C)] public PlayerParamComboTransit knucklesCyKnuckle; [FieldOffset(0x22E)] public PlayerParamComboTransit knucklesHeatKnuckle; [FieldOffset(0x240)] public PlayerParamComboTransit amyTarotAttack; [FieldOffset(0x252)] public PlayerParamComboTransit amyTarotAttack2; [FieldOffset(0x264)] public PlayerParamComboTransit amyTarotRolling; [FieldOffset(0x276)] public PlayerParamComboTransit amyCyHammer; [FieldOffset(0x288)] public PlayerParamComboTransit amyCharmAttack; [FieldOffset(0x29A)] public PlayerParamComboTransit tailsSpanner; } [StructLayout(LayoutKind.Explicit, Size = 0x2E0)] public struct PlayerParamCombo { [FieldOffset(0x00)] public PlayerParamComboCommon common; [FieldOffset(0x04)] public PlayerParamComboMove comboMoveSonic; [FieldOffset(0x18)] public PlayerParamComboMove comboMoveSupersonic; [FieldOffset(0x2C)] public PlayerParamComboMoveCorrection comboMoveCorrection; [FieldOffset(0x34)] public PlayerParamComboTransitTable comboTable; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct AmyParamParryDebuff { [FieldOffset(0x00)] public uint damagePoint; [FieldOffset(0x04)] public float effectTime; [FieldOffset(0x08)] public float initTime; [FieldOffset(0x0C)] public float spanTime; } [StructLayout(LayoutKind.Explicit, Size = 0x58)] public struct CyloopSlashEffectBaseParameter { [FieldOffset(0x00)] public int m_divideCircle; [FieldOffset(0x04)] public float m_circleRadius; [FieldOffset(0x08)] public float m_circleWaveCycle; [FieldOffset(0x0C)] public float m_circleWaveWidth; [FieldOffset(0x10)] public float m_circleWaveSpeed; [FieldOffset(0x14)] public Vector2 m_scale; [FieldOffset(0x20)] public UnmanagedString m_textureName; [FieldOffset(0x30)] public float m_flowSpeed; [FieldOffset(0x34)] public float m_twistCycle; [FieldOffset(0x38)] public float m_rollCycle; [FieldOffset(0x3C)] public float m_rollPhase; [FieldOffset(0x40)] public float m_alphaHeadDistance; [FieldOffset(0x44)] public float m_alphaTailDistance; [FieldOffset(0x48)] public float m_offsetCycle; [FieldOffset(0x4C)] public float m_offsetPhase; [FieldOffset(0x50)] public float m_offsetRadius; } public struct ColorF { public float A; public float R; public float G; public float B; } [StructLayout(LayoutKind.Explicit, Size = 0xA8)] public struct CyloopTransparentLocusParameter { [FieldOffset(0)] public CyloopSlashEffectBaseParameter cyloopSlashEffectBaseParameter; [FieldOffset(0x58)] public ColorF m_color0; [FieldOffset(0x68)] public ColorF m_color1; [FieldOffset(0x78)] public float m_luminance; [FieldOffset(0x7C)] public ColorF m_flashColor0; [FieldOffset(0x8C)] public ColorF m_flashColor1; [FieldOffset(0x9C)] public float m_flashLuminance; [FieldOffset(0xA0)] public float m_flashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct OpaqueLineUvCell { [FieldOffset(0x00)] public float scale; [FieldOffset(0x04)] public float speedX; [FieldOffset(0x08)] public float speedY; } [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct CyloopOpaqueLocusParameter { [FieldOffset(0)] public CyloopSlashEffectBaseParameter cyloopSlashEffectBaseParameter; [FieldOffset(0x58)] public ColorF m_color; [FieldOffset(0x68)] public float m_alphaThreshold; [FieldOffset(0x6C)] public unsafe fixed byte /* OpaqueLineUvCell[2] */ _m_uvCells[24]; public unsafe OpaqueLineUvCell* m_uvCells { get { fixed (byte* p_m_uvCells = _m_uvCells) return (OpaqueLineUvCell*)p_m_uvCells; } } [FieldOffset(0x84)] public float m_uvLineScaleX; [FieldOffset(0x88)] public float m_uvLineScaleY; [FieldOffset(0x8C)] public ColorF m_flashColor; [FieldOffset(0x9C)] public float m_flashTime; } [StructLayout(LayoutKind.Explicit, Size = 0xF0)] public struct CyloopCrossLineParameter { [FieldOffset(0x00)] public UnmanagedString m_textureNamePattern; [FieldOffset(0x10)] public UnmanagedString m_textureNameDist; [FieldOffset(0x20)] public ColorF startColor; [FieldOffset(0x30)] public ColorF endColor; [FieldOffset(0x40)] public float startColorLuminance; [FieldOffset(0x44)] public float endColorLuminance; [FieldOffset(0x48)] public ColorF startColorFlash; [FieldOffset(0x58)] public ColorF endColorFlash; [FieldOffset(0x68)] public float startColorLuminanceFlash; [FieldOffset(0x6C)] public float endColorLuminanceFlash; [FieldOffset(0x70)] public float flashTime; [FieldOffset(0x74)] public float patternDepth; [FieldOffset(0x78)] public float patternScrollSpeed; [FieldOffset(0x7C)] public float patternDarkness; [FieldOffset(0x80)] public float patternScale; [FieldOffset(0x84)] public float glitchResX; [FieldOffset(0x88)] public float glitchResY; [FieldOffset(0x8C)] public float glitchOffset; [FieldOffset(0x90)] public float glitchMaxLength; [FieldOffset(0x94)] public float startGlitchScrollSpeed; [FieldOffset(0x98)] public float startGlitchChangeSpeed; [FieldOffset(0x9C)] public float startGlitchShift; [FieldOffset(0xA0)] public float startGlitchContrust; [FieldOffset(0xA4)] public float endGlitchScrollSpeed; [FieldOffset(0xA8)] public float endGlitchChangeSpeed; [FieldOffset(0xAC)] public float endGlitchShift; [FieldOffset(0xB0)] public float endGlitchContrust; [FieldOffset(0xB4)] public float lineWidth; [FieldOffset(0xB8)] public float lineDisplayWidth; [FieldOffset(0xBC)] public float lineBlackEdgeWidth; [FieldOffset(0xC0)] public float lineBlackEdgeIntensity; [FieldOffset(0xC4)] public float lineBlackEdgeNormalFade; [FieldOffset(0xC8)] public float distNoiseScale; [FieldOffset(0xCC)] public float distLowNoiseScale; [FieldOffset(0xD0)] public float distHighNoiseScale; [FieldOffset(0xD4)] public float distNoiseRate; [FieldOffset(0xD8)] public float distScrollSpeed; [FieldOffset(0xDC)] public float distIntensity; [FieldOffset(0xE0)] public float dissolve; [FieldOffset(0xE4)] public float dissolveRate; [FieldOffset(0xE8)] public float heightOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x4E0)] public struct CyloopLocusParameter { [FieldOffset(0x00)] public int m_numTransparentLines; [FieldOffset(0x08)] public unsafe fixed byte /* CyloopTransparentLocusParameter[3] */ _m_transparentLines[504]; public unsafe CyloopTransparentLocusParameter* m_transparentLines { get { fixed (byte* p_m_transparentLines = _m_transparentLines) return (CyloopTransparentLocusParameter*)p_m_transparentLines; } } [FieldOffset(0x200)] public int m_numOpaqueLines; [FieldOffset(0x208)] public unsafe fixed byte /* CyloopOpaqueLocusParameter[3] */ _m_opaqueLines[480]; public unsafe CyloopOpaqueLocusParameter* m_opaqueLines { get { fixed (byte* p_m_opaqueLines = _m_opaqueLines) return (CyloopOpaqueLocusParameter*)p_m_opaqueLines; } } [FieldOffset(0x3E8)] public int m_numCrossLines; [FieldOffset(0x3F0)] public CyloopCrossLineParameter m_crossline; } [StructLayout(LayoutKind.Explicit, Size = 0x28)] public struct CyloopDropItemWeightParameter { [FieldOffset(0x00)] public uint noneWeight; [FieldOffset(0x04)] public uint ring10Weight; [FieldOffset(0x08)] public uint powerSeedWeight; [FieldOffset(0x0C)] public uint guardSeedWeight; [FieldOffset(0x10)] public uint sequenceItemWeight; [FieldOffset(0x14)] public uint portalBitWeight; [FieldOffset(0x18)] public uint skillPieceWeight; [FieldOffset(0x1C)] public uint skillPieceAmyWeight; [FieldOffset(0x20)] public uint skillPieceKnucklesWeight; [FieldOffset(0x24)] public uint skillPieceTailsWeight; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct CyloopDropItemParameter { [FieldOffset(0x00)] public CyloopDropItemWeightParameter weight; [FieldOffset(0x28)] public CyloopDropItemWeightParameter weight2; [FieldOffset(0x50)] public uint numRings; [FieldOffset(0x54)] public uint numRings2; [FieldOffset(0x58)] public uint num10Rings; [FieldOffset(0x5C)] public uint numSkillPieces; [FieldOffset(0x60)] public uint skillPieceExp; [FieldOffset(0x64)] public float rareDropCoolTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct CyloopShapeWindCountParameter { [FieldOffset(0x00)] public float damageRate; [FieldOffset(0x04)] public float stunRate; [FieldOffset(0x08)] public float staggerRate; [FieldOffset(0x0C)] public float velocityRate; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct CyloopShapeWindEffectParaemter { [FieldOffset(0x00)] public unsafe fixed byte /* CyloopShapeWindCountParameter[5] */ _param[80]; public unsafe CyloopShapeWindCountParameter* param { get { fixed (byte* p_param = _param) return (CyloopShapeWindCountParameter*)p_param; } } } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct CyloopShapeEffectParameter { [FieldOffset(0x00)] public CyloopShapeWindEffectParaemter wind; } [StructLayout(LayoutKind.Explicit, Size = 0x1460)] public struct PlayerParamCyloop { [FieldOffset(0x00)] public CyloopLocusParameter locus; [FieldOffset(0x4E0)] public CyloopLocusParameter locusQuick; [FieldOffset(0x9C0)] public CyloopLocusParameter locusSuperSonic; [FieldOffset(0xEA0)] public CyloopLocusParameter locusSuperSonicQuick; [FieldOffset(0x1380)] public ColorF auraColor; [FieldOffset(0x1390)] public CyloopDropItemParameter dropItem; [FieldOffset(0x13F8)] public float needSpeed; [FieldOffset(0x13FC)] public CyloopShapeEffectParameter shapeEffect; [FieldOffset(0x144C)] public float lossQuickCyloopEnergy; [FieldOffset(0x1450)] public float recoveryQuickCyloopEnergyByTime; [FieldOffset(0x1454)] public float recoveryQuickCyloopEnergyByTimeInMinigame; [FieldOffset(0x1458)] public float recoveryFriendsQuickCyloopEnergyByRing; } [StructLayout(LayoutKind.Explicit, Size = 0x62C0)] public struct CommonPackageAmy { [FieldOffset(0)] public CommonPackage commonPackage; [FieldOffset(0x4B70)] public PlayerParamCombo combo; [FieldOffset(0x4E50)] public AmyParamParryDebuff parryDebuff; [FieldOffset(0x4E60)] public PlayerParamCyloop cyloop; } public enum SupportedPlane : sbyte { Flat = 0, Slope = 1, Wall = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamCommon { [FieldOffset(0x00)] public float movableMaxSlope; [FieldOffset(0x04)] public float activeLandingSlope; [FieldOffset(0x08)] public float activeLandingSlopeInBoost; [FieldOffset(0x0C)] public float landingMaxSlope; [FieldOffset(0x10)] public float slidingMaxSlope; [FieldOffset(0x14)] public float wallAngleMaxSlope; [FieldOffset(0x18)] public SupportedPlane onStand; [FieldOffset(0x19)] public SupportedPlane onRunInAir; [FieldOffset(0x1A)] public SupportedPlane onRun; [FieldOffset(0x1B)] public bool moveHolding; [FieldOffset(0x1C)] public bool wallSlideSlowInBoost; [FieldOffset(0x1D)] public bool attrWallOnGround; [FieldOffset(0x20)] public float priorityInputTime; [FieldOffset(0x24)] public int capacityRings; [FieldOffset(0x28)] public int capacityRingsLvMax; [FieldOffset(0x2C)] public float collectRingRange; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamSpeedData { [FieldOffset(0x00)] public float initial; [FieldOffset(0x04)] public float min; [FieldOffset(0x08)] public float max; [FieldOffset(0x0C)] public float minTurn; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamSpeedAcceleData { [FieldOffset(0x00)] public float force; [FieldOffset(0x04)] public float force2; [FieldOffset(0x08)] public float damperRange; [FieldOffset(0x0C)] public float jerkMin; [FieldOffset(0x10)] public float jerkMax; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamSpeedAcceleData2 { [FieldOffset(0x00)] public float force; [FieldOffset(0x04)] public float damperRange; [FieldOffset(0x08)] public float jerkMin; [FieldOffset(0x0C)] public float jerkMax; } [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct PlayerParamSpeed { [FieldOffset(0x00)] public PlayerParamSpeedData normal; [FieldOffset(0x10)] public PlayerParamSpeedData normal2; [FieldOffset(0x20)] public PlayerParamSpeedData boost; [FieldOffset(0x30)] public PlayerParamSpeedData boost2; [FieldOffset(0x40)] public PlayerParamSpeedData boostLvMax; [FieldOffset(0x50)] public PlayerParamSpeedData boostLvMax2; [FieldOffset(0x60)] public float maxSpeedOver; [FieldOffset(0x64)] public float opitonMaxSpeedLimitMin; [FieldOffset(0x68)] public float opitonMaxSpeedLimitMax; [FieldOffset(0x6C)] public float thresholdStopSpeed; [FieldOffset(0x70)] public float maxFallSpeed; [FieldOffset(0x74)] public PlayerParamSpeedAcceleData accele; [FieldOffset(0x88)] public PlayerParamSpeedAcceleData decele; [FieldOffset(0x9C)] public PlayerParamSpeedAcceleData2 deceleNeutralMin; [FieldOffset(0xAC)] public PlayerParamSpeedAcceleData2 deceleNeutralMax; [FieldOffset(0xBC)] public float acceleAuto; [FieldOffset(0xC0)] public float deceleAuto; [FieldOffset(0xC4)] public float turnDeceleAngleMin; [FieldOffset(0xC8)] public float turnDeceleAngleMax; [FieldOffset(0xCC)] public float maxGravityAccele; [FieldOffset(0xD0)] public float maxGravityDecele; [FieldOffset(0xD4)] public float deceleSquat; [FieldOffset(0xD8)] public float acceleSensitive; [FieldOffset(0xDC)] public float boostAnimSpeedInWater; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamRotation { [FieldOffset(0x00)] public float baseRotateForce; [FieldOffset(0x04)] public float baseRotateForce2; [FieldOffset(0x08)] public float baseRotateForceSpeed; [FieldOffset(0x0C)] public float minRotateForce; [FieldOffset(0x10)] public float maxRotateForce; [FieldOffset(0x14)] public bool angleRotateForceDecayEnabled; [FieldOffset(0x18)] public float frontRotateRatio; [FieldOffset(0x1C)] public float rotationForceDecaySpeed; [FieldOffset(0x20)] public float rotationForceDecayRate; [FieldOffset(0x24)] public float rotationForceDecayMax; [FieldOffset(0x28)] public float autorunRotateForce; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamRunning { [FieldOffset(0x00)] public float walkSpeed; [FieldOffset(0x04)] public float sneakingSpeed; [FieldOffset(0x08)] public float animSpeedSneak; [FieldOffset(0x0C)] public float animSpeedWalk; [FieldOffset(0x10)] public float animSpeedRun; [FieldOffset(0x14)] public float animSpeedBoost; [FieldOffset(0x18)] public float animLRBlendSampleTime; [FieldOffset(0x1C)] public float animLRBlendAngleMin; [FieldOffset(0x20)] public float animLRBlendAngleMax; [FieldOffset(0x24)] public float animLRBlendSpeed; [FieldOffset(0x28)] public float animLRBlendSpeedToCenter; [FieldOffset(0x2C)] public float minChangeWalkTime; [FieldOffset(0x30)] public float fallAnimationAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamBalanceData { [FieldOffset(0x00)] public float rotateSpeedMinFB; [FieldOffset(0x04)] public float rotateSpeedMaxFB; [FieldOffset(0x08)] public float rotateSpeedMinLR; [FieldOffset(0x0C)] public float rotateSpeedMaxLR; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamBalance { [FieldOffset(0x00)] public PlayerParamBalanceData standard; [FieldOffset(0x10)] public PlayerParamBalanceData loop; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBrake { [FieldOffset(0x00)] public float initialSpeedRatio; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float forceLand; [FieldOffset(0x0C)] public float forceAir; [FieldOffset(0x10)] public float endSpeed; [FieldOffset(0x14)] public float stopTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamTurn { [FieldOffset(0x00)] public float thresholdSpeed; [FieldOffset(0x04)] public float thresholdAngle; [FieldOffset(0x08)] public float turnAfterSpeed; [FieldOffset(0x0C)] public bool stopEdge; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamJump { [FieldOffset(0x00)] public float preActionTime; [FieldOffset(0x04)] public float longPressTime; [FieldOffset(0x08)] public float addForceTime; [FieldOffset(0x0C)] public float force; [FieldOffset(0x10)] public float addForce; [FieldOffset(0x14)] public float forceMin; [FieldOffset(0x18)] public float gravitySize; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamJumpSpeed { [FieldOffset(0x00)] public float acceleForce; [FieldOffset(0x04)] public float deceleForce; [FieldOffset(0x08)] public float deceleNeutralForce; [FieldOffset(0x0C)] public float deceleBackForce; [FieldOffset(0x10)] public float limitMin; [FieldOffset(0x14)] public float limitUpSpeed; [FieldOffset(0x18)] public float rotationForce; [FieldOffset(0x1C)] public float rotationForceDecaySpeed; [FieldOffset(0x20)] public float rotationForceDecayRate; [FieldOffset(0x24)] public float rotationForceDecayMax; [FieldOffset(0x28)] public float baseAirDragScaleMin; [FieldOffset(0x2C)] public float baseAirDragScaleMax; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDoubleJump { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float bounceSpeed; [FieldOffset(0x08)] public float limitSpeedMin; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct PlayerParamFall { [FieldOffset(0x00)] public float thresholdVertSpeed; [FieldOffset(0x04)] public float tolerateJumpTime; [FieldOffset(0x08)] public float fallEndDelayTime; [FieldOffset(0x0C)] public float fallEndFadeTime; [FieldOffset(0x10)] public float acceleForce; [FieldOffset(0x14)] public float deceleForce; [FieldOffset(0x18)] public float overSpeedDeceleForce; [FieldOffset(0x1C)] public float rotationForce; [FieldOffset(0x20)] public float rotationForceDecaySpeed; [FieldOffset(0x24)] public float rotationForceDecayRate; [FieldOffset(0x28)] public float rotationForceDecayMax; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageCommon { [FieldOffset(0x00)] public float invincibleTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamDamageNormal { [FieldOffset(0x00)] public float initialHorzSpeed; [FieldOffset(0x04)] public float initialVertSpeed; [FieldOffset(0x08)] public float deceleForce; [FieldOffset(0x0C)] public float transitFallTime; [FieldOffset(0x10)] public float gravityScale; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageTurnBack { [FieldOffset(0x00)] public float fixedTime; } [StructLayout(LayoutKind.Explicit, Size = 0x1C)] public struct PlayerParamDamageBlowOff { [FieldOffset(0x00)] public float initialHorzSpeed; [FieldOffset(0x04)] public float initialVertSpeed; [FieldOffset(0x08)] public float deceleForceInAir; [FieldOffset(0x0C)] public float deceleForceOnGround; [FieldOffset(0x10)] public float gravityScale; [FieldOffset(0x14)] public float downTime; [FieldOffset(0x18)] public float transitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamDamageGuarded { [FieldOffset(0x00)] public float vertSpeed; [FieldOffset(0x04)] public float horzSpeed; [FieldOffset(0x08)] public float deceleForce; [FieldOffset(0x0C)] public float transitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamDamageRunning { [FieldOffset(0x00)] public float actionTime; [FieldOffset(0x04)] public float minSpeed; [FieldOffset(0x08)] public float lossSpeed; [FieldOffset(0x0C)] public float lossTime; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamDamageQuake { [FieldOffset(0x00)] public float actionTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamDamageLava { [FieldOffset(0x00)] public Vector3 jumpVelocity; [FieldOffset(0x10)] public float gravitySize; [FieldOffset(0x14)] public float invincibleTime; [FieldOffset(0x18)] public float noActionTime; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct PlayerParamDamageMine { [FieldOffset(0x00)] public Vector3 jumpVelocity; [FieldOffset(0x10)] public float gravitySize; [FieldOffset(0x14)] public float invincibleTime; [FieldOffset(0x18)] public float noActionTime; [FieldOffset(0x1C)] public float gravitySizeForFall; [FieldOffset(0x20)] public float maxFallSpeed; [FieldOffset(0x28)] public UnmanagedString cameraShakeName; [FieldOffset(0x38)] public UnmanagedString vibrationName; } [StructLayout(LayoutKind.Explicit, Size = 0xE0)] public struct PlayerParamDamage { [FieldOffset(0x00)] public PlayerParamDamageCommon common; [FieldOffset(0x04)] public PlayerParamDamageNormal normal; [FieldOffset(0x18)] public PlayerParamDamageTurnBack turnBack; [FieldOffset(0x1C)] public PlayerParamDamageBlowOff blowOff; [FieldOffset(0x38)] public PlayerParamDamageGuarded guarded; [FieldOffset(0x48)] public PlayerParamDamageGuarded guardedSS; [FieldOffset(0x58)] public PlayerParamDamageRunning running; [FieldOffset(0x68)] public PlayerParamDamageQuake quake; [FieldOffset(0x70)] public PlayerParamDamageLava lava; [FieldOffset(0x90)] public PlayerParamDamageMine mine; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDeadNormal { [FieldOffset(0x00)] public float invincibleTime; [FieldOffset(0x04)] public float initialHorzSpeed; [FieldOffset(0x08)] public float initialVertSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamDead { [FieldOffset(0x00)] public PlayerParamDeadNormal normal; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamSliding { [FieldOffset(0x00)] public float minSpeed; [FieldOffset(0x04)] public float endSpeed; [FieldOffset(0x08)] public float deceleJerk; [FieldOffset(0x0C)] public float deceleJerkContinue; [FieldOffset(0x10)] public float deceleForceMax; [FieldOffset(0x14)] public float baseRotateForce; [FieldOffset(0x18)] public float baseRotateForceSpeed; [FieldOffset(0x1C)] public float maxRotateForce; [FieldOffset(0x20)] public float frontRotateRatio; [FieldOffset(0x24)] public float rotationForceAutoRun; [FieldOffset(0x28)] public float movableMaxSlope; [FieldOffset(0x2C)] public float gravitySize; [FieldOffset(0x30)] public float minContinueTime; [FieldOffset(0x34)] public float maxAutoRunTime; [FieldOffset(0x38)] public float endSpeedAutoRun; [FieldOffset(0x3C)] public float loopKickTransitTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamStomping { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float initialAccele; [FieldOffset(0x08)] public float maxAccele; [FieldOffset(0x0C)] public float jerk; [FieldOffset(0x10)] public float maxFallSpeed; [FieldOffset(0x14)] public float angle; [FieldOffset(0x18)] public float landingCancelTime; [FieldOffset(0x1C)] public float boundStompingCollisionScale; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct PlayerParamGrind { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float maxBoostSpeed; [FieldOffset(0x08)] public float acceleForce; [FieldOffset(0x0C)] public float deceleForce; [FieldOffset(0x10)] public float limitSpeedMin; } [StructLayout(LayoutKind.Explicit, Size = 0x38)] public struct PlayerParamFallSlope { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float brakeAngle; [FieldOffset(0x0C)] public float highBrakeAngle; [FieldOffset(0x10)] public float brakeForce; [FieldOffset(0x14)] public float brakeForceHigh; [FieldOffset(0x18)] public float gravitySize; [FieldOffset(0x1C)] public float gravitySizeAir; [FieldOffset(0x20)] public float endSpeedFront; [FieldOffset(0x24)] public float endSpeedBack; [FieldOffset(0x28)] public float reverseFallTime; [FieldOffset(0x2C)] public float fallToSlipTime; [FieldOffset(0x30)] public float slipIdlingTime; [FieldOffset(0x34)] public float minSlipTime; } [StructLayout(LayoutKind.Explicit, Size = 0x0C)] public struct PlayerParamFallFlip { [FieldOffset(0x00)] public float thresholdSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float flipAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x68)] public struct PlayerParamTumble { [FieldOffset(0x00)] public bool enabled; [FieldOffset(0x04)] public float sideSpinAngle; [FieldOffset(0x08)] public float initialVertSpeed; [FieldOffset(0x0C)] public float gravitySize; [FieldOffset(0x10)] public float gravitySize2; [FieldOffset(0x14)] public float deceleForceInAir; [FieldOffset(0x18)] public float minSpeedInAir; [FieldOffset(0x1C)] public float rotateEaseTimeLeftRight; [FieldOffset(0x20)] public float rotateEaseTimeFrontBack; [FieldOffset(0x24)] public float rotateSpeedMinLeftRight; [FieldOffset(0x28)] public float rotateSpeedMaxLeftRight; [FieldOffset(0x2C)] public float rotateSpeedMinFrontBack; [FieldOffset(0x30)] public float rotateSpeedMaxFrontBack; [FieldOffset(0x34)] public float angleLeftRightStagger; [FieldOffset(0x38)] public float angleLeftRightRoll; [FieldOffset(0x3C)] public float angleFrontBackRoll; [FieldOffset(0x40)] public float angleBigRoll; [FieldOffset(0x44)] public float inRunTime; [FieldOffset(0x48)] public float inAirTime; [FieldOffset(0x4C)] public float rollSpeedFront; [FieldOffset(0x50)] public float bigRollVelocityRatio; [FieldOffset(0x54)] public float dropDashHoldTime; [FieldOffset(0x58)] public float airBrakeVertSpeed; [FieldOffset(0x5C)] public float airBrakeForce; [FieldOffset(0x60)] public float airTrickHeight; [FieldOffset(0x64)] public float airTrickTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSpinAttack { [FieldOffset(0x00)] public float jumpForce; [FieldOffset(0x04)] public float jumpAddForce; [FieldOffset(0x08)] public float addTime; [FieldOffset(0x0C)] public float acceleForce; [FieldOffset(0x10)] public float deceleForce; [FieldOffset(0x14)] public float brakeForce; [FieldOffset(0x18)] public float limitSpeedMin; [FieldOffset(0x1C)] public float limitSpeedMax; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct PlayerParamHomingAttackData { [FieldOffset(0x00)] public float speed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamHomingBounceData { [FieldOffset(0x00)] public float bounceVertSpeed; [FieldOffset(0x04)] public float bounceHorzSpeed; [FieldOffset(0x08)] public float bounceAcceleForce; [FieldOffset(0x0C)] public float bounceDeceleForce; [FieldOffset(0x10)] public float bounceAngleWidth; [FieldOffset(0x14)] public float bounceTime; [FieldOffset(0x18)] public float attackDownTime; [FieldOffset(0x1C)] public float attackDownTimeForStomp; } [StructLayout(LayoutKind.Explicit, Size = 0xB0)] public struct PlayerParamHomingAttack { [FieldOffset(0x00)] public PlayerParamHomingAttackData sonic; [FieldOffset(0x04)] public PlayerParamHomingAttackData supersonic; [FieldOffset(0x08)] public PlayerParamHomingBounceData sonicBounce; [FieldOffset(0x28)] public PlayerParamHomingBounceData sonicBounceWeak; [FieldOffset(0x48)] public PlayerParamHomingBounceData sonicBounceStorm; [FieldOffset(0x68)] public PlayerParamHomingBounceData sonicBounceStormSwirl; [FieldOffset(0x88)] public PlayerParamHomingBounceData supersonicBounce; [FieldOffset(0xA8)] public float cameraEaseInTime; [FieldOffset(0xAC)] public float cameraEaseOutTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamHitEnemy { [FieldOffset(0x00)] public float bounceVertSpeed; [FieldOffset(0x04)] public float bounceHorzSpeed; [FieldOffset(0x08)] public float attackDownTime; [FieldOffset(0x0C)] public float enableHomingTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct SpeedParam { [FieldOffset(0x00)] public float maxVertSpeed; [FieldOffset(0x04)] public float acceleVertForce; [FieldOffset(0x08)] public float maxHorzSpeed; [FieldOffset(0x0C)] public float acceleHorzForce; } [StructLayout(LayoutKind.Explicit, Size = 0x5C)] public struct PlayerParamDiving { [FieldOffset(0x00)] public SpeedParam normal; [FieldOffset(0x10)] public SpeedParam fast; [FieldOffset(0x20)] public SpeedParam damaged; [FieldOffset(0x30)] public SpeedParam ringdash; [FieldOffset(0x40)] public float startHeight; [FieldOffset(0x44)] public float startSpeed; [FieldOffset(0x48)] public float deceleVertForce; [FieldOffset(0x4C)] public float deceleHorzForce; [FieldOffset(0x50)] public float deceleNeutralForce; [FieldOffset(0x54)] public float damageTime; [FieldOffset(0x58)] public float ringdashTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamFan { [FieldOffset(0x00)] public float damperV; [FieldOffset(0x04)] public float damperH; [FieldOffset(0x08)] public float accelRate; [FieldOffset(0x0C)] public float moveForceFV; [FieldOffset(0x10)] public float moveForceSV; [FieldOffset(0x14)] public float jumpCheckSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamBackflip { [FieldOffset(0x00)] public float jumpSpeed; [FieldOffset(0x04)] public float backSpeed; [FieldOffset(0x08)] public float downAccel; [FieldOffset(0x0C)] public float damperV; [FieldOffset(0x10)] public float damperH; [FieldOffset(0x14)] public float time; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSlowMove { [FieldOffset(0x00)] public float startSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public float accel; [FieldOffset(0x0C)] public float brake; [FieldOffset(0x10)] public float damageSpeed; [FieldOffset(0x14)] public float damageBrake; [FieldOffset(0x18)] public float steeringSpeed; [FieldOffset(0x1C)] public float endSteeringSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSpin { [FieldOffset(0x00)] public float startSlopeAngle; [FieldOffset(0x04)] public float endSlopeAngle; [FieldOffset(0x08)] public float startSpeed; [FieldOffset(0x0C)] public float endSpeed; [FieldOffset(0x10)] public float stickAngle; [FieldOffset(0x14)] public float brake; [FieldOffset(0x18)] public float forceBrake; [FieldOffset(0x1C)] public float maxSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x88)] public struct PlayerParamWallMove { [FieldOffset(0x00)] public float maxSpeed; [FieldOffset(0x04)] public float walkSpeed; [FieldOffset(0x08)] public float walkSpeedMax; [FieldOffset(0x0C)] public float runSpeed; [FieldOffset(0x10)] public float runSpeedMax; [FieldOffset(0x14)] public float walkSpeedOnMesh; [FieldOffset(0x18)] public float walkSpeedOnMeshMax; [FieldOffset(0x1C)] public float runSpeedOnMesh; [FieldOffset(0x20)] public float runSpeedOnMeshMax; [FieldOffset(0x24)] public float minAccessSpeed; [FieldOffset(0x28)] public float stickSpeed; [FieldOffset(0x2C)] public float gravity; [FieldOffset(0x30)] public float accel; [FieldOffset(0x34)] public float brake; [FieldOffset(0x38)] public float stopBrake; [FieldOffset(0x3C)] public float fallSpeed; [FieldOffset(0x40)] public float steeringSpeed1; [FieldOffset(0x44)] public float steeringSpeed2; [FieldOffset(0x48)] public float startSteeringSpeed; [FieldOffset(0x4C)] public float endSteeringSpeed; [FieldOffset(0x50)] public float startTime; [FieldOffset(0x54)] public float useEnergySpeedBase; [FieldOffset(0x58)] public float useEnergySpeedBaseOnMesh; [FieldOffset(0x5C)] public float useEnergySpeedVal; [FieldOffset(0x60)] public float useEnergySpeedValOnMesh; [FieldOffset(0x64)] public float useEnergyAngle; [FieldOffset(0x68)] public float useEnergyAngleOnMesh; [FieldOffset(0x6C)] public float brakeStartEnergy; [FieldOffset(0x70)] public float brakeStartEnergyOnMesh; [FieldOffset(0x74)] public float homingSearchDistanceNear; [FieldOffset(0x78)] public float homingSearchDistanceFar; [FieldOffset(0x7C)] public float wallBumpHeightUpper; [FieldOffset(0x80)] public float wallBumpHeightUnder; [FieldOffset(0x84)] public float recoveryCheckTime; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerParamWallJump { [FieldOffset(0x00)] public float gravitySize; [FieldOffset(0x04)] public float minTime; [FieldOffset(0x08)] public float maxTime; [FieldOffset(0x0C)] public float stopTime; [FieldOffset(0x10)] public float maxDownSpeed; [FieldOffset(0x14)] public float fallGroundDistance; [FieldOffset(0x18)] public float frontForce; [FieldOffset(0x1C)] public float upForce; [FieldOffset(0x20)] public float impulseTime; } [StructLayout(LayoutKind.Explicit, Size = 0x54)] public struct PlayerParamClimbing { [FieldOffset(0x00)] public float stepSpeedFront; [FieldOffset(0x04)] public float stepSpeedFrontDash; [FieldOffset(0x08)] public float stepSpeedSide; [FieldOffset(0x0C)] public float stepSpeedSideDash; [FieldOffset(0x10)] public float stepSpeedBack; [FieldOffset(0x14)] public float stepDashRate; [FieldOffset(0x18)] public float maxAnimSpeed; [FieldOffset(0x1C)] public float exhaustAngle; [FieldOffset(0x20)] public float exhaustAngleOnMesh; [FieldOffset(0x24)] public float exhaustBase; [FieldOffset(0x28)] public float exhaustBaseOnMesh; [FieldOffset(0x2C)] public float exhaustRate; [FieldOffset(0x30)] public float exhaustRateOnMesh; [FieldOffset(0x34)] public float useGrabGaugeSpeed; [FieldOffset(0x38)] public float useGrabGaugeSpeedOnMesh; [FieldOffset(0x3C)] public float useGrabGaugeTurbo; [FieldOffset(0x40)] public float useGrabGaugeTurboOnMesh; [FieldOffset(0x44)] public float homingSearchDistanceNear; [FieldOffset(0x48)] public float homingSearchDistanceFar; [FieldOffset(0x4C)] public float resetAngle; [FieldOffset(0x50)] public float recoveryCheckTime; } [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct PlayerParamSlideDown { [FieldOffset(0x00)] public float time; [FieldOffset(0x04)] public float speed; [FieldOffset(0x08)] public float speedOnMesh; [FieldOffset(0x0C)] public float accel; [FieldOffset(0x10)] public float brake; [FieldOffset(0x14)] public float brakeOnMesh; } [StructLayout(LayoutKind.Explicit, Size = 0x3C)] public struct PlayerParamBoost { [FieldOffset(0x00)] public float consumptionRate; [FieldOffset(0x04)] public float consumptionRateSS; [FieldOffset(0x08)] public float recoveryRate; [FieldOffset(0x0C)] public float recoveryRateSS; [FieldOffset(0x10)] public float reigniteRatio; [FieldOffset(0x14)] public float recoveryByRing; [FieldOffset(0x18)] public float recoveryByAttack; [FieldOffset(0x1C)] public unsafe fixed float blurPowers[3]; [FieldOffset(0x28)] public float blurEaseInTime; [FieldOffset(0x2C)] public float blurEaseOutTime; [FieldOffset(0x30)] public float endSpeed; [FieldOffset(0x34)] public float powerBoostCoolTime; [FieldOffset(0x38)] public float infinityBoostTime; } [StructLayout(LayoutKind.Explicit, Size = 0x34)] public struct PlayerParamAirBoost { [FieldOffset(0x00)] public float startHSpeed; [FieldOffset(0x04)] public float startHSpeedMax; [FieldOffset(0x08)] public float startVSpeed; [FieldOffset(0x0C)] public float minHSpeed; [FieldOffset(0x10)] public float minHSpeedMax; [FieldOffset(0x14)] public float brakeTime; [FieldOffset(0x18)] public float minKeepTime; [FieldOffset(0x1C)] public float maxKeepTime; [FieldOffset(0x20)] public float maxTime; [FieldOffset(0x24)] public float gravityRate; [FieldOffset(0x28)] public float steeringSpeed; [FieldOffset(0x2C)] public float additionalTransitTime; [FieldOffset(0x30)] public float supersonicTime; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAutorun { [FieldOffset(0x00)] public float initialSideSpeed; [FieldOffset(0x04)] public float acceleSideForce; [FieldOffset(0x08)] public float deceleSideForce; [FieldOffset(0x0C)] public float maxSideSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSideStep { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float brakeForce; [FieldOffset(0x08)] public float motionSpeedRatio; [FieldOffset(0x0C)] public float stepSpeed; [FieldOffset(0x10)] public float maxStepDistance; [FieldOffset(0x14)] public float minStepDistance; [FieldOffset(0x18)] public float maxStepSpeed; [FieldOffset(0x1C)] public float minStepSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct PlayerParamSideStep2 { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float brakeForce; [FieldOffset(0x08)] public float motionSpeedRatio; [FieldOffset(0x0C)] public float stepSpeed; [FieldOffset(0x10)] public float maxStepDistance; [FieldOffset(0x14)] public float minStepDistance; [FieldOffset(0x18)] public float maxStepSpeed; [FieldOffset(0x1C)] public float minStepSpeed; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct PlayerParamQuickStep { [FieldOffset(0x00)] public float needSpeed; [FieldOffset(0x04)] public float acceleForce; [FieldOffset(0x08)] public float acceleSideForce; [FieldOffset(0x0C)] public float stepInitialSpeed; [FieldOffset(0x10)] public float avoidForce; [FieldOffset(0x14)] public float justBoostForce; [FieldOffset(0x18)] public float justBoostMax; [FieldOffset(0x1C)] public float justBoostTime; [FieldOffset(0x20)] public float justBoostBrake; } [StructLayout(LayoutKind.Explicit, Size = 0x60)] public struct PlayerParamParry { [FieldOffset(0x00)] public float minRecieveTime; [FieldOffset(0x04)] public unsafe fixed float maxRecieveTimes[4]; [FieldOffset(0x14)] public unsafe fixed float justRecieveTimes[4]; [FieldOffset(0x24)] public float frozenTime; [FieldOffset(0x28)] public float justFrozenTime; [FieldOffset(0x2C)] public float justEffectEasein; [FieldOffset(0x30)] public float justEffectEaseout; [FieldOffset(0x34)] public float justEffectTime; [FieldOffset(0x38)] public float justEffectEasein2; [FieldOffset(0x3C)] public float justEffectEaseout2; [FieldOffset(0x40)] public float justEffectTime2; [FieldOffset(0x44)] public float justEffectEasein3; [FieldOffset(0x48)] public float justEffectEaseout3; [FieldOffset(0x4C)] public float justEffectTime3; [FieldOffset(0x50)] public UnmanagedString cameraName; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct PlayerParamAvoidData { [FieldOffset(0x00)] public float speed; [FieldOffset(0x04)] public float damper; [FieldOffset(0x08)] public float parryTime; [FieldOffset(0x0C)] public float invincibleTime; } [StructLayout(LayoutKind.Explicit, Size = 0x94)] public struct PlayerParamAvoid { [FieldOffset(0x00)] public float time; [FieldOffset(0x04)] public float fixedTime; [FieldOffset(0x08)] public float reentryInputPriorityTime; [FieldOffset(0x0C)] public float reentryTime; [FieldOffset(0x10)] public float frontAngle; [FieldOffset(0x14)] public float backAngle; [FieldOffset(0x18)] public float addFallSpeed; [FieldOffset(0x1C)] public unsafe fixed byte /* PlayerParamAvoidData[7] */ _data[112]; public unsafe PlayerParamAvoidData* data { get { fixed (byte* p_data = _data) return (PlayerParamAvoidData*)p_data; } } [FieldOffset(0x8C)] public float baseDistance; [FieldOffset(0x90)] public float limitAngle; } [StructLayout(LayoutKind.Explicit, Size = 0x8F0)] public struct ModePackage { [FieldOffset(0x00)] public PlayerParamCommon common; [FieldOffset(0x30)] public PlayerParamSpeed speed; [FieldOffset(0x110)] public PlayerParamRotation rotation; [FieldOffset(0x13C)] public PlayerParamRunning running; [FieldOffset(0x170)] public PlayerParamBalance balance; [FieldOffset(0x190)] public PlayerParamBrake brake; [FieldOffset(0x1A8)] public PlayerParamTurn turn; [FieldOffset(0x1B8)] public PlayerParamJump jump; [FieldOffset(0x1D4)] public PlayerParamJumpSpeed jumpSpeed; [FieldOffset(0x204)] public PlayerParamDoubleJump doubleJump; [FieldOffset(0x210)] public PlayerParamFall fall; [FieldOffset(0x240)] public PlayerParamDamage damage; [FieldOffset(0x320)] public PlayerParamDead dead; [FieldOffset(0x32C)] public PlayerParamSliding sliding; [FieldOffset(0x36C)] public PlayerParamStomping stomping; [FieldOffset(0x38C)] public PlayerParamGrind grind; [FieldOffset(0x3A0)] public PlayerParamFallSlope fallSlope; [FieldOffset(0x3D8)] public PlayerParamFallFlip fallFlip; [FieldOffset(0x3E4)] public PlayerParamTumble tumble; [FieldOffset(0x44C)] public PlayerParamSpinAttack spinAttack; [FieldOffset(0x46C)] public PlayerParamHomingAttack homingAttack; [FieldOffset(0x51C)] public PlayerParamHitEnemy hitEnemy; [FieldOffset(0x52C)] public PlayerParamDiving diving; [FieldOffset(0x588)] public PlayerParamFan fan; [FieldOffset(0x5A0)] public PlayerParamBackflip backflip; [FieldOffset(0x5B8)] public PlayerParamSlowMove slowmove; [FieldOffset(0x5D8)] public PlayerParamSpin spin; [FieldOffset(0x5F8)] public PlayerParamWallMove wallmove; [FieldOffset(0x680)] public PlayerParamWallJump walljump; [FieldOffset(0x6A4)] public PlayerParamClimbing climbing; [FieldOffset(0x6F8)] public PlayerParamSlideDown slidedown; [FieldOffset(0x710)] public PlayerParamBoost boost; [FieldOffset(0x74C)] public PlayerParamAirBoost airboost; [FieldOffset(0x780)] public PlayerParamAutorun autorun; [FieldOffset(0x790)] public PlayerParamSideStep sidestep; [FieldOffset(0x7B0)] public PlayerParamSideStep2 sidestep2; [FieldOffset(0x7D0)] public PlayerParamQuickStep quickstep; [FieldOffset(0x7F8)] public PlayerParamParry parry; [FieldOffset(0x858)] public PlayerParamAvoid avoid; } [StructLayout(LayoutKind.Explicit, Size = 0x2C)] public struct AmyParamPropellerJump { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float bounceSpeed; [FieldOffset(0x08)] public float limitSpeedMin; [FieldOffset(0x0C)] public float riseDampingStartTime; [FieldOffset(0x10)] public float riseDampingRate; [FieldOffset(0x14)] public float maxFallSpeed; [FieldOffset(0x18)] public float fallGravitySize; [FieldOffset(0x1C)] public float minDuration; [FieldOffset(0x20)] public float propellerVertSpeedThreshold; [FieldOffset(0x24)] public bool holdTransitHover; [FieldOffset(0x28)] public float practiceTime; } [StructLayout(LayoutKind.Explicit, Size = 0x04)] public struct AmyParamStomping { [FieldOffset(0x00)] public float landAttackScale; } [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct AmyParamHighJump { [FieldOffset(0x00)] public float jumpForce; [FieldOffset(0x04)] public float longPressTime; } public enum Condition : sbyte { Time = 0, Animation = 1 } public enum Shape : sbyte { Sphere = 0, Cylinder = 1, Box = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct PlayerParamAttackCollider { [FieldOffset(0x00)] public Condition condition; [FieldOffset(0x01)] public sbyte count; [FieldOffset(0x04)] public float spanTime; [FieldOffset(0x08)] public Shape shape; [FieldOffset(0x10)] public Vector3 shapeSize; [FieldOffset(0x20)] public Vector3 shapeOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct AmyParamTarotAttackSpeed { [FieldOffset(0x00)] public float initial; [FieldOffset(0x04)] public float min; [FieldOffset(0x08)] public float max; [FieldOffset(0x0C)] public float minTurn; } [StructLayout(LayoutKind.Explicit, Size = 0xA0)] public struct AmyParamTarotAttack { [FieldOffset(0x00)] public PlayerParamAttackCollider hit; [FieldOffset(0x30)] public PlayerParamAttackCollider rollingHit; [FieldOffset(0x60)] public AmyParamTarotAttackSpeed speed; [FieldOffset(0x70)] public AmyParamTarotAttackSpeed speedRingMax; [FieldOffset(0x80)] public float speedEaseInTime; [FieldOffset(0x84)] public float speedEaseOutTime; [FieldOffset(0x88)] public float minSpeedScale; [FieldOffset(0x8C)] public float longPressTime; [FieldOffset(0x90)] public float minRollingTime; [FieldOffset(0x94)] public float rollingTime; [FieldOffset(0x98)] public float stunTime; } [StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct AmyParamCyHammer { [FieldOffset(0x00)] public float radius; [FieldOffset(0x04)] public float effectTime; [FieldOffset(0x08)] public float rotateCycleTime; [FieldOffset(0x10)] public UnmanagedString cameraShakeName; } [StructLayout(LayoutKind.Explicit, Size = 0x30)] public struct AmyParamAirCyHammer { [FieldOffset(0x00)] public float acceleForce; [FieldOffset(0x04)] public float deceleForce; [FieldOffset(0x08)] public float overSpeedDeceleForce; [FieldOffset(0x0C)] public float rotationForce; [FieldOffset(0x10)] public float rotationForceDecaySpeed; [FieldOffset(0x14)] public float rotationForceDecayRate; [FieldOffset(0x18)] public float rotationForceDecayMax; [FieldOffset(0x1C)] public float groundRadius; [FieldOffset(0x20)] public UnmanagedString cameraShakeName; } [StructLayout(LayoutKind.Explicit, Size = 0x78)] public struct AmyParamCyHammerAppearGimmick { [FieldOffset(0x00)] public float appearWaitTime; [FieldOffset(0x04)] public CyloopDropItemParameter dropItem; [FieldOffset(0x6C)] public float airCyHammerBonusScale; [FieldOffset(0x70)] public float airCyHammerMinBonusDistance; [FieldOffset(0x74)] public float airCyHammerMaxBonusDistance; } [StructLayout(LayoutKind.Explicit, Size = 0x50)] public struct AmyParamTarotBoostSpeed { [FieldOffset(0x00)] public float buildInitialSpeed; [FieldOffset(0x04)] public float buildMinSpeed; [FieldOffset(0x08)] public float buildMaxSpeed; [FieldOffset(0x0C)] public float buildAirRotationForce; [FieldOffset(0x10)] public float initialSpeed; [FieldOffset(0x14)] public float maxSpeed; [FieldOffset(0x18)] public PlayerParamSpeedAcceleData accele; [FieldOffset(0x2C)] public PlayerParamSpeedAcceleData decele; [FieldOffset(0x40)] public float baseRotateForce; [FieldOffset(0x44)] public float minTurnSpeed; [FieldOffset(0x48)] public float turnDeceleAngleMin; [FieldOffset(0x4C)] public float turnDeceleAngleMax; } public enum AirAccelMode : sbyte { Alawys = 0, AirAccelMode_None = 1, Speed = 2 } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct AmyParamTarotTurnCamera { [FieldOffset(0x00)] public float minDistance; [FieldOffset(0x04)] public float maxDistance; [FieldOffset(0x08)] public float followTime; [FieldOffset(0x0C)] public float easeInTime; [FieldOffset(0x10)] public float easeOutTime; } [StructLayout(LayoutKind.Explicit, Size = 0xB4)] public struct AmyParamTarotBoost { [FieldOffset(0x00)] public float prepareTime; [FieldOffset(0x04)] public float initialRunTime; [FieldOffset(0x08)] public AmyParamTarotBoostSpeed speed; [FieldOffset(0x58)] public float gravitySize; [FieldOffset(0x5C)] public float gravityBeginTime; [FieldOffset(0x60)] public float gravityMaxTime; [FieldOffset(0x64)] public float gravitySizeMinInAir; [FieldOffset(0x68)] public float gravitySizeMaxInAir; [FieldOffset(0x6C)] public float maxGravityAccele; [FieldOffset(0x70)] public float maxGravityDecele; [FieldOffset(0x74)] public float jumpOutAngle; [FieldOffset(0x78)] public float jumpOutSpeed; [FieldOffset(0x7C)] public bool humpJumpOut; [FieldOffset(0x7D)] public AirAccelMode airAccelMode; [FieldOffset(0x80)] public float airAccelVertSpeedThreshold; [FieldOffset(0x84)] public float quickTurnTime; [FieldOffset(0x88)] public float quickTurnThresholdSpeed; [FieldOffset(0x8C)] public float quickTurnThresholdAngle; [FieldOffset(0x90)] public float quickTurnTurnAfterSpeed; [FieldOffset(0x94)] public bool quickTurnStopEdge; [FieldOffset(0x98)] public float stompingLimitHeight; [FieldOffset(0x9C)] public float stompingLimitJumpOutTime; [FieldOffset(0xA0)] public AmyParamTarotTurnCamera cameraTurn; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct AmyParamTarotDriftCamera { [FieldOffset(0x00)] public float fovy; [FieldOffset(0x04)] public float zRot; [FieldOffset(0x08)] public float distance; [FieldOffset(0x0C)] public float angleLerpFactorPerSec; [FieldOffset(0x10)] public float azimuthOffset; [FieldOffset(0x14)] public float elevationOffset; [FieldOffset(0x18)] public float gravityOffset; [FieldOffset(0x1C)] public float maxAzimuthOffset; [FieldOffset(0x20)] public float maxHorzOffset; } [StructLayout(LayoutKind.Explicit, Size = 0x64)] public struct AmyParamTarotDrift { [FieldOffset(0x00)] public float startAngle; [FieldOffset(0x04)] public float endSpeed; [FieldOffset(0x08)] public float minSpeed; [FieldOffset(0x0C)] public float minSpeedMax; [FieldOffset(0x10)] public float maxSpeed; [FieldOffset(0x14)] public float maxSpeedMax; [FieldOffset(0x18)] public float accel; [FieldOffset(0x1C)] public float brake; [FieldOffset(0x20)] public float maxSteerAngle; [FieldOffset(0x24)] public float steerAccel; [FieldOffset(0x28)] public float maxSteerSpeed; [FieldOffset(0x2C)] public float neutralSteerAccel; [FieldOffset(0x30)] public float maxNeutralSteerSpeed; [FieldOffset(0x34)] public float maxRotateSpeed; [FieldOffset(0x38)] public bool steerFixedInput; [FieldOffset(0x3C)] public float driftDashTime; [FieldOffset(0x40)] public AmyParamTarotDriftCamera camera; } [StructLayout(LayoutKind.Explicit, Size = 0x24)] public struct AmyParamBlowKissCamera { [FieldOffset(0x00)] public float playerUpOffset; [FieldOffset(0x04)] public float playerRightOffset; [FieldOffset(0x08)] public float distance; [FieldOffset(0x0C)] public float targetDistance; [FieldOffset(0x10)] public float distanceEaseTime; [FieldOffset(0x14)] public float azimuth; [FieldOffset(0x18)] public float elevation; [FieldOffset(0x1C)] public float easeInTime; [FieldOffset(0x20)] public float easeOutTime; } [StructLayout(LayoutKind.Explicit, Size = 0x14)] public struct AmyParamHeartBreakCamera { [FieldOffset(0x00)] public float distanceToPlayer; [FieldOffset(0x04)] public float azimuthOffset; [FieldOffset(0x08)] public float elevationOffset; [FieldOffset(0x0C)] public float easeInTime; [FieldOffset(0x10)] public float easeOutTime; } [StructLayout(LayoutKind.Explicit, Size = 0x88)] public struct AmyParamCharmAttack { [FieldOffset(0x00)] public unsafe fixed float lockonLevelUpSpanTime[5]; [FieldOffset(0x14)] public float lockonSearchDistance; [FieldOffset(0x18)] public float lockonSearchDistanceFar; [FieldOffset(0x1C)] public float speed; [FieldOffset(0x20)] public float followSpeed; [FieldOffset(0x24)] public float followTime; [FieldOffset(0x28)] public float chargeTime; [FieldOffset(0x2C)] public float moveTime; [FieldOffset(0x30)] public float preDamageTime; [FieldOffset(0x34)] public float damageSpanTime; [FieldOffset(0x38)] public float postDamageTime; [FieldOffset(0x40)] public UnmanagedString hitStopObject; [FieldOffset(0x50)] public AmyParamBlowKissCamera camera; [FieldOffset(0x74)] public AmyParamHeartBreakCamera cameraHeartBreak; } [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct PlayerParamSpinBoostSpeed { [FieldOffset(0x00)] public float initialSpeed; [FieldOffset(0x04)] public float maxSpeed; [FieldOffset(0x08)] public PlayerParamSpeedAcceleData accele; [FieldOffset(0x1C)] public PlayerParamSpeedAcceleData decele; [FieldOffset(0x30)] public float baseRotateForce; [FieldOffset(0x34)] public float minTurnSpeed; [FieldOffset(0x38)] public float turnDeceleAngleMin; [FieldOffset(0x3C)] public float turnDeceleAngleMax; } public enum PlayerParamSpinBoost_AirAccelMode : sbyte { PlayerParamSpinBoost_AirAccelMode_Alawys = 0, PlayerParamSpinBoost_AirAccelMode_None = 1, PlayerParamSpinBoost_AirAccelMode_Speed = 2 } [StructLayout(LayoutKind.Explicit, Size = 0xF8)] public struct PlayerParamSpinBoost { [FieldOffset(0x00)] public float forceRunTime; [FieldOffset(0x04)] public float initialRunTime; [FieldOffset(0x08)] public PlayerParamSpinBoostSpeed speedBall; [FieldOffset(0x48)] public PlayerParamSpinBoostSpeed speedBoost; [FieldOffset(0x88)] public PlayerParamSpeedAcceleData2 deceleNeutralMin; [FieldOffset(0x98)] public PlayerParamSpeedAcceleData2 deceleNeutralMax; [FieldOffset(0xA8)] public float gravitySize; [FieldOffset(0xAC)] public float gravityBeginTime; [FieldOffset(0xB0)] public float gravityMaxTime; [FieldOffset(0xB4)] public float gravitySizeMinInAir; [FieldOffset(0xB8)] public float gravitySizeMaxInAir; [FieldOffset(0xBC)] public float maxGravityAccele; [FieldOffset(0xC0)] public float maxGravityDecele; [FieldOffset(0xC4)] public float inAirTime; [FieldOffset(0xC8)] public float spinBoostEndSpeed; [FieldOffset(0xCC)] public float jumpOutAngle; [FieldOffset(0xD0)] public float jumpOutSpeed; [FieldOffset(0xD4)] public bool humpJumpOut; [FieldOffset(0xD5)] public PlayerParamSpinBoost_AirAccelMode airAccelMode; [FieldOffset(0xD8)] public float airAccelVertSpeedThreshold; [FieldOffset(0xDC)] public float chargeRotateForce; [FieldOffset(0xE0)] public float chargeRotateForceMinAngle; [FieldOffset(0xE4)] public float chargeRotateForceMaxAngle; [FieldOffset(0xE8)] public UnmanagedString cameraShakeName; } [StructLayout(LayoutKind.Explicit, Size = 0xD30)] public struct ModePackageAmy { [FieldOffset(0)] public ModePackage modePackage; [FieldOffset(0x8F0)] public AmyParamPropellerJump propellerJump; [FieldOffset(0x91C)] public AmyParamStomping stomping; [FieldOffset(0x920)] public AmyParamHighJump highJump; [FieldOffset(0x930)] public AmyParamTarotAttack tarotAttack; [FieldOffset(0x9D0)] public AmyParamCyHammer cyHammer; [FieldOffset(0x9F0)] public AmyParamAirCyHammer airCyHammer; [FieldOffset(0xA20)] public AmyParamCyHammerAppearGimmick cyHammerAppearGimmick; [FieldOffset(0xA98)] public AmyParamTarotBoost tarotBoost; [FieldOffset(0xB4C)] public AmyParamTarotDrift tarotDrift; [FieldOffset(0xBB0)] public AmyParamCharmAttack charmAttack; [FieldOffset(0xC38)] public PlayerParamSpinBoost spinBoost; } [StructLayout(LayoutKind.Explicit, Size = 0x1A8)] public struct WaterModePackage { [FieldOffset(0x00)] public PlayerParamSpeed speed; [FieldOffset(0xE0)] public PlayerParamJump jump; [FieldOffset(0xFC)] public PlayerParamJumpSpeed jumpSpeed; [FieldOffset(0x12C)] public PlayerParamDoubleJump doubleJump; [FieldOffset(0x138)] public PlayerParamBoost boost; [FieldOffset(0x174)] public PlayerParamAirBoost airboost; } [StructLayout(LayoutKind.Explicit, Size = 0x7ED0)] public struct Root { [FieldOffset(0x00)] public CommonPackageAmy common; [FieldOffset(0x62C0)] public ModePackageAmy forwardView; [FieldOffset(0x6FF0)] public WaterModePackage water; [FieldOffset(0x71A0)] public ModePackageAmy cyberspaceSV; } } Library "Bridge.DisableJumpBoardPaths" by "Hyper" { #include "BlackboardStatus" noemit #lib "Memory" private static bool _isInitialised = false; private static bool _isCyberSpace = false; public static bool IsDisabledOnIslands = false; public static bool IsDisabledInCyberSpace = false; [LibraryInitializer] public void Init() { if (_isInitialised) return; /* 0x140EC6CB0 */ long sigSendMessage = Memory.ReadCall ( /* v1.41: 0x14926F0E3 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x80\x7D\xE5\x00\x0F\x84\xDB\x00\x00\x00\xE8\xCC\xCC\xCC\xCC\x48\x89\xC2", "x????xxxxxxxxxxx????xxx" ) ); fixed (bool* p_isCyberSpace = &_isCyberSpace) fixed (bool* pIsDisabledOnIslands = &IsDisabledOnIslands) fixed (bool* pIsDisabledInCyberSpace = &IsDisabledInCyberSpace) { /* This hook checks if we're on an island and calls the message sender to enter Sonic into the jump board path if we're in Cyber Space. */ WriteAsmHook ( $@" mov rbx, {(long)p_isCyberSpace} cmp byte ptr [rbx], 0 jnz isCyberSpace mov rbx, {(long)pIsDisabledOnIslands} cmp byte ptr [rbx], 0 jnz exit sendMessage: lea r8, qword ptr [rbp + 0x57 + 0xFFFFFFFFFFFFFF40] lea rdx, qword ptr [rbp + 0x57 + 0x10] mov ecx, [rax] mov dword ptr [rbp + 0x57 + 0x10], ecx mov rcx, rsi mov r9, {sigSendMessage} call r9 jmp exit isCyberSpace: mov rbx, {(long)pIsDisabledInCyberSpace} cmp byte ptr [rbx], 0 jz sendMessage exit: ", /* 0x14964DF16 */ ScanSignature ( "\x48\x8D\x55\x67\x8B\x08\x89\x4D\x67\x48\x89\xF1", "xxxxxxxxxxxx" ), HookBehavior.Replace ); } _isInitialised = true; } [LibraryUpdate] public void Update() { _isCyberSpace = IS_WORLD_FLAG(IsCyberSpace); } } Library "Bridge.DisableMessages" by "Hyper" { #include "Helpers" noemit #lib "GameMode" using System.Collections.Generic; private static bool _isInitialised = false; public static bool IsDisabledTutorialMessages = false; public static bool IsDisabledDLCMessages = false; private static List _allowedMessages = new() { "tu1000_200", "tu1000_530", "tu1000_570", "tu1000_590" }; private static List _deniedMessages = new() { "tu1000dlc_060", "tu1000dlc_050", "tu1000dlc_150", "tu1000dlc_140" }; UNMANAGED_FUNCTION(bool, CheckOverlayMessage, long in_pCaptionName) { bool result = false; if (in_pCaptionName == 0) return true; string captionName = FROM_STRING_PTR(in_pCaptionName); if (IsDisabledDLCMessages && GameMode.GetName() != "GameModeTitle") { if (_deniedMessages.Contains(captionName)) result = true; } if (IsDisabledTutorialMessages && !result) { if (!_allowedMessages.Contains(captionName)) result = captionName.StartsWith("tu") && !captionName.Contains("dlc_"); } return result; } [LibraryInitializer] public void Init() { if (_isInitialised) return; WriteAsmHook ( $@" ; Restore original code. mov qword ptr [rsp + 0x08], rbx mov qword ptr [rsp + 0x10], rbp mov qword ptr [rsp + 0x18], rsi push rax ; Checks the overlay type, expected 1. mov eax, dword ptr [rdx + 0x18] cmp eax, 1 jne exit ; I hate it here. push rcx push rdx push r8 push r9 push r10 push r11 mov rcx, qword ptr [rdx + 0x48] mov rax, {GET_UNMANAGED_FUNCTION_PTR(CheckOverlayMessage)} call rax cmp al, 1 pop r11 pop r10 pop r9 pop r8 pop rdx pop rcx jnz exit pop rax ret exit: pop rax ", /* v1.10: 0x14093AFB0 */ /* v1.20: 0x14096E8A0 */ /* v1.30: 0x1409E38E0 */ /* v1.40: 0x140AC85C0 */ ScanSignature ( "\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x10\x48\x89\x74\x24\x18\x57\x41\x56\x41\x57\x48\x83\xEC\x20\x4C\x8B\xF1\x48\x8B\xEA", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); _isInitialised = true; } } Code "Force Free Camera in 3D" in "Camera/Cyber Space" by "Hyper" does "Forces the camera to always be controllable in 3D, regardless of camera volumes." // #include "BlackboardStatus" noemit #lib "Player" #import "Messages" // { if (!IS_WORLD_FLAG(IsCyberSpace)) return; if (Player.Status.IsSideView()) return; Messages.SendMessageToLayer(16, new MsgStartFreeCamera()); } Code "Force Free Camera in 2D" in "Camera/Cyber Space" by "Hyper" does "Forces the camera to be unlocked and always controllable in 2D." // #include "BlackboardStatus" noemit #lib "Player" #import "Messages" // { if (!IS_WORLD_FLAG(IsCyberSpace)) return; if (!Player.Status.IsSideView()) return; Messages.SendMessageToLayer(16, new MsgStartFreeCamera()); } Code "Use Open Zone Camera FOV" in "Camera/Cyber Space" by "Hyper" does /* Sets the field of view to match that of the open zone camera. Notes; - This is useful when using the "Force Free Camera" codes. */ // #include "BlackboardStatus" noemit #lib "Player" #import "Cameras" #import "GOComponents" // { if (!IS_WORLD_FLAG(IsCyberSpace)) return; var pPlayer = Player.GetPlayerData(); if (pPlayer == null) return; var pGOCCamera = GameObject.GetGOC(&pPlayer->GameObject); if (pGOCCamera == null) return; var pStandardCamera = pGOCCamera->GetCameraController(); if (pStandardCamera == null) return; var pStandardCameraContext = pStandardCamera->pContext; if (pStandardCameraContext == null) return; pStandardCameraContext->SetFieldOfView(60.0f); } Patch "Disable Tilt Limit" in "Camera/Photo Mode" by "Hyper" { /* 0x1400A5F66 */ var addr = ScanSignature ( "\x72\x1D\x41\x0F\x2F\xC2", "xxxxxx" ); WriteNop(addr, 2); WriteProtected(addr + 0x16, Assemble("mov rax, rcx\n nop")); } Code "Extended Photo Mode" in "Camera/Photo Mode" by "Hyper" does /* Allows for quick access to Photo Mode via a button combination with some extended features. Controller Layout; - RS (x2) - toggle Photo Mode - Start - toggle game execution (hold to resume, release to suspend) - Back - bring the player to the camera's position - B - exit Photo Mode Keyboard/Mouse Layout; - Tab - toggle Photo Mode - 9/X1 - toggle game execution (hold to resume, release to suspend) - 0/X2 - bring the player to the camera's position - ESC - exit Photo Mode Notes; - This allows you to access Photo Mode in other game modes, as the menu option isn't present outside of the islands. - When toggling Photo Mode in Cyber Space, the Red Ring display will be hidden permanently. - When teleporting the player to the camera, the reset position will change to the position of the camera at that moment. - For the keyboard/mouse layout, X buttons refer to the back/forward buttons on the mouse respectively. */ // #include "BlackboardStatus" noemit #lib "GameManager" #lib "GameObject" #lib "HMM" #lib "MathHelpers" #lib "PhotoMode" #lib "Player" #lib "Time" #lib "Win32" #lib "XInput" #import "Messages" #load "System.Numerics.dll" using System.Collections.Generic; using System.Numerics; static bool _isInitialised = false; static bool _isExitInputBuffered = false; static bool _isToggleKeyBuffered = false; static bool _isResumeInputReceivedOnce = false; static bool _isResumeMessageSent = false; static bool _isSuspendMessageSent = false; static bool _isOrbitCamera = true; static float _inputTimer = 0.0f; static float _inputTimerThreshold = 0.5f; static int _inputCount = 0; static List _forceExitTeleportStates = new() { Sonic.StateID.StateCaught, Sonic.StateID.StateGrind, Sonic.StateID.StateJumpBoardLaunch, Sonic.StateID.StateSpringJump }; static bool IsKeyDown(Keys in_keys) { if ((GetAsyncKeyState(Keys.LMenu) & 0x8000) != 0) return false; return (GetAsyncKeyState(in_keys) & 0x8000) != 0; } // { if (!_isInitialised) { foreach (var code in HMM.GetCodes()) { if (code == "Camera/Photo Mode/Disable Orbit Camera (experimental)") { _isOrbitCamera = false; break; } } // Disable Photo Mode exit confirmation. WriteNop ( /* 0x1402073FD */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCF\xE8\xCC\xCC\xCC\xCC\x48\x8B\x88\x90\x00\x00\x00\x48\x8B\x41\x78\x0F\xBE\x48\x47", "x????x????xxxxxxx????xxxxxxxxxxxxxxx" ), 5 ); _isInitialised = true; } if (!Win32.IsGameForegroundWindow()) return; if (IsKeyDown(Keys.Tab)) { _inputCount = _isToggleKeyBuffered ? 0 : 2; _isToggleKeyBuffered = true; } else { _isToggleKeyBuffered = false; } if (_inputTimer <= _inputTimerThreshold) { if (Player.Input.IsPressed(Player.InputActionType.CameraGaze)) _inputCount++; } else { _inputTimer = 0.0f; _inputCount = 0; } _inputTimer += Time.GetDeltaTime(); if (_inputCount >= 2) { PhotoMode.Toggle(); _inputTimer = 0.0f; _inputCount = 0; } if (PhotoMode.IsEnabled()) { bool isTeleportInputDown = XInput.IsButtonDown(XInput.Buttons.BACK) || (IsKeyDown(Keys.D0) || IsKeyDown(Keys.XButton2)); if ((XInput.IsButtonDown(XInput.Buttons.START) || (IsKeyDown(Keys.D9) || IsKeyDown(Keys.XButton1))) || isTeleportInputDown) { _isResumeInputReceivedOnce = true; if (!_isResumeMessageSent) { Messages.EnqueueMessage(new MsgResumeWorld("PhotoMode")); _isResumeMessageSent = true; } _isSuspendMessageSent = false; } else { /* Check if the Start button has been pressed at least once, since suspending the game world after Photo Mode itself does causes some problems. */ if (!_isSuspendMessageSent && _isResumeInputReceivedOnce) { Messages.EnqueueMessage(new MsgSuspendWorld("PhotoMode", 0x31F8000)); _isSuspendMessageSent = true; } _isResumeMessageSent = false; } if (isTeleportInputDown) { var kinematics = Player.Kinematics.Get(); var pPhotoModeCamera = PhotoMode.GetCamera(); // Force the player out of the current state when teleporting, if necessary. if (_forceExitTeleportStates.Contains(Player.State.GetCurrentStateID()) || IS_STATE_FLAG(IsWallClimb)) Player.State.SetState(Sonic.StateID.StateStand); if (kinematics != null && pPhotoModeCamera != null) { var centre = pPhotoModeCamera->Centre; var dist = pPhotoModeCamera->Distance; // Update camera start centre to new camera centre. pPhotoModeCamera->StartCentre = centre; if (_isOrbitCamera) { kinematics->Position = centre; } else { float yawRad = MathHelpers.WrapToRadians(pPhotoModeCamera->Yaw); float pitchRad = MathHelpers.WrapToRadians(pPhotoModeCamera->Pitch); // Calculate the direction of the orbit camera. var direction = new Vector3 ( (float)(Math.Sin(yawRad) * Math.Cos(pitchRad)), (float)(Math.Sin(pitchRad)), (float)(Math.Cos(yawRad) * Math.Cos(pitchRad)) ); // Project the player to the opposite side of the sphere. kinematics->Position = (centre + -direction * (dist + 1.5f)) + new Vector3(0.0f, -0.5f, 0.0f); } // Kill velocity to prevent jitter. kinematics->Velocity = Vector3.Zero; } } if (!_isExitInputBuffered) { if (XInput.IsButtonDown(XInput.Buttons.B) || IsKeyDown(Keys.Escape) || IS_WORLD_FLAG(IsDead)) PhotoMode.SetEnabled(false); } else if (!XInput.IsButtonDown(XInput.Buttons.B)) { _isExitInputBuffered = false; } } else { /* Check B input before entering Photo Mode in case the player is squatting. */ if (XInput.IsButtonDown(XInput.Buttons.B)) _isExitInputBuffered = true; _isResumeInputReceivedOnce = false; } } Patch "Disable Orbit Camera (experimental)" in "Camera/Photo Mode" by "Hyper" does /* Makes the camera in Photo Mode control more like a first-person camera, rather than orbiting a specific point. Known issues; - The camera will always point up in Supreme's arena. */ // static float Distance = 0.1f; // { fixed (float* pDistance = &Distance) { WriteAsmHook ( $@" mov rcx, {(long)pDistance} movss xmm8, dword ptr [rcx] mov rcx, rsi ", /* 0x1400B1E41 */ ScanSignature ( "\x48\x8B\xCE\xE8\xCC\xCC\xCC\xCC\xF3\x44\x0F\x10\x40\x2C", "xxxx????xxxxxx" ), HookBehavior.Replace ); } } Patch "Disable Camera Collision" in "Camera/Photo Mode" by "Hyper" // #lib "Memory" // { // Camera position Memory.WriteForceJump ( /* 0x1400B3442 */ ScanSignature ( "\x0F\x84\x2D\x02\x00\x00\xF3\x0F\x10\x0D", "xxxxxxxxxx" ) ); // Camera rotation Memory.WriteForceJump ( /* 0x1400B2BEE */ ScanSignature ( "\x0F\x84\xAA\x01\x00\x00\x0F\x28\x8D\x80\x00\x00\x00", "xxxxxxxxxxxxx" ) ); // Camera position (water) Memory.WriteForceJump ( /* 0x1400B3764 */ ScanSignature ( "\x73\x33\x48\x8D\x55\x80", "xxxxxx" ) ); // Camera rotation (water) WriteProtected ( /* 0x1400B2E8C */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\xF3\x0F\x10\x40\x14\x0F\x2F\xC7\x73\x04", "x????xxxxxxxxxx" ), 0xEB, 0x11 ); } Patch "Disable Distance Limit" in "Camera/Photo Mode" by "Hyper" // #lib "Memory" // { Memory.WriteForceJump ( /* 0x1400B3425 */ ScanSignature ( "\x76\x7D\x0F\x10\x23", "xxxxx" ) ); } Patch "Disable Zoom Limit (experimental)" in "Camera/Photo Mode" by "Hyper" does /* Allows the Photo Mode camera to zoom in and out past the base limit. Known issues; - Setting the camera zoom to 90+ FOV causes the game to become unstable. */ { /* 0x1400A5D69 */ var addr = ScanSignature ( "\x72\x1C\x41\x0F\x2F\xF0", "xxxxxx" ); WriteNop(addr, 2); WriteProtected(addr + 0x16, Assemble("mov rax, rcx\n nop")); } Code "Infinite Purple Coins" in "Cheats/Fishing" by "Hyper" // #include "SaveData" noemit // { SAVE_SET_PARAM(character.numFishCoins, ushort.MaxValue); } Code "Infinite Tickets" in "Cheats/Fishing" by "Hyper" // #include "SaveData" noemit // { SAVE_SET_PARAM(character.numGoldCards, ushort.MaxValue); } Code "Infinite Tokens" in "Cheats/Fishing" by "Hyper" // #include "SaveData" noemit // { SAVE_SET_PARAM(character.numFishTokens, ushort.MaxValue); } Patch "Always Unlocked Arcade Mode" in "Cheats/UI" by "Hyper" { WriteNop ( /* 0x140ACF3DF */ ScanSignature ( "\x74\x57\x4C\x8B\x7B\x08", "xxxxxx" ), 2 ); } Patch "Always Unlocked Extreme Difficulty" in "Cheats/UI" by "Hyper" { WriteNop ( /* 0x140A007D9 */ ScanSignature ( "\x74\x65\x0F\x1F\x44\x00\x00", "xxxxxxx" ), 2 ); } Patch "Always Unlocked New Game+" in "Cheats/UI" by "Hyper" // #lib "Memory" // { // Always display menu item. Memory.WriteForceJump ( /* 0x140ACF05D */ ScanSignature ( "\x0F\x85\xC1\x00\x00\x00\x33\xD2", "xxxxxxxx" ) ); // Allow any save slot. Memory.WriteForceJump ( /* 0x140AEBBC6 */ ScanSignature ( "\x75\x6E\x83\xFE\x04", "xxxxx" ) ); } Patch "Always Allow Unlocking Story Skills" in "Cheats/Skills" by "Hyper" does /* Allows the skills typically obtained through story progression to be unlocked as regular skills for free. Affected skills; - Grand Slam - Cyclone Kick - Cross Slash */ // static int Seek = 0; // { fixed (int* pSeek = &Seek) { WriteAsmHook ( $@" push rax push rbx mov rax, {(long)pSeek} iterate: cmp dword ptr [rax], 0x3C ; 60 (fixed array size of 20 elements, each are 3 bytes total) jge exit mov ebx, dword ptr [rax] add rbx, rdx cmp byte ptr [rbx], 0xFF ; check 'unlockPoint' field, 0xFF is reserved for story skills jne notStorySkill ; not 0xFF, so don't perform any operations on this element mov byte ptr [rbx], 0 ; set 'unlockPoint' to zero, who needs skill points anyway? mov byte ptr [rbx + 2], 0 ; set 'present' field to zero, this'll treat the skill as a normal one notStorySkill: add dword ptr [rax], 3 ; increment by three to reach the next element in the next iteration jmp iterate exit: mov dword ptr [rax], 0 ; reset incrementation, this code runs every time the skill tree opens, so we'll be back pop rbx pop rax movzx edi, byte ptr [rsi + rax * 8 + 0x30] movzx ecx, byte ptr [rdx + 1] imul edi, ecx add dil, [rdx] ", /* 0x140AA5F50 */ ScanSignature ( "\x0F\xB6\x7C\xC6\x30", "xxxxx" ), HookBehavior.Replace ); } } Patch "Always Have Power Boost on Islands" in "Cheats/Skills" by "SuperSonic16" // #lib "Memory" // { Memory.WriteForceJump ( /* 0x140994D48 */ ScanSignature ( "\x74\x2A\x0F\xBE\x43\x30", "xxxxxx" ) ); } Code "Always Unlocked Spin Dash" in "Cheats/Skills" by "Hyper" // #include "BlackboardStatus" noemit static bool _isInitialised = false; // { if (!_isInitialised) { // Unlock various components of Spin Dash. WriteAsmHook ( $@" mov al, 1 ret ", /* v1.41: 0x140AFEF70 */ ScanSignature ( "\x48\x8B\x41\x08\xF6\x40\x4C\x06", "xxxxxxxx" ), HookBehavior.Replace ); _isInitialised = true; } SET_COMBAT_FLAG(IsSpinDash, true); } Code "Infinite Quick Cyloop Gauge" in "Cheats/Skills" by "Hyper" // #lib "BlackboardBattle" // { var pBlackboardBattle = BlackboardBattle.Get(); if (pBlackboardBattle == null) return; pBlackboardBattle->QuickCyloopAmount = 120.0f; } Patch "Always Have Power Boost in Cyber Space" in "Cheats/Skills" by "Hyper" // #lib "Memory" // { Memory.WriteForceJump ( /* v1.41: 0x1409968E3 */ ScanSignature ( "\x75\x12\x48\x8B\x4F\x20", "xxxxxx" ) ); } Code "Infinite Phantom Rush Gauge" in "Cheats/Skills" by "Hyper" // #lib "BlackboardBattle" // { var pBlackboardBattle = BlackboardBattle.Get(); if (pBlackboardBattle == null) return; pBlackboardBattle->PhantomRushAmount = 120.0f; } Code "Infinite Skill Points" in "Cheats/Skills" by "Hyper" // #lib "GameManager" #import "Services" // { var pExpManager = GameManager.GetService(); if (pExpManager == null) return; pExpManager->Sonic.TotalSkillPoints = 999; pExpManager->Amy.TotalSkillPoints = 999; pExpManager->Knuckles.TotalSkillPoints = 999; pExpManager->Tails.TotalSkillPoints = 999; } Patch "Infinite Training Simulator Timer" in "Cheats/Timers" by "Hyper" does "Allows the timer in Training Simulator to drop below zero and continue uninterrupted." // #lib "Memory" // { Memory.WriteForceJump ( /* 0x1401D1F56 */ ScanSignature ( "\x0F\x87\x33\x01\x00\x00\x48\x8D\x05", "xxxxxxxxx" ) ); } Code "Disable Cyber Space Timer" in "Cheats/Timers" by "Hyper" // #lib "GameMode" #import "GameModes" // { var pGameModeCyberStage = GameMode.Get("GameModeCyberStage"); if (pGameModeCyberStage == null) return; var pGameModeStageTimeExtension = pGameModeCyberStage->GetExtension(); if (pGameModeStageTimeExtension == null) return; pGameModeStageTimeExtension->Time = 0.0f; } Patch "Disable Ring Loss from Damage" in "Cheats/Player" by "RagdollClash" { WriteProtected ( /* 0x140799210 */ ScanSignature ( "\x4C\x8B\x49\x30\x44\x8B\xC2\x41\xF7\xD8\x45\x85\xC0\x7E\x1B\x41\x8B\x41\x24\x41\x2B\x41\x28\x44\x3B\xC0\x44\x0F\x4D\xC0\x45\x03\x41\x28\x41\x8B\xC0\x45\x89\x41\x28\xC3\x41\x8B\x49\x20\x41\x2B\x49\x28\x41\x3B\xC8\x44\x0F\x4D\xC1\x45\x03\x41\x28\x41\x8B\xC0\x45\x89\x41\x28\xC3", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ), 0xC3 ); } Patch "Disable Ring Loss from Super Sonic" by "MegAmi" in "Cheats/Player" does "Disables losing a ring every second as Super Sonic." { WriteNop ( /* v1.41: 0x14099C4C9 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\x85\xC0\x75\x3D", "x????xxxx????xxxx" ), 5 ); } Patch "Disable Ring Capacity Debuff for New Final Boss" by "MegAmi" in "Cheats/Player" does "Disables max rings decreasing when getting hit by the energy ball projectiles in the final boss of Another Story." { /* 1.40: 0x14091C408 */ WriteNop(ScanSignature("\x41\x89\x40\x04\x41\x8B\x50\x08", "xxxxxxxx"), 8); // First 4 nops disable the max rings decrease, last 4 nops disable losing current rings } Patch "Keep Red Rings on Death" in "Cheats/Player" by "WasifBoomz" does "Prevents you from losing Red Rings after dying in Cyber Space." { WriteNop ( /* 0x1401D29C4 */ ScanSignature ( "\x88\x41\x1A\xC3\x0F\xB6\x41\x18\x88\x41\x1A\x88\x41\x19\xC3\x0F\xB6\x41\x1A\x88\x41\x18", "xxxxxxxxxxxxxxxxxxxxxx" ), 3 ); } Code "Always Start with Max Rings for Bosses" in "Cheats/Player" by "Trepe Serafin" // #lib "Player" #lib "BlackboardItem" static bool Refill = false; // { var pBlackboardItem = BlackboardItem.Get(); if (pBlackboardItem == null) return; int maxrings = pBlackboardItem->RingCapacity; int rings = pBlackboardItem->RingCount; if (BlackboardStatus.IsSuper() && !Refill) { pBlackboardItem->RingCount += (maxrings - rings); Refill = true; } if (!BlackboardStatus.IsSuper()) { Refill = false; } } Patch "Always Unlocked All Juke Box Songs" in "Cheats/Player" by "Hyper" { WriteProtected ( /* 0x1408BCE36 */ ScanSignature ( "\x74\x34\x8B\xC6\xFF\xC6", "xxxxxx" ), 0xEB ); } Code "Infinite Boost Gauge" in "Cheats/Player" by "Hyper" // #lib "Player" #import "Plugins" // { var pStatePluginBoost = Player.State.GetStatePlugin(); if (pStatePluginBoost == null) return; pStatePluginBoost->BoostAmount = pStatePluginBoost->BoostCapacity; } Code "Keep Rings from Cyber Space on Islands" in "Cheats/Player" by "Hyper" does "Carries your rings over to the islands from Cyber Space." // #lib "BlackboardItem" #lib "GameMode" #lib "MathHelpers" #lib "Player" static bool _isAddedCyberSpaceRingCount = false; static int _cyberSpaceRingCount = 0; // { var name = GameMode.GetName(); /* Reset on title, in case exiting out of Arcade Mode or Cyber Space Challenge. */ if (name == "GameModeTitle") _cyberSpaceRingCount = 0; var pBlackboardItem = BlackboardItem.Get(); if (pBlackboardItem == null) return; if (name == "GameModeCyberStage") { // Check if we've reached the goal so we don't carry rings via exiting from the menu. _cyberSpaceRingCount = Player.State.GetCurrentStateID() == Sonic.StateID.StateNoisyGoal ? pBlackboardItem->RingCount : 0; _isAddedCyberSpaceRingCount = false; } else if (name == "GameModeStage") { if (!_isAddedCyberSpaceRingCount) { pBlackboardItem->RingCount = MathHelpers.Clamp ( pBlackboardItem->RingCount + _cyberSpaceRingCount, 0, pBlackboardItem->RingCapacity ); _cyberSpaceRingCount = 0; _isAddedCyberSpaceRingCount = true; } } } Patch "Disable Damage (experimental)" in "Cheats/Player" by "Hyper" does /* Disables damage completely and makes Sonic invulnerable. Known issues; - Asura will softlock when Sonic is supposed to take damage after taking out one of the arms. */ { WriteProtected ( /* 0x140915C52 */ ScanSignature ( "\x0F\x84\x64\x01\x00\x00\x83\xEA\x02", "xxxxxxxxx" ), 0xE9, 0x80, 0x00, 0x00, 0x00 ); } Patch "Always Play 'Vandalize' During Credits" in "Audio/Music" by "RagdollClash" // #lib "Memory" // { /* v1.40: 0x1401EB95E */ WriteNop ( ScanSignature ( "\x3C\x02\x0F\x8D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\xD0", "xxxx????x????xxx" ), 8 ); /* v1.40: 0x1409FFA9A */ Memory.WriteForceJump ( ScanSignature ( "\x3C\x02\x7C\x00\x0F\x28\x05\x00\x00\x00\x00\x48\x8D\x54\x24\x00", "xxx?xxx????xxxx?" ) + 2 ); } Patch "Disable Fishing Jingle" in "Audio/Music" by "Hyper" does "Disables the jingle that plays when successfully reeling in a fish." { WriteNop ( /* 0x1406D82AA */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x8B\x8E\x78\x02\x00\x00\xE8\xCC\xCC\xCC\xCC\x84\xC0\x74\x0F", "x????xxxxxxx????xxxx" ), 5 ); } Patch "Always Play 'One Way Dream' During Credits" in "Audio/Music" by "RagdollClash" // #lib "Memory" // { /* v1.40: 0x1401EB95E */ Memory.WriteForceJump ( ScanSignature ( "\x3C\x02\x0F\x8D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\xD0", "xxxx????x????xxx" ) + 2 ); /* v1.40: 0x1409FFA9A */ WriteNop ( ScanSignature ( "\x3C\x02\x7C\x00\x0F\x28\x05\x00\x00\x00\x00\x48\x8D\x54\x24\x00", "xxx?xxx????xxxx?" ), 4 ); } Patch "Allow Juke Box in Another Story (experimental)" in "Audio/Music" by "angryzor & Hyper" does /* Allows using Juke Box whilst playing Another Story. Known issues; - Changing the Music Playback mode does not affect Another Story. */ // #lib "Memory" // { // Restore Juke Box UI. WriteNop ( /* v1.41: 0x1479E2B0D */ ScanSignature ( "\x75\x73\xE8\xCC\xCC\xCC\xCC\x48\x89\xC2", "xxx????xxx" ), 2 ); // Restore Juke Box option select. WriteProtected ( /* v1.41: 0x140A789A0 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x88\x85\xF0\x10\x00\x00", "x????xxxxxx" ), Assemble("xor al, al\n nop\n nop\n nop") ); // Restore Juke Box options' visibility. WriteAsmHook ( $@" xor al, al ret ", /* v1.41: 0x140A8D4C0 */ Memory.ReadCall ( /* v1.41: 0x140A9190A */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x84\xC0\x74\x0A\x33\xD2\x48\x8B\xCB\xE8\xCC\xCC\xCC\xCC\xB2\x04", "x????xxxxxxxxxx????xx" ) ), HookBehavior.Replace ); } Code "Play Random Soundtrack in Cyber Space" in "Audio/Music" by "Hyper" does "Plays a random soundtrack every time you enter Cyber Space." // static long Address = 0; static string[] BgmList = new[] { /* Kronos */ "bgm_w6d01", "bgm_w6d02", "bgm_w6d03", "bgm_w6d04", "bgm_w6d05", "bgm_w6d06", "bgm_w6d07", "bgm_w6d08", "bgm_w6d09", "bgm_w6d10", /* Ares */ "bgm_w7d01", "bgm_w7d02", "bgm_w7d03", "bgm_w7d04", "bgm_w7d05", "bgm_w7d06", "bgm_w7d07", "bgm_w7d08", /* Chaos */ "bgm_w8d01", "bgm_w8d02", "bgm_w8d03", "bgm_w8d04", "bgm_w8d05", "bgm_w8d06", /* Ouranos */ "bgm_w9d02", "bgm_w9d03", "bgm_w9d04", "bgm_w9d05", "bgm_w9d06", "bgm_w9d07", /* Another Story */ "bgm_w6d21", "bgm_w6d22", "bgm_w6d23", "bgm_w7d21", "bgm_w7d22", "bgm_w7d23", "bgm_w9d21", "bgm_w9d22", "bgm_w9d23" }; // { if (Address == 0) { /* 0x14132A3C0 */ Address = ScanSignature ( "bgm_%s", "xxxxxx" ); } else { WriteProtected(Address, System.Text.Encoding.UTF8.GetBytes(BgmList[new Random().Next(0, BgmList.Length)])); } } Patch "Disable Idle Music Volume Reduction" in "Audio/Music" by "Hyper" does "Disables the timer that lowers the game's music volume when idle for too long." { WriteNop ( /* 0x1408BEE05 */ ScanSignature ( "\x89\x03\x8B\x41\x04", "xxxxx" ), 2 ); } Patch "Disable Drop Dash Turning Delay" in "Physics/Sonic" by "Hyper" does "Disables the out of control timer that determines when Sonic can start turning whilst drop dashing." { WriteNop ( /* 0x14084323B */ ScanSignature ( "\x73\x19\x48\x8B\x47\x40", "xxxxxx" ), 2 ); } Code "Tighter Drop Dash Rotation" in "Physics/Sonic" by "Hyper" does "Allows for tighter steering whilst rolling for more precise movement." // #include "Reflection" noemit #lib "Reflection" #lib "SonicParameters" // { var SonicParametersInfo = Reflection.GetDataInfo("player_common"); if (SonicParametersInfo.pData == null) return; RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, dropDash.steeringSpeed1, 400.0f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, dropDash.steeringSpeed2, 200.0f); RFL_SET_CONTEXTUAL_PLAYER_PARAM(SonicParametersInfo, dropDash.brake, 2.5f); } Code "Airborne Drop Dash Rotation" in "Physics/Sonic" by "Hyper" does "Allows Sonic to rotate whilst airborne during a Drop Dash." // #lib "DeltaTime" #lib "Memory" #lib "Player" #lib "VectorHelpers" #import "GOComponents" #load "System.Numerics.dll" using System.Numerics; const float _airForce = 10.0f; const float _airAccel = 100.0f; const float _turnSpeed = 3.0f; static float _lastGroundedMagnitude = 0.0f; // { if (Player.State.GetCurrentStateID() != Sonic.StateID.StateDropDash) return; if (Player.Status.IsSideView()) return; if (Player.Status.IsGrounded()) { _lastGroundedMagnitude = Player.Kinematics.GetHorizontalMagnitude(); return; } if (!Memory.TryGetPointer(Player.Kinematics.Get(), out var out_pKinematics)) return; var worldInput = out_pKinematics->WorldInput; if (worldInput.Length() <= 0.0f) return; var dt = DeltaTime.GetDeltaTime(); var forward = VectorHelpers.GetForward(out_pKinematics->Rotation); // Rotation { var worldInputAngle = VectorHelpers.SignedAngle(forward, Vector3.Normalize(worldInput), Vector3.UnitY); var rotation = (float)Math.Min(Math.Abs(worldInputAngle), _turnSpeed * dt); // Apply rotation in stick direction. rotation *= (float)Math.Sign(worldInputAngle); var rotationDelta = Quaternion.CreateFromAxisAngle(Vector3.UnitY, rotation); out_pKinematics->Rotation = Quaternion.Normalize(Quaternion.Concatenate(out_pKinematics->Rotation, rotationDelta)); } // Velocity { var forwardVelocity = forward * _airAccel; var nrmVelocity = Vector3.Normalize(out_pKinematics->Velocity); if (_lastGroundedMagnitude < Player.Kinematics.GetHorizontalMagnitude()) forwardVelocity = forward * nrmVelocity * dt; var force = (forwardVelocity - out_pKinematics->Velocity) * _airForce * dt; out_pKinematics->Velocity.X += force.X; out_pKinematics->Velocity.Z += force.Z; // Decelerate over time. out_pKinematics->Velocity -= nrmVelocity * Player.Kinematics.GetHorizontalMagnitude() * dt; } } Patch "Force 3D Open Zone Physics (experimental)" in "Physics/Cyber Space" by "NM" does /* Forces the game to use the 3D open zone physics in Cyber Space. Known issues; - Entering a Rocket Boost will cause the player to lose gravity. - Certain auto-run sections (e.g. loops) may cause the player to fling off of terrain. */ // #include "Helpers" noemit #import "GOComponents" // { /* 0x1408B2E14 `app::player::GOCPlayerParameter::GetPlayerParameter` */ long address = ScanSignature("\x48\x63\x83\xB8\x00\x00\x00", "xxxxxxx"); // TODO: Switch to direct RflClass comparison once code library implementation is made string instructions = @$" movsxd rax, dword ptr [rbx + 0xB8] lea r8, [rbp - 40h] mov r9, rsi cmp rax, {(int)(GOCPlayerParameter.ModePackageType.CyberSpace)} jnz End CyberSpaceModePackage: push rbx push rcx push rdx push rsi mov rbx, 0 ; RDX points to an `app::rfl::RflClass` ; The beginning offset of this class is a pointer to the class name; we'll want to compare that against PlayerParamCyberMode ; If both strings match, we'll want to prefer the Cyber Space ForwardView; the open zone ForwardView doesn't have the parameters ; set correctly mov rdx, [rdx] NameComparison: movsx rcx, byte ptr [rbx + rdx] movsx rsi, byte ptr [rbx + {TO_STRING_PTR("PlayerParamCyberMode")}] cmp rcx, rsi jnz MatchFailed inc rbx ; 14h = End of PlayerParamCyberMode cmp rbx, 14h jnz NameComparison jmp MatchSuccess MatchFailed: ; Since we're not dealing with Cyber Space-specific parameters, force the ForwardView ModePackage mov rax, {(int)(GOCPlayerParameter.ModePackageType.ForwardView)} MatchSuccess: ; Keep the ModePackageType (rax) the same, effectively making it pull from the Cyber Space parameters Cleanup: pop rsi pop rdx pop rcx pop rbx End: "; WriteAsmHook(instructions, address, HookBehavior.Replace); } Code "Tighter Spin Dash Rotation" in "Physics/Cyber Space" by "Hyper" // #include "Reflection" noemit #lib "GameMode" #lib "Reflection" #lib "SonicParameters" // { if (!GameMode.GetName().Contains("CyberStage")) return; var SonicParametersInfo = Reflection.GetDataInfo("player_common"); if (SonicParametersInfo.pData == null) return; RFL_SET_PARAM(SonicParametersInfo, cyberspace.spinBoost.speedBoost.baseRotateForce, 2250.0f); } Patch "Allow Party Details in Another Story" by "RagdollClash" in "Graphics/Objects/Open Zone" // #lib "Memory" // { /* 0x140134040 */ long funcAddr = Memory.ReadCall ( ScanSignature ( "\xE8\x00\x00\x00\x00\x31\xDB\x48\x89\xEE", "x????xxxxx" ) ); /* 0x140134092 */ Memory.WriteForceJump(funcAddr + 0x52); /* 0x1401340E6 */ Memory.WriteForceJump(funcAddr + 0xA6); } Patch "Hide Challenge Markers" in "Graphics/Objects/Open Zone" by "Hyper" does "Hides the markers that appear next to challenges on the islands." { // Hide map sensor visual. WriteProtected ( /* 0x1403BF63B */ ScanSignature ( "\x74\x17\x48\x8D\x55\xD7\x48\x8B\xC8\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD3\x48\x8B\xCF\xE8\xCC\xCC\xCC\xCC\x48\x8B\x8F\x58\x02\x00\x00", "xxxxxxxxxx????xxxxxxx????xxxxxxx" ), 0xEB ); // Hide map sensor prerequisite marker. WriteProtected ( /* 0x1403BF6B3 */ ScanSignature ( "\x0F\x85\xE5\x00\x00\x00\xE8", "xxxxxxx" ), 0xE9, 0xE6, 0x00, 0x00, 0x00 ); // Hide map sensor name. WriteProtected ( /* 0x1408D128F */ ScanSignature ( "\x0F\x8E\x47\x02\x00\x00\x4C\x89\xA4\x24\x58\x01\x00\x00", "xxxxxxxxxxxxxx" ), 0xE9, 0x48, 0x02, 0x00, 0x00 ); } Code "Force Cyber Space Object Design" in "Graphics/Objects/Open Zone" by "Hyper" does /* Replaces all supported objects on the islands with their Cyber Space designs. Unsupported objects; - Jump Selectors (Generations-style) */ // #lib "Bitwise" #lib "BlackboardStatus" #lib "GameMode" #lib "Resources" using System.Collections.Generic; private static List _objects = new() { "cmnisl_obj_balloonB", "cmnisl_obj_balloonG", "cmnisl_obj_balloonR", "cmnisl_obj_balloonY", "cmnisl_obj_dashpanel", "cmnisl_obj_dashpanel_arrow", "cmnisl_obj_dashpanel_belt", "cmnisl_obj_dashring", "cmnisl_obj_dashring_body", "cmnisl_obj_dashroller", "cmnisl_obj_dashroller_GR", "cmnisl_obj_dashroller_SV", "cmnisl_obj_fan_fly", "cmnisl_obj_fan_ground", "cmnisl_obj_fan_top", "cmnisl_obj_grindbooster", "cmnisl_obj_grindbooster_arrow", "cmnisl_obj_grindbooster_arrow_stop", "cmnisl_obj_grindbooster_light_stop", "cmnisl_obj_jumppanel_arrow", "cmnisl_obj_jumppanel_belt", "cmnisl_obj_jumppanel30L", "cmnisl_obj_jumppanel30M", "cmnisl_obj_jumppanel30S", "cmnisl_obj_jumpselector", "cmnisl_obj_jumpselector@correct", "cmnisl_obj_jumpselector@miss", "cmnisl_obj_jumpselector_arrow", "cmnisl_obj_jumpselector_gauge_correct", "cmnisl_obj_jumpselector_gauge_in", "cmnisl_obj_jumpselector_gauge_miss", "cmnisl_obj_laserfence", "cmnisl_obj_pole_fvA", "cmnisl_obj_pole_fvB", "cmnisl_obj_pole_guide", "cmnisl_obj_pole_guide_meter", "cmnisl_obj_pole_guide_meterB", "cmnisl_obj_pole_svA", "cmnisl_obj_pole_svB", "cmnisl_obj_pole_svC", "cmnisl_obj_pole_svD", "cmnisl_obj_propellerspring_body_limit", "cmnisl_obj_propellerspring_bottom", "cmnisl_obj_propellerspring_top", "cmnisl_obj_pulley", "cmnisl_obj_pulleystandA", "cmnisl_obj_pulleystandB", "cmnisl_obj_pulleystandC", "cmnisl_obj_rainbowring", "cmnisl_obj_rainbowring_body", "cmnisl_obj_spring", "cmnisl_obj_springair_bottom", "cmnisl_obj_springair_top", "cmnisl_obj_springC", "cmnisl_obj_springC_red", "cmnisl_obj_springC_yellow", "cmnisl_obj_springegg", "cmnisl_obj_springpole", "cmnisl_obj_springpole_L", "cmnisl_obj_springpole_M", "cmnisl_obj_springpole_S", "cmnisl_obj_upreel_handle", "cmnisl_obj_upreel_stand", "cmnisl_obj_upreel_wire", "cmnisl_obj_walljumpblock01", "cmnisl_obj_walljumpblock02", "cmnisl_obj_walljumpblock03", "cmnisl_obj_widespring", "cmnisl_obj_wjblock_arrow" }; // { string NotifyRedirectIslandObjects(string resourceName, string resourceType) { switch (resourceType) { case "ResEffect": { if (resourceName == "ef_ob_dashring02") return "ef_ob_dashring01"; break; } case "ResModel": case "ResSkeleton": { if (resourceName == "cmnisl_obj_switchusual") return "cmn_obj_switch"; break; } case "ResAnimation": { if (resourceName == "cmnisl_obj_switchusual_on") return "cmn_obj_switch_on"; break; } case "ResPhysicsMesh": { switch (resourceName) { case "cmnisl_obj_jumppanel30S": return "cmn_obj_jumppanel30S_col"; case "cmnisl_obj_jumppanel30M": return "cmn_obj_jumppanel30M_col"; case "cmnisl_obj_jumppanel30L": return "cmn_obj_jumppanel30L_col"; case "col_cmnisl_obj_switchusual": return "col_cmn_obj_switch"; } break; } case "ResAnimTexSrt": { if (resourceName == "cmnisl_obj_switchusual03_on") return "cmn_obj_switch03_on"; break; } case "ResAnimMaterial": { if (resourceName == "cmnisl_obj_switchusual03") return "cmn_obj_switch03"; break; } } if (_objects.Contains(resourceName)) return resourceName.Replace("cmnisl_obj_", "cmn_obj_"); return resourceName; } if (GameMode.GetName() == "GameModeStage" || GameMode.GetTutorialDestination() == GameMode.DestinationMode.GameModeStage) { Resources.AddResourceNotifyAction(NotifyRedirectIslandObjects); } else { Resources.RemoveResourceNotifyAction(NotifyRedirectIslandObjects); } } Code "Force Open Zone Object Design" in "Graphics/Objects/Cyber Space" by "Hyper" does /* Replaces all supported objects in Cyber Space with their open zone designs. Unsupported objects; - Checkpoints - Up-reel Carriers */ // #lib "Bitwise" #lib "BlackboardStatus" #lib "GameMode" #lib "Resources" using System.Collections.Generic; private static List _objects = new() { "cmn_obj_balloonB", "cmn_obj_balloonG", "cmn_obj_balloonR", "cmn_obj_balloonY", "cmn_obj_dashpanel", "cmn_obj_dashpanel_arrow", "cmn_obj_dashpanel_belt", "cmn_obj_dashring", "cmn_obj_dashring_body", "cmn_obj_dashroller", "cmn_obj_dashroller_GR", "cmn_obj_dashroller_SV", "cmn_obj_fan_fly", "cmn_obj_fan_ground", "cmn_obj_fan_top", "cmn_obj_grindbooster", "cmn_obj_grindbooster_arrow", "cmn_obj_grindbooster_arrow_stop", "cmn_obj_grindbooster_light_stop", "cmn_obj_jumppanel_arrow", "cmn_obj_jumppanel_belt", "cmn_obj_jumppanel30L", "cmn_obj_jumppanel30M", "cmn_obj_jumppanel30S", "cmn_obj_jumpselector", "cmn_obj_jumpselector@correct", "cmn_obj_jumpselector@miss", "cmn_obj_jumpselector_arrow", "cmn_obj_jumpselector_gauge_correct", "cmn_obj_jumpselector_gauge_in", "cmn_obj_jumpselector_gauge_miss", "cmn_obj_laserfence", "cmn_obj_pole_fvA", "cmn_obj_pole_fvB", "cmn_obj_pole_guide", "cmn_obj_pole_guide_meter", "cmn_obj_pole_guide_meterB", "cmn_obj_pole_svA", "cmn_obj_pole_svB", "cmn_obj_pole_svC", "cmn_obj_pole_svD", "cmn_obj_propellerspring_body_limit", "cmn_obj_propellerspring_bottom", "cmn_obj_propellerspring_top", "cmn_obj_pulley", "cmn_obj_pulleystandA", "cmn_obj_pulleystandB", "cmn_obj_pulleystandC", "cmn_obj_rainbowring", "cmn_obj_rainbowring_body", "cmn_obj_spring", "cmn_obj_springair_bottom", "cmn_obj_springair_top", "cmn_obj_springC", "cmn_obj_springC_red", "cmn_obj_springC_yellow", "cmn_obj_springegg", "cmn_obj_springpole", "cmn_obj_springpole_L", "cmn_obj_springpole_M", "cmn_obj_springpole_S", "cmn_obj_upreel_handle", "cmn_obj_upreel_stand", "cmn_obj_upreel_wire", "cmn_obj_walljumpblock01", "cmn_obj_walljumpblock02", "cmn_obj_walljumpblock03", "cmn_obj_widespring", "cmn_obj_wjblock_arrow" }; // { string NotifyRedirectCyberSpaceObjects(string resourceName, string resourceType) { switch (resourceType) { case "ResEffect": { if (resourceName == "ef_ob_dashring01") return "ef_ob_dashring02"; break; } case "ResModel": case "ResSkeleton": { if (resourceName == "cmn_obj_switch") return "cmnisl_obj_switchusual"; break; } case "ResAnimation": { if (resourceName == "cmn_obj_switch_on") return "cmnisl_obj_switchusual_on"; break; } case "ResPhysicsMesh": { switch (resourceName) { case "cmn_obj_jumppanel30S_col": return "cmnisl_obj_jumppanel30S"; case "cmn_obj_jumppanel30M_col": return "cmnisl_obj_jumppanel30M"; case "cmn_obj_jumppanel30L_col": return "cmnisl_obj_jumppanel30L"; case "col_cmn_obj_switch": return "col_cmnisl_obj_switchusual"; } break; } case "ResAnimTexSrt": { if (resourceName == "cmn_obj_switch03_on") return "cmnisl_obj_switchusual03_on"; break; } case "ResAnimMaterial": { if (resourceName == "cmn_obj_switch03") return "cmnisl_obj_switchusual03"; break; } } if (_objects.Contains(resourceName)) return resourceName.Replace("cmn_obj_", "cmnisl_obj_"); return resourceName; } if (GameMode.GetName() == "GameModeCyberStage" || GameMode.GetTutorialDestination() == GameMode.DestinationMode.GameModeCyberStage) { Resources.AddResourceNotifyAction(NotifyRedirectCyberSpaceObjects); } else { Resources.RemoveResourceNotifyAction(NotifyRedirectCyberSpaceObjects); } } Patch "Hide Drift Dash Panels" in "Graphics/Objects/Cyber Space" by "Hyper" does "Hides the drift dash panels, but still allows them to function, similarly to drift zones in Sonic Colours." { // Remove model. WriteNop ( /* 0x140432970 */ ScanSignature ( "\x48\x89\x47\x38\x48\x8D\x1D\x00\x00\x00\x00", "xxxxxxx????" ), 4 ); // Remove sound. WriteNop ( /* 0x140432AEC */ ScanSignature ( "\xE8\x00\x00\x00\x00\x48\x8D\x4C\x24\x00\xE8\x00\x00\x00\x00\xB0\x01\x48\x81\xC4\x00\x00\x00\x00\x5E", "x????xxxx?x????xxxxx????x" ), 5 ); } Patch "Disable Idle Kocos" in "Gameplay/Open Zone/Objects" by "Hyper" does "Disables the Kocos appearing in front of Sonic when idle." { WriteNop ( /* 0x1406B8199 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\x5C\x24\x50\x48\x8B\x6C\x24\x68", "x????xxxxxxxxxx" ), 5 ); } Patch "Disable Traversal Objects in Chests" in "Gameplay/Open Zone/Objects" by "Hyper" does /* Disables the hidden traversal objects in chests that require cyloop to reveal, making them always accessible. Affected objects; - Dash Panels - Jump Boards - Springs */ // #lib "Memory" // { // Dash Panels WriteAsmHook ( "mov byte ptr [r14 + 0xB8], 0", /* v1.41: 0x1403D3823 */ ScanSignature ( "\x0F\x28\xD3\x0F\x59\xD3\x0F\x28\xCA\x0F\xC6\xCA\x99\xF3\x0F\x58\xD1\x0F\x28\xC1\x0F\xC6\xC1\x55\xF3\x0F\x58\xD0\x0F\x57\xC0\x0F\xC6\xD2\x00\x0F\x51\xCA\x0F\xC2\x15\xCC\xCC\xCC\xCC\xCC\x0F\x5E\xD9\x0F\xC2\xC8\x04\x0F\x54\xD9\xF3\x0F\x10\x0D\xCC\xCC\xCC\xCC\x0F\x54\xDA\x0F\x55\x15\xCC\xCC\xCC\xCC\x0F\x56\xDA\x0F\x29\x9D\xE0\x00\x00\x00", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx?????xxxxxxxxxxxxxx????xxxxxx????xxxxxxxxxx" ), HookBehavior.After ); // Jump Boards { /* v1.41: 0x140426C03 */ long instrAddr = ScanSignature ( "\x80\xB8\xB8\x00\x00\x00\x00\x74\x12", "xxxxxxxxx" ); WriteProtected(instrAddr, Assemble("mov byte ptr [rax + 0xB8], 0")); /* 0x140425B7A */ Memory.WriteForceJump(instrAddr + 0x07); } // Springs WriteNop ( /* v1.41: 0x1404A1BA7 */ ScanSignature ( "\x41\x0F\xB7\xC1\x66\x23\xC1\x66\x41\x83\xC9\x08", "xxxxxxxxxxxx" ), 4 ); } Patch "Always Trickable Dash Rings" in "Gameplay/Open Zone/Objects" by "Hyper" { WriteProtected ( /* 0x148CA72A7 */ ScanSignature ( "\x0F\x44\xC8\x88\x8F\xD0\x02\x00\x00", "xxxxxxxxx" ), Assemble("mov cl, 2\n nop") ); } Patch "Always Trickable Springs" in "Gameplay/Open Zone/Objects" by "Hyper" { WriteNop ( /* 0x1404A0B76 */ ScanSignature ( "\x66\x44\x0F\x44\xC8\x66\x44\x89\x8B\x00\x03\x00\x00\x41\x0F\xB7\xC1\x66\x23\xC1\x66\x41\x83\xC9\x20", "xxxxxxxxxxxxxxxxxxxxxxxxx" ), 5 ); } Patch "Disable Challenge Rails" in "Gameplay/Open Zone/Objects" by "Hyper" does /* Disables the white rails that appear after completing challenges. Your progress will still be saved, so disabling this code after completing challenges will still unlock their respective rails. */ { WriteAsmHook ( @" add rsp, 0x40 pop rdi ret ", /* 0x148E533EF */ ScanSignature ( "\x48\x89\xD3\x48\x89\xCF\xE8\xCC\xCC\xCC\xCC\x48\x89\xC2\x48\x89\xF9\xE8\xCC\xCC\xCC\xCC\x48\x89\xDA", "xxxxxxx????xxxxxxx????xxx" ), HookBehavior.Replace ); /* 0x14033E730 */ long addr = ScanSignature ( "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x60\x8B\xDA\x48", "xxxxxxxxxxxxx" ); if (addr != 0) WriteNop(addr + 0x5F, 5); } Patch "Always Trickable Jump Boards" in "Gameplay/Open Zone/Objects" by "Hyper" { WriteProtected ( /* 0x1403C8CFA */ ScanSignature ( "\x0F\x95\xC1\x88\x8F\x90\x02\x00\x00\x80\xB8\xB8\x00\x00\x00\x00", "xxxxxxxxxxxxxxxx" ), Assemble("mov cl, 1\n nop") ); } Patch "Disable Jump Board Paths" in "Gameplay/Open Zone/Objects" by "Hyper" does "Stops the player locking to a path when hitting jump boards on the islands, allowing him to fling off them like ramps." // #lib "Bridge.DisableJumpBoardPaths" // { Bridge.DisableJumpBoardPaths.IsDisabledOnIslands = true; } Code "Drop Dash on Slide" in "Gameplay/Skills/Sonic" by "Hyper" // #include "BlackboardStatus" noemit #lib "Globals" #lib "Player" // { if (Player.GetPlayerType() != Player.PlayerType.Sonic) return; if (Player.State.GetCurrentStateID() == Sonic.StateID.StateSliding) Player.State.SetState(Sonic.StateID.StateDropDash); // Ensure the state transition fixes don't conflict with the other code. if (Globals.GetFlag("Fix Drop Dash Transitions")) return; var state = Player.State.GetCurrentStateID(); var isGrounded = Player.Status.IsGrounded(); if (state == Sonic.StateID.StateDropDash) { if (Player.Input.IsPressed(Player.InputActionType.PlayerBoost)) Player.State.SetState(isGrounded ? Sonic.StateID.StateRun : Sonic.StateID.StateAirBoost); if (Player.Input.IsPressed(Player.InputActionType.PlayerStomping)) Player.State.SetState(isGrounded ? Sonic.StateID.StateRun : Sonic.StateID.StateStompingDown); if (Player.Input.IsPressed(Player.InputActionType.PlayerJump) && !isGrounded) Player.State.SetState(Sonic.StateID.StateDoubleJump); if (Player.Input.IsPressed(Player.InputActionType.PlayerSonicboom)) Player.State.SetState(Sonic.StateID.StateSpinBoostCharge); } else if (state == Sonic.StateID.StateRun) { if (Player.Input.IsDown(Player.InputActionType.PlayerBoost) && isGrounded) { if (Player.State.GetPreviousStateID() == Sonic.StateID.StateDropDash) SET_STATE_FLAG(IsBoost, true); } } } Code "Always Have Perfect Parry" by "ĐeäTh" in "Gameplay/Skills/Sonic" does "Enables the perfect parry at all times for Sonic." // #include "BlackboardStatus" noemit // { if (!IS_COMBAT_FLAG(IsPerfectParry)) SET_COMBAT_FLAG(IsPerfectParry, true) } Code "Allow Cyclone Kick for Traversal" in "Gameplay/Skills/Sonic" by "WasifBoomz" does "Allows Sonic to use the Cyclone Kick for traversal by pressing the attack button while holding the jump button." // #lib "Player" static bool allowChargeAttack = false; // { if (Player.GetPlayerType() != Player.PlayerType.Sonic) return; if (Player.Status.IsGroundedSpecial()) allowChargeAttack = true; if (Player.State.GetCurrentStateID() == Sonic.StateID.StateAcceleCombo1 && Player.Input.IsDown(Player.InputActionType.PlayerJump) && !Player.Status.IsGroundedSpecial() && allowChargeAttack) { Player.State.SetState(Sonic.StateID.StateChargeAttack); allowChargeAttack = false; } } Patch "Disable Spin Slash on Drop Dash" in "Gameplay/Skills/Sonic" by "Hyper" // #lib "Memory" // { Memory.WriteForceJump ( /* v1.41: 0x14BD2B2DF */ ScanSignature ( "\x74\x79\xBA\x31\x00\x00\x00", "xxxxxxx" ) ); } Code "Allow Dodging from Homing Shot" in "Gameplay/Skills/Sonic" by "Hyper" does "Allows Sonic to exit from Homing Shot by dodging." // #lib "Player" #lib "VectorHelpers" #import "States" // { if (Player.GetPlayerType() != Player.PlayerType.Sonic) return; if (Player.State.GetCurrentStateID() == Sonic.StateID.StateHomingShot) { if (Player.Input.IsPressed(Player.InputActionType.PlayerLeftStep) || Player.Input.IsPressed(Player.InputActionType.PlayerRightStep)) { var dir = VectorHelpers.LookRotation(-Player.Kinematics.GetForward()); Player.State.SetState(Sonic.StateID.StateAvoid, new StateAvoidParameter(dir)); } } } Patch "Disable Drop Dash" in "Gameplay/Skills/Sonic" by "Hyper" // #lib "Memory" // { // Disable drop dash charge from StateDoubleJump. Memory.WriteForceJump ( /* v1.41: 0x14B7B7FAF */ ScanSignature ( "\x0F\x84\x9B\x00\x00\x00\x48\x89\xF9", "xxxxxxxxx" ) ); // Disable drop dash from StateDoubleJump. WriteProtected ( /* 0x14B4C1A03 */ ScanSignature ( "\x74\x14\xF3\x0F\x10\x8F\xB4\x00\x00\x00", "xxxxxxxxxx" ), 0xEB ); // Disable drop dash charge from StateRecoveryJump. WriteProtected ( /* 0x1408A0A37 */ ScanSignature ( "\x0F\x84\xB7\x00\x00\x00\x80\xBE\xC4\x00\x00\x00\x00", "xxxxxxxxxxxxx" ), 0xE9, 0xB8, 0x00, 0x00, 0x00 ); } Patch "Disable Power Boost" in "Gameplay/Skills/Sonic" by "Hyper" { WriteProtected ( /* v1.41: 0x1409968F7 */ ScanSignature ( "\xB0\x01\xF3\x0F\x10\x47\x60", "xxxxxxx" ), Assemble("xor al, al") ); } Patch "Drop Dash on Double Jump" in "Gameplay/Skills/Sonic" by "Hyper" does "Allows you to drop dash immediately after double jumping, making it require only two presses." { /* v1.42: 0x14B65598C */ var sig = ScanSignature ( "\x74\x3D\x48\x89\xF9", "xxxxx" ); WriteNop(sig, 2); WriteProtected(sig + 0x0F, 0xEB); } Code "Air Trick from Rails" in "Gameplay/Skills/Sonic" by "Hyper" does /* Allows Sonic to perform Air Tricks when jumping off of grind rails. Notes; - Holding the jump button whilst jumping off of a grind rail will keep you in the usual grind jump state until released. - Releasing the jump button will give you a small frame window where you can perform a double jump. - Flinging off of a grind rail will automatically begin tricking. */ // #lib "DeltaTime" #lib "Player" static bool _isReleaseAirTricks = false; static float _airTricksReleaseTimer = 0.0f; static float _airTricksReleaseTimerThreshold = 0.2f; static void ResetMembers() { _isReleaseAirTricks = false; _airTricksReleaseTimer = 0.0f; } // { if (Player.GetPlayerType() != Player.PlayerType.Sonic) return; if (Player.State.GetCurrentStateID() == Sonic.StateID.StateFall && Player.State.GetPreviousStateID() == Sonic.StateID.StateGrind) { // Enter into StateBumpJump when flinging off of grind rails. Player.State.SetState(Sonic.StateID.StateBumpJump); } if (Player.State.GetCurrentStateID() == Sonic.StateID.StateGrindJump) { if (Player.Input.IsReleased(Player.InputActionType.PlayerJump)) _isReleaseAirTricks = true; if (_isReleaseAirTricks) _airTricksReleaseTimer += DeltaTime.GetDeltaTime(); // Provide small frame window to allow for StateGrindDoubleJump. if (_airTricksReleaseTimer > _airTricksReleaseTimerThreshold) { Player.State.SetState(Sonic.StateID.StateBumpJump); ResetMembers(); } } else { ResetMembers(); } } Code "Disable Sonic Boom for Regular Objects" in "Gameplay/Skills/Sonic" by "Hyper" does "Disables the Sonic Boom skill when Sonic is targeting anything but enemies, allowing him to freely charge a Spin Dash around targetable objects." // #lib "GameObject" #lib "Player" // { if (Player.GetPlayerType() != Player.PlayerType.Sonic) return; var pGameObject = Player.Status.GetLockOnTarget(); if (pGameObject == null) return; // Target is an enemy if it has the GOCHealth component. if (GameObject.GetGOC(pGameObject, "GOCHealth") != null) { Player.State.Restore(Sonic.StateID.StateSonicBoomKick); } else { Player.State.Redirect(Sonic.StateID.StateSonicBoomKick, Sonic.StateID.StateSpinBoostCharge); } } Patch "Disable Loop Kick on Slide" in "Gameplay/Skills/Sonic" by "Hyper" { WriteNop ( /* 0x1409678C0 */ ScanSignature ( "\xE8\xCC\xCC\xCC\xCC\x48\x8B\xCF\xBB\x1C\x00\x00\x00", "x????xxxxxxxx" ), 5 ); } Code "Increase Flight Altitude on A Hold" in "Gameplay/Skills/Tails" by "Hyper" does "Allows Tails to fly upwards when holding down the A button." // #lib "Player" #import "States" // { if (Player.GetPlayerType() != Player.PlayerType.Tails) return; var kinematics = Player.Kinematics.Get(); if (kinematics == null) return; var pStateTailsFly = Player.State.GetState(); if (pStateTailsFly == null) return; if (pStateTailsFly->Phase == StateTailsFly.PhaseType.Tired) return; if (Player.Input.IsDown(Player.InputActionType.PlayerJump)) kinematics->Position.Y += 0.12f; } Code "Enable Dodge and Parry" in "Gameplay/Cyber Space/Skills" by "Hyper" does "Enables dodging and parrying in Cyber Space for potentially recovering from a fall." // #include "BlackboardStatus" noemit #lib "HMM" #lib "Player" #lib "Time" #import "States" static bool _isInitialised = false; static bool _isDodgeAlways = false; static bool _isDodgeAnalog = false; static bool _isInputBuffered = false; static bool _isParried = false; static float _dodgeTimer = 0.0f; static float _dodgeTimerThreshold = 0.08f; static void PerformBumperActions(bool in_isRight = false) { var state = Sonic.StateID.StateAvoid; if (Player.Status.IsSpecialAction()) { _dodgeTimer = 0.0f; _isInputBuffered = false; _isParried = false; return; } if (Player.Status.IsGrounded()) { if (!_isDodgeAlways) return; // Prevent dodge spam on input hold. if (Player.State.GetCurrentStateID() == Sonic.StateID.StateAvoid) return; if (Player.Kinematics.GetHorizontalMagnitude() >= 15.0f) { state = in_isRight ? Sonic.StateID.StateRightStepRun : Sonic.StateID.StateLeftStepRun; if (IS_STATE_FLAG(IsIdle)) state = in_isRight ? Sonic.StateID.StateRightStep : Sonic.StateID.StateLeftStep; } } if (Player.Input.IsDown(Player.InputActionType.PlayerLeftStep) && Player.Input.IsDown(Player.InputActionType.PlayerRightStep)) { if (!_isInputBuffered) { Player.State.SetState(Sonic.StateID.StateParry); _isInputBuffered = true; _isParried = true; } return; } else if (Player.State.GetCurrentStateID() != Sonic.StateID.StateParry) { _isInputBuffered = false; } // Prevent air dodging immediately after air parrying. if (_isParried && (Player.Input.IsDown(Player.InputActionType.PlayerLeftStep) || Player.Input.IsDown(Player.InputActionType.PlayerRightStep))) { return; } else { _isParried = false; } if (Player.Input.IsDown(in_isRight ? Player.InputActionType.PlayerRightStep : Player.InputActionType.PlayerLeftStep)) { _dodgeTimer += Time.GetDeltaTime(); if (_dodgeTimer >= _dodgeTimerThreshold) { if (!_isDodgeAnalog) { var dir = StateAvoidParameter.GetDirectionRelativeToCameraPlane(in_isRight); Player.State.AddStateParameter(new StateAvoidParameter(dir)); } Player.State.SetState(state); _dodgeTimer = 0.0f; } } } // { if (!_isInitialised) { _isDodgeAlways = HMM.GetCodes().Contains("Gameplay/Skills/Always Dodge with Side Step"); _isDodgeAnalog = HMM.GetCodes().Contains("Gameplay/Skills/Always Dodge in Stick Direction"); _isInitialised = true; } if (!IS_WORLD_FLAG(IsCyberSpace)) return; SET_COMBAT_FLAG(IsParry, true); if (Player.State.GetCurrentStateID() == Sonic.StateID.StateGrindStep) return; PerformBumperActions(); PerformBumperActions(true); } Code "Enable Air Tricks from Terrain" in "Gameplay/Cyber Space/Skills" by "Hyper" does /* Enables air tricks only when flinging off terrain in Cyber Space. Notes; - This code requires 'Enable Terrain Flinging' to work. */ // #include "BlackboardStatus" noemit #lib "Player" // { if (!IS_WORLD_FLAG(IsCyberSpace)) return; if (!Player.Status.IsGrounded() && Player.State.GetCurrentStateID() == Sonic.StateID.StateBumpJump) SET_WORLD_FLAG(IsAirTrick, true); } Patch "Disable Drift Dash Panels" in "Gameplay/Cyber Space/Objects" by "Hyper" { WriteProtected ( /* 0x140482A6E */ ScanSignature ( "\x48\x8B\xC2\x48\x8B\xF9\x48\x8B\xC8\x48\x8D\x15\xCC\xCC\xCC\xCC\xE8\xCC\xCC\xCC\xCC\x4C\x8B\xF8\xE8\xCC\xCC\xCC\xCC\x48\x8B\xD0\x48\x8B\xCF\xE8\xCC\xCC\xCC\xCC\x4C\x8B\xE8", "xxxxxxxxxxxx????x????xxxx????xxxxxxx????xxx" ), 0xE9, 0x24, 0x03, 0x00, 0x00 ); } Code "Always Trickable Dash Rings" in "Gameplay/Cyber Space/Objects" by "Hyper" // #include "BlackboardStatus" noemit #import "Plugins" #import "Services" #import "States" static bool _isJumpBoard = false; // { if (!IS_WORLD_FLAG(IsCyberSpace)) return; var pStatePluginAirTrick = Player.State.GetStatePlugin(); if (pStatePluginAirTrick == null) return; var pStateSpringJumpParameter = Player.State.GetStateParameter(); if (pStateSpringJumpParameter == null) return; // Workaround for Jump Boards in Cyber Space 4-5. if (LevelInfo.GetCurrentStageID() == "w6d10") { if (Player.State.GetCurrentStateID() == Sonic.StateID.StateJumpBoardLaunch) { _isJumpBoard = true; return; } if (Player.State.GetCurrentStateID() == Sonic.StateID.StateSpringJump && _isJumpBoard) { _isJumpBoard = false; return; } } if (((pStateSpringJumpParameter->Flags & 0x20) != 0) || ((pStateSpringJumpParameter->Flags & 0x40) != 0)) pStatePluginAirTrick->IsEnabled = true; } Code "Always Trickable Springs" in "Gameplay/Cyber Space/Objects" by "Hyper" // #include "BlackboardStatus" noemit #import "Plugins" #import "Services" #import "States" // { if (!IS_WORLD_FLAG(IsCyberSpace)) return; var pStatePluginAirTrick = Player.State.GetStatePlugin(); if (pStatePluginAirTrick == null) return; var pStateSpringJumpParameter = Player.State.GetStateParameter(); if (pStateSpringJumpParameter == null) return; if ((pStateSpringJumpParameter->Flags & 4) != 0) pStatePluginAirTrick->IsEnabled = true; } Code "Always Trickable Jump Boards" in "Gameplay/Cyber Space/Objects" by "Hyper" // #include "BlackboardStatus" noemit #lib "Player" #import "Services" // { if (!IS_WORLD_FLAG(IsCyberSpace)) return; if (Player.State.GetCurrentStateID() == Sonic.StateID.StateJumpBoardLaunch) SET_WORLD_FLAG(IsAirTrick, true); // Workaround for Jump Boards in Cyber Space 4-5. if (LevelInfo.GetCurrentStageID() == "w6d10") { // https://cdn.discordapp.com/attachments/1102872412648914947/1165261324515823666/927698306430304267.png if ((Player.State.GetCurrentStateID() == Sonic.StateID.StateSpringJump && Player.State.GetPreviousStateID() == Sonic.StateID.StateJumpBoardLaunch) || (Player.State.GetPreviousStateID() == Sonic.StateID.StateSpringJump && Player.State.GetPreviousStateID(1) == Sonic.StateID.StateJumpBoardLaunch)) { SET_WORLD_FLAG(IsAirTrick, true); } } } Patch "Disable Jump Board Paths" in "Gameplay/Cyber Space/Objects" by "Hyper" does "Stops the player locking to a path when hitting jump boards in Cyber Space, allowing him to fling off them like ramps." // #lib "Bridge.DisableJumpBoardPaths" // { Bridge.DisableJumpBoardPaths.IsDisabledInCyberSpace = true; } Patch "Swing Reels Only Swing Once" in "Gameplay/Cyber Space/Objects" by "Hyper" does "This changes all swing reels to require only one swing for the player to launch off of it, rather than two." // static float _swingTime = 47.5f; static float _swingVelocityMul = 1.35f; // { fixed (float* p_swingTime = &_swingTime) { WriteAsmHook ( $@" mov rcx, {(long)p_swingTime} movss xmm2, dword ptr [rcx] movss dword ptr [rbx + 0x27C], xmm0 comiss xmm0, xmm2 mov rbp, qword ptr [rsp + 0x50] ", /* 0x140522449 */ ScanSignature ( "\xF3\x0F\x11\x83\x7C\x02\x00\x00\x0F\x2F\x45\x64", "xxxxxxxxxxxx" ), HookBehavior.Replace ); } fixed (float* p_swingVelocityMul = &_swingVelocityMul) { WriteAsmHook ( $@" mov r9, {(long)p_swingVelocityMul} movss xmm0, dword ptr [r9] mulss xmm6, xmm0 lea r9, qword ptr [rsp + 0x58] mov dword ptr [rsp + 0x80], 0 ", /* 0x1405211EA */ ScanSignature ( "\x4C\x8D\x4C\x24\x58\xC7\x84\x24\x80\x00\x00\x00\x00\x00\x00\x00", "xxxxxxxxxxxxxxxx" ), HookBehavior.Replace ); } } Code "Fix Recovery Jump Transitions" in "Fixes/Gameplay/States" by "Hyper" does /* Fixes state transitions for the recovery jump state. Notes; - This allows Knuckles to glide after performing a recovery jump whilst holding A. - This allows Tails to fly after performing a recovery jump whilst holding A. */ // #lib "DeltaTime" #lib "Globals" #lib "Player" static bool _isInitialised = false; static float _recoveryJumpTimer = 0.0f; // { if (!_isInitialised) { Globals.Add("Fix Recovery Jump Transitions", true); _isInitialised = true; } if (!Globals.GetFlag("Fix Recovery Jump Transitions")) return; switch (Player.GetPlayerType()) { case Player.PlayerType.Knuckles: { // Fix Knuckles being unable to glide out of StateRecoveryJump. if (Player.State.GetCurrentStateID() == Knuckles.StateID.StateRecoveryJump) { _recoveryJumpTimer += DeltaTime.GetDeltaTime(); if (_recoveryJumpTimer > 0.65f && Player.Input.IsDown(Player.InputActionType.PlayerJump)) { Player.State.SetState(Knuckles.StateID.StateGliding); _recoveryJumpTimer = 0.0f; } } break; } case Player.PlayerType.Tails: { // Fix Tails being unable to fly out of StateRecoveryJump. if (Player.State.GetCurrentStateID() == Tails.StateID.StateRecoveryJump) { _recoveryJumpTimer += DeltaTime.GetDeltaTime(); if (_recoveryJumpTimer > 0.65f && Player.Input.IsDown(Player.InputActionType.PlayerJump)) { Player.State.SetState(Tails.StateID.StateTailsFly); _recoveryJumpTimer = 0.0f; } } break; } } } Patch "Fix Spin Dash Transitions" in "Fixes/Gameplay/States" by "Hyper" does /* Fixes state transitions for the spin dash state. Notes; - This allows Sonic to always trick when exiting out of spin dash whilst in the air without having to hold the boost input. */ { WriteProtected ( /* 0x1408A5B97 */ ScanSignature ( "\x41\x8D\x50\x04\x48\x8B\xCF\xE8\xCC\xCC\xCC\xCC\xB0\x01", "xxxxxxxx????xx" ), Assemble("lea edx, dword ptr [r8 + 0x10]") ); } Code "Fix Spin Transitions" in "Fixes/Gameplay/States" by "Hyper" does /* Fixes state transitions for the spin state. Notes; - This fixes Sonic being unable to spin boost, air boost and stomp out of the spin state. */ // #include "BlackboardStatus" noemit #lib "Globals" #lib "Player" #import "Plugins" static bool _isInitialised = false; // { if (!_isInitialised) { Globals.Add("Fix Spin Transitions", true); _isInitialised = true; } if (!Globals.GetFlag("Fix Spin Transitions")) return; var state = Player.State.GetCurrentStateID(); var isGrounded = Player.Status.IsGrounded(); if (state == Sonic.StateID.StateSpin) { if (Player.Input.IsPressed(Player.InputActionType.PlayerSonicboom)) Player.State.SetState(Sonic.StateID.StateSpinBoostCharge); if (Player.Input.IsPressed(Player.InputActionType.PlayerBoost)) Player.State.SetState(isGrounded ? Sonic.StateID.StateRun : Sonic.StateID.StateAirBoost); if (Player.Input.IsPressed(Player.InputActionType.PlayerStomping)) Player.State.SetState(isGrounded ? Sonic.StateID.StateRun : Sonic.StateID.StateStompingDown); } else if (state == Sonic.StateID.StateRun) { if (Memory.TryGetPointer(Player.State.GetStatePlugin(), out var out_pStatePluginBoost)) { // Don't exit with boost if the gauge is empty. if ((out_pStatePluginBoost->Flags & StatePluginBoost.BoostFlags.IsGaugeEmpty) != 0) return; } if (Player.Input.IsDown(Player.InputActionType.PlayerBoost) && isGrounded) { if (Player.State.GetPreviousStateID() == Sonic.StateID.StateSpin) SET_STATE_FLAG(IsBoost, true); } } } Code "Fix Air Boost Transitions" in "Fixes/Gameplay/States" by "Hyper & Weezley" does /* Fixes state transitions for the air boost state. Notes; - This fixes being unable to perform another air boost after previously using it before a homing attack, stomp or spring. */ // #include "BlackboardStatus" noemit #lib "Bitwise" #lib "BlackboardStatus" #lib "Globals" #lib "Player" #lib "HMM" using System.Collections.Generic; static List _allowedStates = new() { Sonic.StateID.StateHomingFinished, Sonic.StateID.StateSpringJump, Sonic.StateID.StateStompingBounce, Sonic.StateID.StateStompingFlip, Sonic.StateID.StateUpDownPole, Sonic.StateID.StateUpDownPoleDamage }; static List _disallowedStates = new() { Sonic.StateID.StateAirBoost, Sonic.StateID.StateAuraTrain, Sonic.StateID.StateGrindStep, Sonic.StateID.StateJumpBoardLaunch, Sonic.StateID.StateCaught, Sonic.StateID.StateSpinBoost }; static List _noAirBoostStates = new() { Sonic.StateID.StateGrindStep, Sonic.StateID.StateHoldStand, Sonic.StateID.StateHangPole, Sonic.StateID.StateUpDownPole, Sonic.StateID.StateUpDownPoleDamage }; static bool _isInitialised = false; static bool _isRestoredAirBoost = false; static bool _isNoAirBoost = false; static bool _isNoCycloneStart = false; static bool _isNoSpinBoostStart = false; // { if (!_isInitialised) { Globals.Add("Fix Air Boost Transitions", true); foreach (var code in HMM.GetCodes()) { switch (code) { case "Animation/Tails/Disable Cyclone Transition": _isNoCycloneStart = true; break; case "Animation/Amy/Disable Card Spin Boost Transition": _isNoSpinBoostStart = true; break; } } Sonic.StateID NotifyAirBoostReset(Sonic.StateID in_stateId, Sonic.StateID[] in_stateStackTrace) { // Reset flag for StateAirBoost or when the player is grounded. if (_disallowedStates.Contains(in_stateId) || Player.Status.IsGrounded()) { _isRestoredAirBoost = false; return in_stateId; } foreach (var state in _allowedStates) { if (state == in_stateId) _isRestoredAirBoost = true; } _isNoAirBoost = _noAirBoostStates.Contains(in_stateId); return in_stateId; } Player.State.AddStateNotifyAction(NotifyAirBoostReset); _isInitialised = true; } if (!Globals.GetFlag("Fix Air Boost Transitions")) return; var pStatePluginDiving = Player.State.GetStatePlugin("StatePluginDiving"); if (BlackboardStatus.IsSuper() || pStatePluginDiving != null || IS_STATE_FLAG(IsDiving) || IS_STATE_FLAG(IsDivingBoost) || IS_STATE_FLAG(IsBoarding) || IS_WORLD_FLAG(IsDead)) { _isRestoredAirBoost = false; } if (_isRestoredAirBoost && !_isNoAirBoost && !Player.Status.IsGroundedSpecial() && Player.Input.IsPressed(Player.InputActionType.PlayerBoost)) { // Exit into Air Boost depending on current character. if (IS_WORLD_FLAG(IsPowerBoost)) { if (Player.GetPlayerType() == Player.PlayerType.Tails) { Player.State.SetState(_isNoCycloneStart ? Tails.StateID.StateAirBoostCyclone : Tails.StateID.StateCycloneAppear); } else if (Player.GetPlayerType() == Player.PlayerType.Amy) { Player.State.SetState(_isNoSpinBoostStart ? Amy.StateID.AmyStateTarotBoost : Amy.StateID.AmyStateTarotBuildAir); } else if (Player.GetPlayerType() == Player.PlayerType.Knuckles) { Player.State.SetState(Knuckles.StateID.KnucklesStateDrillBoostAir) } else { Player.State.SetState(Sonic.StateID.StateAirBoost); } } else { Player.State.SetState(Sonic.StateID.StateAirBoost); } _isRestoredAirBoost = false; } } Code "Fix Drop Dash Transitions" in "Fixes/Gameplay/States" by "Hyper" does /* Fixes state transitions for the drop dash state. Notes; - This fixes Sonic being unable to boost, spin boost, stomp, jump or otherwise exit out of drop dash. */ // #include "BlackboardStatus" noemit #lib "Globals" #lib "Memory" #lib "Player" #import "Plugins" static bool _isInitialised = false; // { if (!_isInitialised) { Globals.Add("Fix Drop Dash Transitions", true); _isInitialised = true; } if (!Globals.GetFlag("Fix Drop Dash Transitions")) return; var state = Player.State.GetCurrentStateID(); var isGrounded = Player.Status.IsGrounded(); if (state == Sonic.StateID.StateDropDash) { if (Player.Input.IsPressed(Player.InputActionType.PlayerBoost)) Player.State.SetState(isGrounded ? Sonic.StateID.StateRun : Sonic.StateID.StateAirBoost); if (Player.Input.IsPressed(Player.InputActionType.PlayerStomping)) Player.State.SetState(isGrounded ? Sonic.StateID.StateRun : Sonic.StateID.StateStompingDown); if (Player.Input.IsPressed(Player.InputActionType.PlayerJump) && !isGrounded) Player.State.SetState(Sonic.StateID.StateDoubleJump); if (Player.Input.IsPressed(Player.InputActionType.PlayerSonicboom)) Player.State.SetState(Sonic.StateID.StateSpinBoostCharge); } else if (state == Sonic.StateID.StateRun) { if (Memory.TryGetPointer(Player.State.GetStatePlugin(), out var out_pStatePluginBoost)) { // Don't exit with boost if the gauge is empty. if ((out_pStatePluginBoost->Flags & StatePluginBoost.BoostFlags.IsGaugeEmpty) != 0) return; } if (Player.Input.IsDown(Player.InputActionType.PlayerBoost) && isGrounded) { if (Player.State.GetPreviousStateID() == Sonic.StateID.StateDropDash) SET_STATE_FLAG(IsBoost, true); } } } Code "Fix Grind Transitions" in "Fixes/Gameplay/States" by "Hyper" does /* Fixes state transitions for the grind states. Notes; - This fixes Tails being unable to stomp after jumping off of a grind rail. */ // #lib "Globals" #lib "Player" static bool _isInitialised = false; // { if (!_isInitialised) { Globals.Add("Fix Grind Transitions", true); _isInitialised = true; } if (!Globals.GetFlag("Fix Grind Transitions")) return; if (Player.GetPlayerType() == Player.PlayerType.Tails) { if (Player.State.GetCurrentStateID() is Tails.StateID.StateGrindJump or Tails.StateID.StateGrindDoubleJump) { // Fix Tails being unable to stomp back onto a grind rail after jumping. if (Player.Input.IsPressed(Player.InputActionType.PlayerStomping)) Player.State.SetState(Tails.StateID.TailsStateStompingDown); } } } Code "Fix Stomp Transitions" in "Fixes/Gameplay/States" by "Hyper & MyorraTheSniper" does /* Fixes state transitions for the stomp states. Notes; - This fixes the stomp attack only resetting once you hit the ground, allowing you to perform multiple stomps whilst still airborne. - This fixes Sonic being unable to stomp again after performing a stomp bounce. - This fixes Sonic being unable to attack after performing a stomp bounce. - This disables Sonic flipping after stomping onto specific types of collision. - This disables Sonic flipping after using the stomp shockwave on enemies. - This allows Knuckles to cancel stomp to start gliding by holding A. */ // #lib "Globals" #lib "Player" static bool _isInitialised = false; // { if (!_isInitialised) { Globals.Add("Fix Stomp Transitions", true); byte[] asm = Assemble($"lea edx, [r8 + {(int)Sonic.StateID.StateStompingLand}]"); // Disable stomp flip for collision types (e.g. Asura body). WriteProtected ( /* v1.41: 0x14096EBDE */ ScanSignature ( "\x41\x8D\x50\x3B\xE8\xCC\xCC\xCC\xCC\x48\x8D\x4D\x17\xE8\xCC\xCC\xCC\xCC\xB0\x01\xE9\x4C\x02\x00\x00", "xxxxx????xxxxx????xxxxxxx" ), asm ); // Disable stomp flip for stomp shockwave kill. { /* v1.41: 0x14B938C8C */ var sig = ScanSignature ( "\x41\x8D\x50\x3B\xE8\xCC\xCC\xCC\xCC\x48\x8D\x4C\x24\x20\xC6\x87\xB8\x00\x00\x00\x01", "xxxxx????xxxxxxxxxxxx" ); WriteProtected(sig, asm); WriteNop(sig + 14, 7); } // Fix Sonic being unable to stomp again after stomping at least once. WriteNop ( /* v1.41: 0x1409D3A9B */ ScanSignature ( "\x74\x98\x45\x33\xC0", "xxxxx" ), 2 ); _isInitialised = true; } if (!Globals.GetFlag("Fix Stomp Transitions")) return; switch (Player.GetPlayerType()) { case Player.PlayerType.Sonic: { if (Player.State.GetCurrentStateID() == Sonic.StateID.StateBounceJump) { // Fix Sonic being unable to stomp again after performing a stomp bounce. if (Player.Input.IsPressed(Player.InputActionType.PlayerStomping)) Player.State.SetState(Sonic.StateID.StateStompingDown); // Fix Sonic being unable to attack after performing a stomp bounce. if (Player.Input.IsPressed(Player.InputActionType.PlayerAttack)) Player.State.SetState(Sonic.StateID.StateFall); } break; } case Player.PlayerType.Knuckles: { // Fix Knuckles being unable to glide out of KnucklesStateStompingDown. if (Player.State.GetCurrentStateID() == Knuckles.StateID.KnucklesStateStompingDown) { if (Player.Input.IsDown(Player.InputActionType.PlayerJump)) Player.State.SetState(Knuckles.StateID.StateGliding); Player.State.Redirect(Knuckles.StateID.StateJump, Knuckles.StateID.StateGliding); Player.State.Redirect(Knuckles.StateID.StateDoubleJump, Knuckles.StateID.StateGliding); } else { Player.State.Restore(Knuckles.StateID.StateJump); Player.State.Restore(Knuckles.StateID.StateDoubleJump); } break; } } } Code "Always Have No Guard Level" in "Cheats/Upgrades/0%" by "Hyper" does /* Resets the level to 1/99 for Guard. WARNING: this will affect your save data! */ // #include "SaveData" noemit // { SAVE_SET_PARAM(character.guardLevel, 0); for (int i = 0; i < 3; i++) SAVE_SET_PARAM(extraCharacters.characters[i].guardLevel, 0); } Code "Always Have No Power Level" in "Cheats/Upgrades/0%" by "Hyper" does /* Resets the level to 1/99 for Power. WARNING: this will affect your save data! */ // #include "SaveData" noemit // { SAVE_SET_PARAM(character.powerLevel, 0); for (int i = 0; i < 3; i++) SAVE_SET_PARAM(extraCharacters.characters[i].powerLevel, 0); } Code "Always Have No Speed Level" in "Cheats/Upgrades/0%" by "Hyper" does /* Resets the level to 1/99 for Speed. WARNING: this will affect your save data! */ // #include "SaveData" noemit // { SAVE_SET_PARAM(character.speedLevel, 0); for (int i = 0; i < 3; i++) SAVE_SET_PARAM(extraCharacters.characters[i].speedLevel, 0); } Code "Always Have No Ring Level" in "Cheats/Upgrades/0%" by "Hyper" does /* Resets the level to 1/99 for ring capacity. WARNING: this will affect your save data! */ // #include "SaveData" noemit // { SAVE_SET_PARAM(character.ringLevel, 0); for (int i = 0; i < 3; i++) SAVE_SET_PARAM(extraCharacters.characters[i].ringLevel, 0); } Code "Always Have Max Guard Level" in "Cheats/Upgrades/100%" by "Hyper" does /* Gives the player the maximum level for Guard. WARNING: this will affect your save data! */ // #include "SaveData" noemit // { SAVE_SET_PARAM(character.guardLevel, 98); for (int i = 0; i < 3; i++) SAVE_SET_PARAM(extraCharacters.characters[i].guardLevel, 98); } Code "Always Have Max Power Level" in "Cheats/Upgrades/100%" by "Hyper" does /* Gives the player the maximum level for Power. WARNING: this will affect your save data! */ // #include "SaveData" noemit // { SAVE_SET_PARAM(character.powerLevel, 98); for (int i = 0; i < 3; i++) SAVE_SET_PARAM(extraCharacters.characters[i].powerLevel, 98); } Code "Always Have Max Ring Level" in "Cheats/Upgrades/100%" by "Hyper" does /* Gives the player the maximum level for ring capacity. WARNING: this will affect your save data! */ // #include "SaveData" noemit // { SAVE_SET_PARAM(character.ringLevel, 98); for (int i = 0; i < 3; i++) SAVE_SET_PARAM(extraCharacters.characters[i].ringLevel, 98); } Code "Always Have Max Boost Gauge" in "Cheats/Upgrades/100%" by "Hyper" does /* Gives the player the maximum level for the boost gauge. WARNING: this will affect your save data! */ // #include "SaveData" noemit // { SAVE_SET_PARAM(character.boostGaugeLevel, 32); for (int i = 0; i < 3; i++) SAVE_SET_PARAM(extraCharacters.characters[i].boostGaugeLevel, 32); } Code "Always Have Max Speed Level" in "Cheats/Upgrades/100%" by "Hyper" does /* Gives the player the maximum level for Speed. WARNING: this will affect your save data! */ // #include "SaveData" noemit // { SAVE_SET_PARAM(character.speedLevel, 98); for (int i = 0; i < 3; i++) SAVE_SET_PARAM(extraCharacters.characters[i].speedLevel, 98); } Code "Disable Air Tricks from Traversal Objects" in "Gameplay/Open Zone/Skills/Sonic" by "Hyper" does "Disables the ability to air trick when using Dash Rings, Jump Boards and Springs." // #include "BlackboardStatus" noemit #lib "Player" // { if (IS_WORLD_FLAG(IsCyberSpace)) return; if (IS_STATE_FLAG(IsSpringJump) || Player.State.GetCurrentStateID() == Sonic.StateID.StateJumpBoardLaunch) SET_WORLD_FLAG(IsAirTrick, false); } Code "Disable Air Tricks from Terrain" in "Gameplay/Open Zone/Skills/Sonic" by "Hyper" does /* Disables the ability to air trick when flinging off terrain. Notes; - This also applies to boosting out of Spin Dash in the air. */ // #include "BlackboardStatus" noemit #lib "Player" // { if (IS_WORLD_FLAG(IsCyberSpace)) return; if (!Player.Status.IsGrounded() && Player.State.GetCurrentStateID() == Sonic.StateID.StateBumpJump) SET_WORLD_FLAG(IsAirTrick, false); }