init new repos
This commit is contained in:
148
Assets/Code/ScriptLoader.cs
Normal file
148
Assets/Code/ScriptLoader.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
public class ScriptLoader
|
||||
{
|
||||
public Script Load(byte[] binaryData)
|
||||
{
|
||||
Script script = new Script();
|
||||
using (BinaryReader reader = new BinaryReader(new MemoryStream(binaryData)))
|
||||
{
|
||||
uint subTableOffset = reader.ReadUInt32();
|
||||
uint unk2 = reader.ReadUInt32();
|
||||
uint subCount = reader.ReadUInt32();
|
||||
|
||||
uint cmdListOffset = reader.ReadUInt32();
|
||||
uint paramsListOffset = reader.ReadUInt32();
|
||||
uint textArrayOffset = reader.ReadUInt32();
|
||||
uint endOfFileOffset = (uint)binaryData.Length; // <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
script.SubroutineTable = ParseSubTable(reader, subCount, subTableOffset);
|
||||
|
||||
reader.BaseStream.Position = cmdListOffset;
|
||||
List<ScriptCommand> commandsWithoutParams = ParseCmdListWithoutParams(reader, paramsListOffset);
|
||||
script.Commands = new List<ScriptCommand>(commandsWithoutParams.Count);
|
||||
|
||||
for (int i = 0; i < commandsWithoutParams.Count; i++)
|
||||
{
|
||||
ScriptCommand cmd = commandsWithoutParams[i];
|
||||
uint currentParamsOffset = cmd.ParamsOffset;
|
||||
uint nextParamsOffset;
|
||||
|
||||
if (i < commandsWithoutParams.Count - 1)
|
||||
{
|
||||
nextParamsOffset = commandsWithoutParams[i + 1].ParamsOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextParamsOffset = textArrayOffset;
|
||||
}
|
||||
|
||||
|
||||
int paramsLengthInBytes = (int)(nextParamsOffset - currentParamsOffset);
|
||||
cmd.Params = ReadParamValues(reader, currentParamsOffset, paramsLengthInBytes);
|
||||
script.Commands.Add(cmd);
|
||||
}
|
||||
script.TextData = ReadBytes(reader, textArrayOffset, endOfFileOffset);
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
private List<ScriptCommand> ParseCmdListWithoutParams(BinaryReader reader, uint paramsListOffset)
|
||||
{
|
||||
var commands = new List<ScriptCommand>();
|
||||
while (reader.BaseStream.Position < paramsListOffset)
|
||||
{
|
||||
ScriptCommand cmd = new ScriptCommand
|
||||
{
|
||||
OpCode = reader.ReadUInt32() & 0xFFFF, //Cleaning to 16-bit command (May be some trash or what ???),
|
||||
ParamsOffset = reader.ReadUInt32()
|
||||
};
|
||||
commands.Add(cmd);
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
|
||||
private int[] ReadParamValues(BinaryReader reader, uint startOffset, int lengthInBytes)
|
||||
{
|
||||
if (lengthInBytes <= 0) return new int[0];
|
||||
if (lengthInBytes % 4 != 0)
|
||||
{
|
||||
Debug.LogWarning($"Parameter block length ({lengthInBytes}) is not a multiple of 4. Truncating.");
|
||||
lengthInBytes = (lengthInBytes / 4) * 4; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 4
|
||||
}
|
||||
|
||||
int paramCount = lengthInBytes / 4;
|
||||
int[] parameters = new int[paramCount];
|
||||
|
||||
reader.BaseStream.Position = startOffset;
|
||||
for (int i = 0; i < paramCount; i++)
|
||||
{
|
||||
parameters[i] = reader.ReadInt32();
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private byte[] ReadBytes(BinaryReader reader, uint startAddr, uint endAddr)
|
||||
{
|
||||
if (startAddr >= endAddr)
|
||||
return new byte[0];
|
||||
|
||||
int length = (int)(endAddr - startAddr);
|
||||
reader.BaseStream.Position = startAddr;
|
||||
return reader.ReadBytes(length);
|
||||
}
|
||||
|
||||
private Dictionary<ushort, Subroutine> ParseSubTable(BinaryReader reader, uint subCount, long baseOffset)
|
||||
{
|
||||
var table = new Dictionary<ushort, Subroutine>();
|
||||
|
||||
for (ushort id = 0; id < subCount; id++)
|
||||
{
|
||||
long entryOffset = baseOffset + (id * 72); // 72 bytes on each subroutine header
|
||||
reader.BaseStream.Position = entryOffset;
|
||||
|
||||
Subroutine sub = new Subroutine();
|
||||
sub.Id = id;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> (null-terminated string)
|
||||
List<byte> nameBytes = new List<byte>();
|
||||
byte b;
|
||||
while ((b = reader.ReadByte()) != 0)
|
||||
{
|
||||
nameBytes.Add(b);
|
||||
}
|
||||
sub.Name = System.Text.Encoding.UTF8.GetString(nameBytes.ToArray());
|
||||
|
||||
reader.BaseStream.Position = entryOffset + 64; //address always +64 byte offset from structure start
|
||||
sub.Address = reader.ReadUInt32();
|
||||
|
||||
table.Add(id, sub);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
public class Script
|
||||
{
|
||||
public Dictionary<ushort, Subroutine> SubroutineTable { get; set; }
|
||||
public List<ScriptCommand> Commands { get; set; }
|
||||
public byte[] TextData { get; set; } // textBlob
|
||||
}
|
||||
|
||||
public class Subroutine
|
||||
{
|
||||
public ushort Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public uint Address { get; set; } // <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Commands
|
||||
}
|
||||
|
||||
public class ScriptCommand
|
||||
{
|
||||
public uint OpCode { get; set; }
|
||||
public ushort executedStatus { get; set; } //For original engine compability (0 - not executed, 3 - parsed, may be other statuses - need to reverse)
|
||||
public uint ParamsOffset { get; set; }
|
||||
public int[] Params { get; set; } // command params array
|
||||
}
|
||||
Reference in New Issue
Block a user