-
Notifications
You must be signed in to change notification settings - Fork 3
/
TEMPLATE_unreal_4.23+.asl
124 lines (100 loc) · 4.12 KB
/
TEMPLATE_unreal_4.23+.asl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// unreal 4.23+
state("TEMPLATE")
{
long FNamePool: ;
// long worldFName: , 0x18;
}
startup
{
Assembly.Load(File.ReadAllBytes("Components/asl-help")).CreateInstance("Basic");
vars.Helper.GameName = "TEMPLATE";
// vars.Helper.Settings.CreateFromXml("Components/TEMPLATE.Settings.xml");
vars.Watch = (Action<IDictionary<string, object>, IDictionary<string, object>, string>)((oldLookup, currentLookup, key) =>
{
var oldValue = oldLookup[key];
var currentValue = currentLookup[key];
if (!oldValue.Equals(currentValue))
vars.Log(key + ": " + oldValue + " -> " + currentValue);
});
vars.CompletedSplits = new HashSet<string>();
// vars.Helper.AlertLoadless();
}
init
{
// vars.FNamePool = vars.Helper.ScanRel(13, "89 5C 24 ?? 89 44 24 ?? 74 ?? 48 8D 15");
// vars.GWorld = vars.Helper.ScanRel(3, "48 8B 05 ???????? 48 3B C? 48 0F 44 C? 48 89 05 ???????? E8");
// vars.GEngine = vars.Helper.ScanRel(7, "A8 01 75 ?? 48 C7 05");
// vars.GameEngine = vars.Helper.ScanRel(0x3, "48 89 05 ?? ?? ?? ?? 48 85 C9 74 ?? E8 ?? ?? ?? ?? 48 8D 4D");
// vars.UWorld = vars.Helper.ScanRel(0x3, "48 8B 1D ?? ?? ?? ?? 48 85 DB 75 ?? E8 ?? ?? ?? ?? 48 8B D8 48 85 C0 74 ?? E8 ?? ?? ?? ?? 48 8B 53 ?? 4C 8D 40 ?? 48 63 40 ?? 3B 42 ?? 7F ?? 48 8B C8 48 8B 42 ?? 4C 39 04 C8 74 ?? 49 8B DF");
// The following code derefences FName structs to their string counterparts by
// indexing the FNamePool table
// `fname` is the actual struct, not a pointer to the struct
var cachedFNames = new Dictionary<long, string>();
vars.ReadFName = (Func<long, string>)(fname =>
{
string name;
if (cachedFNames.TryGetValue(fname, out name))
return name;
int name_offset = (int) fname & 0xFFFF;
int chunk_offset = (int) (fname >> 0x10) & 0xFFFF;
var base_ptr = new DeepPointer((IntPtr) current.FNamePool + chunk_offset * 0x8, name_offset * 0x2);
byte[] name_metadata = base_ptr.DerefBytes(game, 2);
// First 10 bits are the size, but we read the bytes out of order
// e.g. 3C05 in memory is 0011 1100 0000 0101, but really the bytes we want are the last 8 and the first two, in that order.
int size = name_metadata[1] << 2 | (name_metadata[0] & 0xC0) >> 6;
// read the next (size) bytes after the name_metadata
IntPtr name_addr;
base_ptr.DerefOffsets(game, out name_addr);
// 2 bytes here for the name_metadata
name = game.ReadString(name_addr + 0x2, size);
cachedFNames[fname] = name;
return name;
});
// this function is a helper for checking splits that may or may not exist in settings,
// and if we want to do them only once
vars.CheckSplit = (Func<string, bool>)(key =>
{
// if the split doesn't exist, or it's off, or we've done it already
if (!settings.ContainsKey(key)
|| !settings[key]
|| !vars.CompletedSplits.Add(key)
) {
return false;
}
vars.Log("Completed: " + key);
return true;
});
}
update
{
// Deref useful FNames here
IDictionary<string, object> currentLookup = current;
foreach (var key in new List<string>(currentLookup.Keys))
{
object value = currentLookup[key];
if (!key.EndsWith("FName") || value.GetType() != typeof(long))
continue;
// e.g. missionFName -> mission
string newKey = key.Substring(0, key.Length - 5);
string newName = vars.ReadFName((long) value);
object oldName;
bool newKeyExists = currentLookup.TryGetValue(newKey, out oldName);
if (newName == "None" && newKeyExists)
continue;
// Debugging and such
if (!newKeyExists)
{
vars.Log(newKey + ": " + newName);
}
else if (oldName != newName)
{
vars.Log(newKey + ": " + oldName + " -> " + newName);
}
currentLookup[newKey] = newName;
}
}
onStart
{
// refresh all splits when we start the run, none are yet completed
vars.CompletedSplits.Clear();
}