Last active
February 22, 2025 02:46
-
-
Save wRadion/b44f84cdd0233eb5e2e6ef024aa1b6e4 to your computer and use it in GitHub Desktop.
Hell of an Office - Autosplitter and Load Remover
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Hell Of An Office (1.0.0) | |
* Autosplitter + Load Removal by wRadion | |
*/ | |
state("HellOfAnOffice-Win64-Shipping") | |
{ | |
// IsOpenLevelSelector, switch from false to true when exiting a level back to level selector | |
bool IsOpenLevelSelector : "HellOfAnOffice-Win64-Shipping.exe", 0x5070360, 0x1D0, 0x2F0; | |
// Level Names: "01-01", "01-02", ... | |
string10 LevelFinished : "HellOfAnOffice-Win64-Shipping.exe", 0x5070360, 0x30, 0xA8, 0x38, 0x580, 0x10, 0x5B0, 0x0; | |
string10 NextLevel : "HellOfAnOffice-Win64-Shipping.exe", 0x5070360, 0x30, 0xA8, 0x38, 0x580, 0x10, 0x5C8, 0x0; | |
} | |
startup | |
{ | |
Assembly.Load(File.ReadAllBytes("Components/asl-help")).CreateInstance("Basic"); | |
settings.Add("chapters", true, "Split at every chapters"); | |
settings.Add("levels", false, "Split at every levels", "chapters"); | |
} | |
init | |
{ | |
var namePoolData = vars.Helper.ScanRel(0xD, "89 5C 24 ?? 89 44 24 ?? 74 ?? 48 8D 15"); | |
var gWorld = vars.Helper.ScanRel(0x8, "0F 2E ?? 74 ?? 48 8B 1D ?? ?? ?? ?? 48 85 DB 74"); | |
if (namePoolData == IntPtr.Zero || gWorld == IntPtr.Zero) | |
{ | |
throw new InvalidOperationException("Failed to find required memory addresses. Retrying."); | |
} | |
// GWorld->OwningGameInstance (UMyGameInstance_C)->CurrentLevel | |
vars.Helper["LevelFName"] = vars.Helper.Make<ulong>(gWorld, 0x1D0, 0x298); | |
const int FNameBlockOffsetBits = 16; | |
const int FNameBlockOffsetMask = (1 << FNameBlockOffsetBits) - 1; | |
const int FNameIndexBits = 32; | |
const ulong FNameIndexMask = 0xFFFFFFFF; | |
var nameCache = new Dictionary<ulong, string>() { { 0, "None" } }; | |
vars.FNameToString = (Func<ulong, string>)(fName => | |
{ | |
var number = (int)(fName >> FNameIndexBits); | |
var comparisonIndex = (ulong)(fName & FNameIndexMask); | |
string name; | |
if (!nameCache.TryGetValue(comparisonIndex, out name)) | |
{ | |
var blockIndex = (ushort)(comparisonIndex >> FNameBlockOffsetBits); | |
var offset = (ushort)(comparisonIndex & FNameBlockOffsetMask); | |
var block = vars.Helper.Read<IntPtr>(namePoolData + 0x10 + blockIndex * 0x8); | |
var entry = block + 2 * offset; | |
var length = vars.Helper.Read<short>(entry) >> 6; | |
name = vars.Helper.ReadString(length, ReadStringType.UTF8, entry + 2); | |
nameCache.Add(comparisonIndex, name); | |
} | |
return number == 0 ? name : name + "_" + (number - 1); | |
}); | |
vars.Loading = false; | |
vars.WaitNextLevel = null; | |
vars.CurrentLevel = "None"; | |
} | |
start | |
{ | |
if (old.LevelFName == 0 && old.LevelFName != current.LevelFName && vars.CurrentLevel == "01-01") | |
{ | |
vars.Loading = false; | |
vars.WaitNextLevel = null; | |
return true; | |
} | |
} | |
reset | |
{ | |
return (!old.IsOpenLevelSelector && current.IsOpenLevelSelector) || | |
(current.LevelFName == 0 && (current.LevelFinished == null || current.LevelFinished[2] != '-') && (current.NextLevel == null || current.NextLevel[2] != '-') && vars.WaitNextLevel == null) || | |
(old.LevelFName == 0 && old.LevelFName != current.LevelFName && vars.CurrentLevel == "01-01"); | |
} | |
update | |
{ | |
vars.Helper.Update(); | |
vars.Helper.MapPointers(); | |
if (old.LevelFName != current.LevelFName) | |
vars.CurrentLevel = vars.FNameToString(current.LevelFName); | |
if (current.NextLevel != old.NextLevel && current.NextLevel != null && current.NextLevel[2] == '-') | |
{ | |
// Only happens when EndLevel screen shows up | |
if (current.LevelFinished == vars.CurrentLevel) | |
vars.Loading = true; | |
vars.WaitNextLevel = current.NextLevel; | |
} | |
} | |
split | |
{ | |
// Level split | |
if (vars.WaitNextLevel != null && vars.CurrentLevel == vars.WaitNextLevel) | |
{ | |
vars.Loading = false; | |
vars.WaitNextLevel = null; | |
if (settings["levels"]) | |
return true; | |
// Chapter split | |
bool firstLevel = vars.CurrentLevel.Length == 5 && vars.CurrentLevel[4] == '1'; | |
if (settings["chapters"] && firstLevel) | |
return true; | |
} | |
// Last Split | |
if (current.NextLevel == "Main_") | |
return true; | |
} | |
isLoading | |
{ | |
return vars.Loading; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment