Skip to content

Instantly share code, notes, and snippets.

@wRadion
Last active February 22, 2025 02:46
Show Gist options
  • Save wRadion/b44f84cdd0233eb5e2e6ef024aa1b6e4 to your computer and use it in GitHub Desktop.
Save wRadion/b44f84cdd0233eb5e2e6ef024aa1b6e4 to your computer and use it in GitHub Desktop.
Hell of an Office - Autosplitter and Load Remover
/**
* 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