Implement native RT.DAT read history
This commit is contained in:
@@ -28,13 +28,20 @@ public static class ScriptAssembler
|
||||
{
|
||||
int codeLen = 0;
|
||||
foreach (var ins in instrs) codeLen += 1 + 2 * ins.Args.Length;
|
||||
var messageOffsets = new List<uint>();
|
||||
int instructionOffset = 0;
|
||||
foreach (var ins in instrs)
|
||||
{
|
||||
if (ins.Op == 0x71) messageOffsets.Add((uint)instructionOffset);
|
||||
instructionOffset += 1 + 2 * ins.Args.Length;
|
||||
}
|
||||
|
||||
// Encode strings; record each string's starting dword offset (relative to body start).
|
||||
var strDwords = new List<uint>();
|
||||
var strOffset = new int[strings.Count];
|
||||
for (int i = 0; i < strings.Count; i++)
|
||||
{
|
||||
strOffset[i] = codeLen + strDwords.Count;
|
||||
strOffset[i] = codeLen + messageOffsets.Count + strDwords.Count;
|
||||
strDwords.AddRange(EncodeString(strings[i]));
|
||||
}
|
||||
|
||||
@@ -49,10 +56,14 @@ public static class ScriptAssembler
|
||||
body.Add((uint)val);
|
||||
}
|
||||
}
|
||||
body.AddRange(messageOffsets);
|
||||
body.AddRange(strDwords);
|
||||
|
||||
var fields = new int[NumFields];
|
||||
fields[8] = codeLen; // F8 = code end (strings begin here)
|
||||
fields[7] = messageOffsets.Count; // F7 = T1/read-message boundary count
|
||||
fields[8] = codeLen; // F8 = code end / T1 table start
|
||||
fields[10] = codeLen + messageOffsets.Count;
|
||||
fields[12] = codeLen + messageOffsets.Count;
|
||||
|
||||
var bytes = new byte[HeaderSize + body.Count * 4];
|
||||
Encoding.ASCII.GetBytes("SYS4422 ").CopyTo(bytes, 0);
|
||||
|
||||
@@ -7,7 +7,7 @@ public static class Sys4Loader
|
||||
public static Script Load(string path, OpcodeTable table)
|
||||
=> Parse(File.ReadAllBytes(path), table, Path.GetFileName(path));
|
||||
|
||||
public static Script Parse(byte[] data, OpcodeTable table, string name = "")
|
||||
public static Script Parse(byte[] data, OpcodeTable table, string name = "", uint packedId = 0)
|
||||
{
|
||||
if (data.Length < HeaderSize) throw new InvalidDataException($"{name}: too small");
|
||||
if (!(data[0] == (byte)'S' && data[1] == (byte)'Y' && data[2] == (byte)'S' && data[3] == (byte)'4'))
|
||||
@@ -22,14 +22,23 @@ public static class Sys4Loader
|
||||
|
||||
var header = new ScriptHeader(fields[0], fields[1], fields[2], fields[3], fields[4], fields[5]);
|
||||
var (instrs, idxByOff, strings) = DecodeCode(dw, fields, nbody, table);
|
||||
int messageCount = fields[7];
|
||||
int messageTableOffset = fields[8];
|
||||
if (messageCount < 0 || messageTableOffset < 0
|
||||
|| messageTableOffset > nbody || messageCount > nbody - messageTableOffset)
|
||||
throw new InvalidDataException($"{name}: invalid T1 read-message table");
|
||||
int[] messageOffsets = dw.AsSpan(messageTableOffset, messageCount)
|
||||
.ToArray().Select(value => checked((int)value)).ToArray();
|
||||
return new Script
|
||||
{
|
||||
Name = name,
|
||||
PackedId = packedId,
|
||||
Header = header,
|
||||
Instructions = instrs,
|
||||
IndexByOffset = idxByOff,
|
||||
Strings = strings,
|
||||
BodyDwords = dw,
|
||||
ReadMessageOffsets = messageOffsets,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -51,5 +51,5 @@ public sealed class Sys4ScriptProvider : IScriptProvider
|
||||
=> GetByName(name) ?? throw new FileNotFoundException($"script is not in SYS4INI: {name}", name);
|
||||
|
||||
private Script Parse(AssetEntry entry)
|
||||
=> Sys4Loader.Parse(_store.ReadAll(entry), _table, entry.Name);
|
||||
=> Sys4Loader.Parse(_store.ReadAll(entry), _table, entry.Name, unchecked((uint)entry.PackedId));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user