mirror of
https://github.com/ncblakely/GiantsTools
synced 2024-11-27 16:13:09 +01:00
Add binary tools assembly and FX decompiler.
This commit is contained in:
parent
1f4d4e846c
commit
d2bc9454ed
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,6 +14,7 @@ profile.arm.json
|
|||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
launchSettings.json
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
xcopy "%GIANTS_PATH%\gg_dx7r.dll" "Files\" /Y
|
xcopy "%GIANTS_PATH%\gg_dx7r.dll" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\gg_dx9r.dll" "Files\" /Y
|
xcopy "%GIANTS_PATH%\gg_dx9r.dll" "Files\" /Y
|
||||||
|
xcopy "%GIANTS_PATH%\dedicated.exe" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\Giants.exe" "Files\" /Y
|
xcopy "%GIANTS_PATH%\Giants.exe" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\GiantsMain.exe" "Files\" /Y
|
xcopy "%GIANTS_PATH%\GiantsMain.exe" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\GiantsDedicated.exe" "Files\" /Y
|
xcopy "%GIANTS_PATH%\GiantsDedicated.exe" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\gs_ds.dll" "Files\" /Y
|
xcopy "%GIANTS_PATH%\gs_ds.dll" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\Giants.WebApi.Clients.dll" "Files\" /Y
|
xcopy "%GIANTS_PATH%\Giants.WebApi.Clients.dll" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\fmt.dll" "Files\" /Y
|
xcopy "%GIANTS_PATH%\fmt.dll" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\BugTrap.dll" "Files\" /Y
|
xcopy "%GIANTS_PATH%\crashrpt_lang.ini" "Files\" /Y
|
||||||
|
xcopy "%GIANTS_PATH%\CrashRpt1403.dll" "Files\" /Y
|
||||||
|
xcopy "%GIANTS_PATH%\CrashSender1403.exe" "Files\" /Y
|
||||||
|
xcopy "%GIANTS_PATH%\dbghelp.dll" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\cpprest_2_10.dll" "Files\" /Y
|
xcopy "%GIANTS_PATH%\cpprest_2_10.dll" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\Newtonsoft.Json.dll" "Files\" /Y
|
xcopy "%GIANTS_PATH%\Newtonsoft.Json.dll" "Files\" /Y
|
||||||
xcopy "%GIANTS_PATH%\zlib1.dll" "Files\" /Y
|
xcopy "%GIANTS_PATH%\zlib1.dll" "Files\" /Y
|
||||||
|
|
||||||
|
pause
|
@ -42,7 +42,7 @@ SetCompressor /SOLID lzma
|
|||||||
; MUI end ------
|
; MUI end ------
|
||||||
|
|
||||||
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
|
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
|
||||||
OutFile "Output\GPatch1_498_204_0.exe"
|
OutFile "Output\GPatch1_498_206_0.exe"
|
||||||
InstallDir "$PROGRAMFILES\Giants\"
|
InstallDir "$PROGRAMFILES\Giants\"
|
||||||
InstallDirRegKey HKCU "SOFTWARE\PlanetMoon\Giants" "DestDir"
|
InstallDirRegKey HKCU "SOFTWARE\PlanetMoon\Giants" "DestDir"
|
||||||
ShowInstDetails hide
|
ShowInstDetails hide
|
||||||
@ -77,6 +77,7 @@ Section
|
|||||||
Delete $INSTDIR\gg_dx8r.dll
|
Delete $INSTDIR\gg_dx8r.dll
|
||||||
Delete $INSTDIR\gg_dx9r.dll
|
Delete $INSTDIR\gg_dx9r.dll
|
||||||
Delete $INSTDIR\Giants.exe
|
Delete $INSTDIR\Giants.exe
|
||||||
|
Delete $INSTDIR\BugTrap.dll
|
||||||
Delete $INSTDIR\GiantsMain.exe
|
Delete $INSTDIR\GiantsMain.exe
|
||||||
Delete $INSTDIR\*.vso
|
Delete $INSTDIR\*.vso
|
||||||
Delete $INSTDIR\*.pso
|
Delete $INSTDIR\*.pso
|
||||||
|
38
Giants.BinTools/Extensions.cs
Normal file
38
Giants.BinTools/Extensions.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
namespace Giants.BinTools
|
||||||
|
{
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a null-terminated C-string from the binary reader.
|
||||||
|
/// </summary>
|
||||||
|
public static string ReadCString(this BinaryReader reader)
|
||||||
|
{
|
||||||
|
var stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
char c = reader.ReadChar();
|
||||||
|
if (c == '\0')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stringBuilder.Append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringBuilder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a null-terminated C-string to the binary writer.
|
||||||
|
/// </summary>
|
||||||
|
public static void WriteCString(this BinaryWriter writer, string value)
|
||||||
|
{
|
||||||
|
writer.Write(Encoding.UTF8.GetBytes(value));
|
||||||
|
writer.Write('\0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
Giants.BinTools/Giants.BinTools.csproj
Normal file
19
Giants.BinTools/Giants.BinTools.csproj
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
|
<PackageReference Include="NLog" Version="4.7.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="NLog.config">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
112
Giants.BinTools/Macro/DataDefinitionMacroLine.cs
Normal file
112
Giants.BinTools/Macro/DataDefinitionMacroLine.cs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Giants.BinTools;
|
||||||
|
using Giants.BinTools.Symbol;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
public class DataDefinitionMacroLine : MacroLine
|
||||||
|
{
|
||||||
|
public MacroLineType Type => MacroLineType.DataDefinition;
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string Instruction { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string Constant { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string ConstantName { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string ArgumentPrefix { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public int ArgumentIndex { get; private set; }
|
||||||
|
|
||||||
|
public DataDefinitionMacroLine(string instruction, string[] lineData, SymbolTable symbolTable)
|
||||||
|
{
|
||||||
|
this.Instruction = instruction;
|
||||||
|
|
||||||
|
string data = lineData[1];
|
||||||
|
|
||||||
|
int argIndexRef = data.IndexOf("\\");
|
||||||
|
if (argIndexRef > 0)
|
||||||
|
{
|
||||||
|
this.ArgumentPrefix = data[0..argIndexRef];
|
||||||
|
data = data[argIndexRef..];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.StartsWith("\\"))
|
||||||
|
{
|
||||||
|
string index = data[1..];
|
||||||
|
if (index != "#")
|
||||||
|
{
|
||||||
|
this.ArgumentIndex = Convert.ToInt32(data[1..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string groupName = KnownSymbolGroupNames.GetGroupName(data);
|
||||||
|
if (groupName != null)
|
||||||
|
{
|
||||||
|
this.ConstantName = data;
|
||||||
|
if (symbolTable.TryGetSymbolFromName(groupName, data, out int symbolValue))
|
||||||
|
{
|
||||||
|
this.Constant = symbolValue.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.Constant == null)
|
||||||
|
{
|
||||||
|
this.Constant = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DataDefinitionMacroLine() { }
|
||||||
|
|
||||||
|
public string Deserialize(BinaryReader reader, SymbolTable symbolTable)
|
||||||
|
{
|
||||||
|
string value = this.Instruction switch
|
||||||
|
{
|
||||||
|
MacroInstruction.DefByte => reader.ReadByte().ToString(),
|
||||||
|
MacroInstruction.DefFloat => reader.ReadSingle().ToString(),
|
||||||
|
MacroInstruction.DefLong => reader.ReadInt32().ToString(),
|
||||||
|
MacroInstruction.Name0cs => reader.ReadCString(),
|
||||||
|
_ => throw new NotSupportedException()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(this.ArgumentPrefix))
|
||||||
|
{
|
||||||
|
if (int.TryParse(value, out int intValue) && symbolTable.TryGetSymbolFromId(this.ArgumentPrefix, intValue, out string symbolName))
|
||||||
|
{
|
||||||
|
return symbolName[this.ArgumentPrefix.Length..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Serialize(string token, SymbolTable symbolTable, BinaryWriter binaryWriter)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(this.ArgumentPrefix))
|
||||||
|
{
|
||||||
|
if (symbolTable.TryGetSymbolFromName(this.ArgumentPrefix, this.ArgumentPrefix + token, out int symbolValue))
|
||||||
|
{
|
||||||
|
token = symbolValue.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.Instruction)
|
||||||
|
{
|
||||||
|
case MacroInstruction.DefByte: binaryWriter.Write((byte)Convert.ChangeType(token, typeof(byte))); break;
|
||||||
|
case MacroInstruction.DefFloat: binaryWriter.Write((float)Convert.ChangeType(token, typeof(float))); break;
|
||||||
|
case MacroInstruction.DefLong: binaryWriter.Write((int)Convert.ChangeType(token, typeof(int))); break;
|
||||||
|
case MacroInstruction.Name0cs: binaryWriter.WriteCString(token); break;
|
||||||
|
default: throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Giants.BinTools/Macro/ElseMacroLine.cs
Normal file
7
Giants.BinTools/Macro/ElseMacroLine.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
public class ElseMacroLine : MacroLine
|
||||||
|
{
|
||||||
|
public MacroLineType Type => MacroLineType.Else;
|
||||||
|
}
|
||||||
|
}
|
7
Giants.BinTools/Macro/EndIfMacroLine.cs
Normal file
7
Giants.BinTools/Macro/EndIfMacroLine.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
public class EndIfMacroLine : MacroLine
|
||||||
|
{
|
||||||
|
public MacroLineType Type => MacroLineType.EndIf;
|
||||||
|
}
|
||||||
|
}
|
16
Giants.BinTools/Macro/GroupUseMacroLine.cs
Normal file
16
Giants.BinTools/Macro/GroupUseMacroLine.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
public class GroupUseMacroLine : MacroLine
|
||||||
|
{
|
||||||
|
public MacroLineType Type => MacroLineType.GroupUse;
|
||||||
|
|
||||||
|
public string GroupName { get; set; }
|
||||||
|
|
||||||
|
public GroupUseMacroLine(string[] tokens)
|
||||||
|
{
|
||||||
|
this.GroupName = tokens[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
internal GroupUseMacroLine() { }
|
||||||
|
}
|
||||||
|
}
|
16
Giants.BinTools/Macro/IfMacroLine.cs
Normal file
16
Giants.BinTools/Macro/IfMacroLine.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
public class IfMacroLine : MacroLine
|
||||||
|
{
|
||||||
|
public MacroLineType Type => MacroLineType.If;
|
||||||
|
|
||||||
|
public string Condition { get; }
|
||||||
|
|
||||||
|
public IfMacroLine(string[] tokens)
|
||||||
|
{
|
||||||
|
this.Condition = string.Join(" ", tokens[1..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IfMacroLine() { }
|
||||||
|
}
|
||||||
|
}
|
7
Giants.BinTools/Macro/KnownMacroGroupNames.cs
Normal file
7
Giants.BinTools/Macro/KnownMacroGroupNames.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
public static class KnownMacroGroupNames
|
||||||
|
{
|
||||||
|
public const string FxDefGroup = "fxdefgroup";
|
||||||
|
}
|
||||||
|
}
|
29
Giants.BinTools/Macro/KnownSymbolGroupNames.cs
Normal file
29
Giants.BinTools/Macro/KnownSymbolGroupNames.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public static class KnownSymbolGroupNames
|
||||||
|
{
|
||||||
|
public const string Sfx = "sfx";
|
||||||
|
public const string Fx = "Fx";
|
||||||
|
public const string Object = "ObjObj";
|
||||||
|
public const string ObjectData = "ObjData";
|
||||||
|
public const string ObjectGroup = "ObjGroup";
|
||||||
|
|
||||||
|
public static readonly IList<string> Names = new[] { Sfx, Fx, Object, ObjectData, ObjectGroup };
|
||||||
|
|
||||||
|
public static string GetGroupName(string str)
|
||||||
|
{
|
||||||
|
foreach (string groupName in Names)
|
||||||
|
{
|
||||||
|
if (str.StartsWith(groupName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return groupName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
Giants.BinTools/Macro/MacroDefinition.cs
Normal file
78
Giants.BinTools/Macro/MacroDefinition.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Giants.BinTools.Symbol;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
public class MacroDefinition
|
||||||
|
{
|
||||||
|
private static readonly Logger logger = LogManager.GetLogger(nameof(MacroDefinition));
|
||||||
|
|
||||||
|
private static readonly string[] SplitCharacters = new string[] { " ", "\t" };
|
||||||
|
|
||||||
|
public IDictionary<string, IList<MacroLine>> Groups { get; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public MacroDefinition(string name, IDictionary<string, IList<MacroLine>> groups = null)
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
this.Groups = groups ?? new Dictionary<string, IList<MacroLine>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Read(StreamReader reader, SymbolTable symbolTable)
|
||||||
|
{
|
||||||
|
string activeGroup = string.Empty;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
string line = reader.ReadLine();
|
||||||
|
if (line == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Unexpected end of macro definition in '{this.Name}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
line = line.Trim();
|
||||||
|
if (line.StartsWith(";") || string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.StartsWith(MacroInstruction.MacroDefinitionEnd))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] opcodeData = line.Split(SplitCharacters, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
var macroLine = MacroLineFactory.Read(opcodeData, symbolTable);
|
||||||
|
if (macroLine == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.Groups.Any() && !(macroLine is GroupUseMacroLine))
|
||||||
|
{
|
||||||
|
logger.Warn($"Warning: expected 'groupuse' for macro {this.Name}; this may be a bug");
|
||||||
|
|
||||||
|
// Try to recover
|
||||||
|
this.Groups.TryAdd("-MISSING-", new List<MacroLine>());
|
||||||
|
activeGroup = "-MISSING-";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (macroLine is GroupUseMacroLine groupUseMacroLine)
|
||||||
|
{
|
||||||
|
this.Groups[groupUseMacroLine.GroupName] = new List<MacroLine>();
|
||||||
|
activeGroup = groupUseMacroLine.GroupName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Groups[activeGroup].Add(macroLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
108
Giants.BinTools/Macro/MacroDefinitionTable.cs
Normal file
108
Giants.BinTools/Macro/MacroDefinitionTable.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Giants.BinTools.Symbol;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
public class MacroDefinitionTable
|
||||||
|
{
|
||||||
|
private static readonly Logger logger = LogManager.GetLogger(nameof(MacroDefinition));
|
||||||
|
|
||||||
|
private static readonly string[] SplitCharacters = new string[] { " ", "\t" };
|
||||||
|
|
||||||
|
private readonly HashSet<string> includedFiles = new HashSet<string>();
|
||||||
|
|
||||||
|
public SymbolTable SymbolTable { get; } = new SymbolTable();
|
||||||
|
|
||||||
|
public IList<MacroDefinition> MacroDefinitions { get; } = new List<MacroDefinition>();
|
||||||
|
|
||||||
|
public static MacroDefinitionTable GenerateFromLegacyBuildSystem(string bldFilePath)
|
||||||
|
{
|
||||||
|
var table = new MacroDefinitionTable();
|
||||||
|
table.ProcessFile(bldFilePath);
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessFile(string bldFilePath)
|
||||||
|
{
|
||||||
|
using FileStream stream = File.OpenRead(bldFilePath);
|
||||||
|
using StreamReader streamReader = new StreamReader(stream);
|
||||||
|
|
||||||
|
string currentLine;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
currentLine = streamReader.ReadLine();
|
||||||
|
if (currentLine == null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLine = currentLine.Trim();
|
||||||
|
string[] tokens = currentLine.Split(SplitCharacters, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
if (currentLine.StartsWith(";") || !tokens.Any())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (tokens[0].Equals(MacroInstruction.MacroDefinitionStart, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
MacroDefinition macroDefinition = this.ReadDefinition(currentLine, streamReader);
|
||||||
|
this.MacroDefinitions.Add(macroDefinition);
|
||||||
|
}
|
||||||
|
else if (tokens[0].Equals(MacroInstruction.IncludeFile, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string includeFile = tokens[1];
|
||||||
|
if (this.includedFiles.Contains(includeFile))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string directory = Directory.GetParent(bldFilePath).FullName;
|
||||||
|
string includeFilePath = Path.Combine(directory, includeFile);
|
||||||
|
if (string.IsNullOrEmpty(Path.GetExtension(includeFilePath)))
|
||||||
|
{
|
||||||
|
includeFilePath = includeFilePath + ".bld";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ProcessFile(includeFilePath);
|
||||||
|
}
|
||||||
|
else if (tokens[0].Equals(MacroInstruction.Define, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (int.TryParse(tokens[2], NumberStyles.Number, CultureInfo.InvariantCulture, out int symbolValue))
|
||||||
|
{
|
||||||
|
string groupName = KnownSymbolGroupNames.GetGroupName(tokens[1]);
|
||||||
|
if (groupName != null)
|
||||||
|
{
|
||||||
|
this.SymbolTable.AddSymbol(groupName, tokens[1], symbolValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Warn($"Failed to parse symbol '{tokens[2]}'; only integer constants are supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (currentLine != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroDefinition ReadDefinition(string line, StreamReader reader)
|
||||||
|
{
|
||||||
|
string[] opcodeData = line.Split(SplitCharacters, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
// Save definition name
|
||||||
|
string macroName = opcodeData[1];
|
||||||
|
|
||||||
|
var macroDefinition = new MacroDefinition(macroName);
|
||||||
|
macroDefinition.Read(reader, this.SymbolTable);
|
||||||
|
|
||||||
|
return macroDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MacroDefinitionTable() { }
|
||||||
|
}
|
||||||
|
}
|
18
Giants.BinTools/Macro/MacroInstruction.cs
Normal file
18
Giants.BinTools/Macro/MacroInstruction.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
public static class MacroInstruction
|
||||||
|
{
|
||||||
|
public const string IncludeFile = "include";
|
||||||
|
public const string MacroDefinitionStart = "macro";
|
||||||
|
public const string MacroDefinitionEnd = "macend";
|
||||||
|
public const string Define = "#define";
|
||||||
|
public const string DefByte = "db";
|
||||||
|
public const string DefLong = "dl";
|
||||||
|
public const string DefFloat = "df";
|
||||||
|
public const string Name0cs = "name0cs";
|
||||||
|
public const string GroupUse = "groupuse";
|
||||||
|
public const string If = "if";
|
||||||
|
public const string Else = "else";
|
||||||
|
public const string EndIf = "endif";
|
||||||
|
}
|
||||||
|
}
|
10
Giants.BinTools/Macro/MacroLine.cs
Normal file
10
Giants.BinTools/Macro/MacroLine.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(MacroLineJsonConverter))]
|
||||||
|
public interface MacroLine
|
||||||
|
{
|
||||||
|
public MacroLineType Type { get; }
|
||||||
|
}
|
||||||
|
}
|
24
Giants.BinTools/Macro/MacroLineFactory.cs
Normal file
24
Giants.BinTools/Macro/MacroLineFactory.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
using Giants.BinTools.Symbol;
|
||||||
|
|
||||||
|
public static class MacroLineFactory
|
||||||
|
{
|
||||||
|
public static MacroLine Read(string[] tokens, SymbolTable symbolTable)
|
||||||
|
{
|
||||||
|
string instruction = tokens[0].ToLowerInvariant().Trim();
|
||||||
|
return instruction switch
|
||||||
|
{
|
||||||
|
MacroInstruction.GroupUse => new GroupUseMacroLine(tokens),
|
||||||
|
MacroInstruction.DefByte => new DataDefinitionMacroLine(instruction, tokens, symbolTable),
|
||||||
|
MacroInstruction.DefFloat => new DataDefinitionMacroLine(instruction, tokens, symbolTable),
|
||||||
|
MacroInstruction.DefLong => new DataDefinitionMacroLine(instruction, tokens, symbolTable),
|
||||||
|
MacroInstruction.Name0cs => new DataDefinitionMacroLine(instruction, tokens, symbolTable),
|
||||||
|
MacroInstruction.If => new IfMacroLine(tokens),
|
||||||
|
MacroInstruction.Else => new ElseMacroLine(),
|
||||||
|
MacroInstruction.EndIf => new EndIfMacroLine(),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
Giants.BinTools/Macro/MacroLineJsonConverter.cs
Normal file
47
Giants.BinTools/Macro/MacroLineJsonConverter.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
public class MacroLineJsonConverter : CustomCreationConverter<MacroLine>
|
||||||
|
{
|
||||||
|
private MacroLineType type;
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return (objectType == typeof(MacroLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var jObject = JObject.ReadFrom(reader);
|
||||||
|
this.type = jObject["Type"].ToObject<MacroLineType>();
|
||||||
|
return base.ReadJson(jObject.CreateReader(), objectType, existingValue, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override MacroLine Create(Type objectType)
|
||||||
|
{
|
||||||
|
switch (this.type)
|
||||||
|
{
|
||||||
|
case MacroLineType.DataDefinition: return new DataDefinitionMacroLine();
|
||||||
|
case MacroLineType.Else: return new ElseMacroLine();
|
||||||
|
case MacroLineType.EndIf: return new EndIfMacroLine();
|
||||||
|
case MacroLineType.GroupUse: return new GroupUseMacroLine();
|
||||||
|
case MacroLineType.If: return new IfMacroLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
Giants.BinTools/Macro/MacroLineType.cs
Normal file
12
Giants.BinTools/Macro/MacroLineType.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Giants.BinTools.Macro
|
||||||
|
{
|
||||||
|
public enum MacroLineType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
DataDefinition,
|
||||||
|
If,
|
||||||
|
Else,
|
||||||
|
EndIf,
|
||||||
|
GroupUse
|
||||||
|
}
|
||||||
|
}
|
83
Giants.BinTools/Symbol/SymbolTable.cs
Normal file
83
Giants.BinTools/Symbol/SymbolTable.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
namespace Giants.BinTools.Symbol
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
public class SymbolTable
|
||||||
|
{
|
||||||
|
private static readonly HashSet<string> ExcludedSymbols = new HashSet<string>() { "FxBinVersion", "SfxVersionOld", "SfxVersion1", "SfxVersion2" };
|
||||||
|
|
||||||
|
[JsonProperty(nameof(symbols))]
|
||||||
|
private IDictionary<string, CaseInsensitiveDictionary<int>> symbols = new Dictionary<string, CaseInsensitiveDictionary<int>>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
private IDictionary<string, IDictionary<int, string>> reverseSymbolLookup = new Dictionary<string, IDictionary<int, string>>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
[OnDeserialized]
|
||||||
|
internal void OnDeserialized(StreamingContext context)
|
||||||
|
{
|
||||||
|
foreach (var symbolGroup in this.symbols)
|
||||||
|
{
|
||||||
|
this.reverseSymbolLookup.Add(symbolGroup.Key, new Dictionary<int, string>());
|
||||||
|
foreach (var symbol in this.symbols[symbolGroup.Key])
|
||||||
|
{
|
||||||
|
this.reverseSymbolLookup[symbolGroup.Key].Add(symbol.Value, symbol.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddSymbol(string symbolGroup, string symbolName, int symbolValue)
|
||||||
|
{
|
||||||
|
if (ExcludedSymbols.Contains(symbolName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.symbols.ContainsKey(symbolGroup))
|
||||||
|
{
|
||||||
|
this.symbols.Add(symbolGroup, new CaseInsensitiveDictionary<int>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.reverseSymbolLookup.ContainsKey(symbolGroup))
|
||||||
|
{
|
||||||
|
this.reverseSymbolLookup.Add(symbolGroup, new Dictionary<int, string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.symbols[symbolGroup].Add(symbolName, symbolValue);
|
||||||
|
this.reverseSymbolLookup[symbolGroup].Add(symbolValue, symbolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(string symbolGroup, string key)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(symbolGroup) && !string.IsNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
return this.symbols.ContainsKey(symbolGroup)
|
||||||
|
&& this.symbols[symbolGroup].ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetSymbolFromName(string symbolGroup, string symbolName, out int symbolValue)
|
||||||
|
{
|
||||||
|
return this.symbols[symbolGroup].TryGetValue(symbolName, out symbolValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetSymbolFromId(string symbolGroup, int symbolValue, out string symbolName)
|
||||||
|
{
|
||||||
|
return this.reverseSymbolLookup[symbolGroup].TryGetValue(symbolValue, out symbolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDictionary<string, int> GetSymbolGroup(string symbolGroup)
|
||||||
|
{
|
||||||
|
return this.symbols[symbolGroup];
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CaseInsensitiveDictionary<TValue> : Dictionary<string, TValue>
|
||||||
|
{
|
||||||
|
public CaseInsensitiveDictionary()
|
||||||
|
: base(StringComparer.OrdinalIgnoreCase) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,15 +20,15 @@
|
|||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
return obj is AppVersion info &&
|
return obj is AppVersion info &&
|
||||||
Build == info.Build &&
|
this.Build == info.Build &&
|
||||||
Major == info.Major &&
|
this.Major == info.Major &&
|
||||||
Minor == info.Minor &&
|
this.Minor == info.Minor &&
|
||||||
Revision == info.Revision;
|
this.Revision == info.Revision;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return HashCode.Combine(Build, Major, Minor, Revision);
|
return HashCode.Combine(this.Build, this.Major, this.Minor, this.Revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Version ToVersion()
|
public Version ToVersion()
|
||||||
|
@ -23,16 +23,16 @@ namespace Giants.DataContract.V1
|
|||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
return obj is PlayerInfo info &&
|
return obj is PlayerInfo info &&
|
||||||
Index == info.Index &&
|
this.Index == info.Index &&
|
||||||
Name == info.Name &&
|
this.Name == info.Name &&
|
||||||
Frags == info.Frags &&
|
this.Frags == info.Frags &&
|
||||||
Deaths == info.Deaths &&
|
this.Deaths == info.Deaths &&
|
||||||
TeamName == info.TeamName;
|
this.TeamName == info.TeamName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return HashCode.Combine(Index, Name, Frags, Deaths, TeamName);
|
return HashCode.Combine(this.Index, this.Name, this.Frags, this.Deaths, this.TeamName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,37 +54,37 @@
|
|||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
return obj is ServerInfo info &&
|
return obj is ServerInfo info &&
|
||||||
GameName == info.GameName &&
|
this.GameName == info.GameName &&
|
||||||
EqualityComparer<AppVersion>.Default.Equals(Version, info.Version) &&
|
EqualityComparer<AppVersion>.Default.Equals(this.Version, info.Version) &&
|
||||||
SessionName == info.SessionName &&
|
this.SessionName == info.SessionName &&
|
||||||
Port == info.Port &&
|
this.Port == info.Port &&
|
||||||
MapName == info.MapName &&
|
this.MapName == info.MapName &&
|
||||||
GameType == info.GameType &&
|
this.GameType == info.GameType &&
|
||||||
NumPlayers == info.NumPlayers &&
|
this.NumPlayers == info.NumPlayers &&
|
||||||
GameState == info.GameState &&
|
this.GameState == info.GameState &&
|
||||||
TimeLimit == info.TimeLimit &&
|
this.TimeLimit == info.TimeLimit &&
|
||||||
FragLimit == info.FragLimit &&
|
this.FragLimit == info.FragLimit &&
|
||||||
TeamFragLimit == info.TeamFragLimit &&
|
this.TeamFragLimit == info.TeamFragLimit &&
|
||||||
FirstBaseComplete == info.FirstBaseComplete &&
|
this.FirstBaseComplete == info.FirstBaseComplete &&
|
||||||
PlayerInfo.SequenceEqual(info.PlayerInfo);
|
this.PlayerInfo.SequenceEqual(info.PlayerInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
HashCode hash = new HashCode();
|
HashCode hash = new HashCode();
|
||||||
hash.Add(GameName);
|
hash.Add(this.GameName);
|
||||||
hash.Add(Version);
|
hash.Add(this.Version);
|
||||||
hash.Add(SessionName);
|
hash.Add(this.SessionName);
|
||||||
hash.Add(Port);
|
hash.Add(this.Port);
|
||||||
hash.Add(MapName);
|
hash.Add(this.MapName);
|
||||||
hash.Add(GameType);
|
hash.Add(this.GameType);
|
||||||
hash.Add(NumPlayers);
|
hash.Add(this.NumPlayers);
|
||||||
hash.Add(GameState);
|
hash.Add(this.GameState);
|
||||||
hash.Add(TimeLimit);
|
hash.Add(this.TimeLimit);
|
||||||
hash.Add(FragLimit);
|
hash.Add(this.FragLimit);
|
||||||
hash.Add(TeamFragLimit);
|
hash.Add(this.TeamFragLimit);
|
||||||
hash.Add(FirstBaseComplete);
|
hash.Add(this.FirstBaseComplete);
|
||||||
hash.Add(PlayerInfo);
|
hash.Add(this.PlayerInfo);
|
||||||
return hash.ToHashCode();
|
return hash.ToHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,14 @@
|
|||||||
{
|
{
|
||||||
return obj is ServerInfoWithHostAddress address &&
|
return obj is ServerInfoWithHostAddress address &&
|
||||||
base.Equals(obj) &&
|
base.Equals(obj) &&
|
||||||
HostIpAddress == address.HostIpAddress;
|
this.HostIpAddress == address.HostIpAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
HashCode hash = new HashCode();
|
HashCode hash = new HashCode();
|
||||||
hash.Add(base.GetHashCode());
|
hash.Add(base.GetHashCode());
|
||||||
hash.Add(HostIpAddress);
|
hash.Add(this.HostIpAddress);
|
||||||
return hash.ToHashCode();
|
return hash.ToHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" />
|
||||||
|
<PackageReference Include="coverlet.collector" Version="1.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Giants.EffectCompiler\Giants.EffectCompiler.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -0,0 +1,57 @@
|
|||||||
|
namespace Giants.EffectCompiler.Tests.Integration
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class DecompileCompileTests
|
||||||
|
{
|
||||||
|
private const string ProjectDirectoryPath = @"..\..\..\";
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestDecompileCompile()
|
||||||
|
{
|
||||||
|
// Verify round-trip of compiled file
|
||||||
|
|
||||||
|
Guid testIdentifier = Guid.NewGuid();
|
||||||
|
string textOutputPath = @$"Temp\fx_{testIdentifier}.txt";
|
||||||
|
string binaryOutputPath = @$"Temp\fx_{testIdentifier}.bin";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var definitionTable = Utilities.LoadDefinitions();
|
||||||
|
var fxDecompiler = new FxDecompiler(definitionTable);
|
||||||
|
fxDecompiler.Decompile(
|
||||||
|
Path.Combine(ProjectDirectoryPath, @"TestResources\fx.bin"),
|
||||||
|
Path.Combine(ProjectDirectoryPath, textOutputPath));
|
||||||
|
|
||||||
|
var fxCompiler = new FxCompiler(definitionTable);
|
||||||
|
fxCompiler.Compile(
|
||||||
|
Path.Combine(ProjectDirectoryPath, textOutputPath),
|
||||||
|
Path.Combine(ProjectDirectoryPath, binaryOutputPath));
|
||||||
|
|
||||||
|
using var originalFile = new BinaryReader(File.Open(Path.Combine(ProjectDirectoryPath, @"TestResources\fx.bin"), FileMode.Open));
|
||||||
|
using var recompiledFile = new BinaryReader(File.Open(Path.Combine(ProjectDirectoryPath, binaryOutputPath), FileMode.Open));
|
||||||
|
|
||||||
|
if (originalFile.BaseStream.Length != recompiledFile.BaseStream.Length)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("File sizes do not match.");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (originalFile.BaseStream.Position != originalFile.BaseStream.Length)
|
||||||
|
{
|
||||||
|
byte b1 = originalFile.ReadByte();
|
||||||
|
byte b2 = recompiledFile.ReadByte();
|
||||||
|
|
||||||
|
Assert.AreEqual(b1, b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete(Path.Combine(ProjectDirectoryPath, textOutputPath));
|
||||||
|
File.Delete(Path.Combine(ProjectDirectoryPath, binaryOutputPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
Giants.EffectCompiler.Tests/TestResources/fx.bin
Normal file
BIN
Giants.EffectCompiler.Tests/TestResources/fx.bin
Normal file
Binary file not shown.
8
Giants.EffectCompiler/Compiler/ContentEntry.cs
Normal file
8
Giants.EffectCompiler/Compiler/ContentEntry.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Giants.EffectCompiler
|
||||||
|
{
|
||||||
|
public class ContentEntry
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int Offset { get; set; }
|
||||||
|
}
|
||||||
|
}
|
155
Giants.EffectCompiler/Compiler/FxCompiler.cs
Normal file
155
Giants.EffectCompiler/Compiler/FxCompiler.cs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
namespace Giants.EffectCompiler
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Giants.BinTools.Macro;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Effect binary compiler.
|
||||||
|
/// </summary>
|
||||||
|
public class FxCompiler
|
||||||
|
{
|
||||||
|
private static readonly Logger logger = LogManager.GetLogger(nameof(FxCompiler));
|
||||||
|
|
||||||
|
private FxMacroDefinitionTable macroDefinitionTable;
|
||||||
|
private int doneOpcode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FxCompiler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="macroDefinitionTable">The table of macro and symbol definitions.</param>
|
||||||
|
public FxCompiler(FxMacroDefinitionTable macroDefinitionTable)
|
||||||
|
{
|
||||||
|
this.macroDefinitionTable = macroDefinitionTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compiles a textual effect file to the specified output path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputPath">The path to the effect file.</param>
|
||||||
|
/// <param name="outputPath">The path to write to.</param>
|
||||||
|
public void Compile(
|
||||||
|
string inputPath,
|
||||||
|
string outputPath)
|
||||||
|
{
|
||||||
|
if (!File.Exists(inputPath))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"The input file {inputPath} does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get constants for known symbols
|
||||||
|
this.doneOpcode = Utilities.GetFxSymbolValue(this.macroDefinitionTable.SymbolTable, "FxDone");
|
||||||
|
|
||||||
|
using var streamReader = new StreamReader(inputPath);
|
||||||
|
SerializedEffectData serializedEffectData = this.SerializeEffectData(streamReader);
|
||||||
|
|
||||||
|
using var fileStream = new FileStream(outputPath, FileMode.Create);
|
||||||
|
using var binaryWriter = new BinaryWriter(fileStream);
|
||||||
|
|
||||||
|
this.WriteHeader(binaryWriter, serializedEffectData);
|
||||||
|
this.WriteTableOfContents(binaryWriter, serializedEffectData);
|
||||||
|
this.WriteEffectData(binaryWriter, serializedEffectData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteEffectData(BinaryWriter binaryWriter, SerializedEffectData serializedEffectData)
|
||||||
|
{
|
||||||
|
binaryWriter.Write(serializedEffectData.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteTableOfContents(BinaryWriter binaryWriter, SerializedEffectData serializedEffectData)
|
||||||
|
{
|
||||||
|
foreach (var entry in serializedEffectData.TableOfContents)
|
||||||
|
{
|
||||||
|
binaryWriter.Write(Encoding.UTF8.GetBytes(entry.Name));
|
||||||
|
binaryWriter.Write('\0');
|
||||||
|
binaryWriter.Write(checked(entry.Offset + serializedEffectData.TableOfContentsSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteHeader(BinaryWriter binaryWriter, SerializedEffectData serializedEffectData)
|
||||||
|
{
|
||||||
|
binaryWriter.Write(FxBinaryData.CurrentVersion);
|
||||||
|
binaryWriter.Write(checked(serializedEffectData.Data.Length + serializedEffectData.TableOfContentsSize));
|
||||||
|
binaryWriter.Write(serializedEffectData.TableOfContents.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SerializeEffect(string[] tokens, StreamReader reader, BinaryWriter binaryWriter)
|
||||||
|
{
|
||||||
|
while (!reader.EndOfStream)
|
||||||
|
{
|
||||||
|
tokens = reader.ReadLine().Split(Utilities.SplitCharacters, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
string macroName = tokens[0];
|
||||||
|
if (macroName == "fxdone")
|
||||||
|
{
|
||||||
|
binaryWriter.Write((byte)this.doneOpcode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FxMacroDefinition macroDefinition = this.macroDefinitionTable.MacroDefinitions
|
||||||
|
.Values
|
||||||
|
.FirstOrDefault(x => x.Name.Equals(macroName, StringComparison.OrdinalIgnoreCase) && x.FxDefGroup.Count() == tokens[1..].Length);
|
||||||
|
|
||||||
|
binaryWriter.Write((byte)macroDefinition.Opcode);
|
||||||
|
|
||||||
|
if (macroDefinition == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Unknown macro '{macroName}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameters = new List<object>();
|
||||||
|
int parameterIndex = 1;
|
||||||
|
foreach (var line in macroDefinition.FxDefGroup)
|
||||||
|
{
|
||||||
|
if (line is DataDefinitionMacroLine dataDefinitionMacroLine)
|
||||||
|
{
|
||||||
|
dataDefinitionMacroLine.Serialize(tokens[parameterIndex++], this.macroDefinitionTable.SymbolTable, binaryWriter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SerializedEffectData SerializeEffectData(StreamReader streamReader)
|
||||||
|
{
|
||||||
|
using var memoryStream = new MemoryStream();
|
||||||
|
using var binaryWriter = new BinaryWriter(memoryStream);
|
||||||
|
|
||||||
|
var tableOfContents = new List<ContentEntry>();
|
||||||
|
int tableOfContentsSize = 0; // Keep running total of the final (serialized) size of the TOC
|
||||||
|
|
||||||
|
while (!streamReader.EndOfStream)
|
||||||
|
{
|
||||||
|
string[] tokens = streamReader.ReadLine().Split(Utilities.SplitCharacters, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (!tokens.Any())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokens[0] == "fxdef")
|
||||||
|
{
|
||||||
|
var contentEntry = new ContentEntry()
|
||||||
|
{
|
||||||
|
Name = tokens[1],
|
||||||
|
Offset = checked((int)binaryWriter.BaseStream.Position)
|
||||||
|
};
|
||||||
|
|
||||||
|
tableOfContentsSize += contentEntry.Name.Length + 1 + sizeof(int);
|
||||||
|
tableOfContents.Add(contentEntry);
|
||||||
|
|
||||||
|
this.SerializeEffect(tokens, streamReader, binaryWriter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SerializedEffectData
|
||||||
|
{
|
||||||
|
Data = memoryStream.ToArray(),
|
||||||
|
TableOfContents = tableOfContents,
|
||||||
|
TableOfContentsSize = tableOfContentsSize,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Giants.EffectCompiler/Compiler/SerializedEffectData.cs
Normal file
13
Giants.EffectCompiler/Compiler/SerializedEffectData.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Giants.EffectCompiler
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public class SerializedEffectData
|
||||||
|
{
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
|
||||||
|
public int TableOfContentsSize { get; set; }
|
||||||
|
|
||||||
|
public IList<ContentEntry> TableOfContents { get; set; } = new List<ContentEntry>();
|
||||||
|
}
|
||||||
|
}
|
176
Giants.EffectCompiler/Decompiler/FxDecompiler.cs
Normal file
176
Giants.EffectCompiler/Decompiler/FxDecompiler.cs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
namespace Giants.EffectCompiler
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using Giants.BinTools;
|
||||||
|
using Giants.BinTools.Macro;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Effect binary decompiler.
|
||||||
|
/// </summary>
|
||||||
|
public class FxDecompiler
|
||||||
|
{
|
||||||
|
private static readonly Logger logger = LogManager.GetLogger(nameof(FxDecompiler));
|
||||||
|
|
||||||
|
private readonly Dictionary<string, int> tableOfContents = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
private FxBinaryData binaryData;
|
||||||
|
private FxMacroDefinitionTable macroDefinitionTable;
|
||||||
|
private int doneOpcode;
|
||||||
|
private int pushObjOpcode;
|
||||||
|
private int popObjOpcode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FxDecompiler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="macroDefinitionTable">The table of macro and symbol definitions.</param>
|
||||||
|
public FxDecompiler(FxMacroDefinitionTable macroDefinitionTable)
|
||||||
|
{
|
||||||
|
this.macroDefinitionTable = macroDefinitionTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decompiles an effect binary file to the specified output path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputPath">The path to the effect binary file.</param>
|
||||||
|
/// <param name="outputPath">The path to write to.</param>
|
||||||
|
public void Decompile(
|
||||||
|
string inputPath,
|
||||||
|
string outputPath)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!File.Exists(inputPath))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"The input file {inputPath} does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ReadBinaryData(inputPath);
|
||||||
|
|
||||||
|
using var memoryStream = new MemoryStream(this.binaryData.Data);
|
||||||
|
using var binaryReader = new BinaryReader(memoryStream);
|
||||||
|
using var streamWriter = new StreamWriter(outputPath, false);
|
||||||
|
using var textWriter = new IndentedTextWriter(streamWriter);
|
||||||
|
|
||||||
|
this.BuildTableOfContents(binaryReader);
|
||||||
|
|
||||||
|
// Get constants for known symbols
|
||||||
|
this.doneOpcode = Utilities.GetFxSymbolValue(this.macroDefinitionTable.SymbolTable, "FxDone");
|
||||||
|
this.pushObjOpcode = Utilities.GetFxSymbolValue(this.macroDefinitionTable.SymbolTable, "FxPushObj");
|
||||||
|
this.popObjOpcode = Utilities.GetFxSymbolValue(this.macroDefinitionTable.SymbolTable, "FxPopObj");
|
||||||
|
|
||||||
|
this.ProcessEffects(binaryReader, textWriter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadBinaryData(string path)
|
||||||
|
{
|
||||||
|
using var fileStream = File.OpenRead(path);
|
||||||
|
this.binaryData = new FxBinaryData(fileStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildTableOfContents(BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < this.binaryData.EffectCount; i++)
|
||||||
|
{
|
||||||
|
string fxName = binaryReader.ReadCString();
|
||||||
|
int offset = binaryReader.ReadInt32();
|
||||||
|
|
||||||
|
if (this.tableOfContents.ContainsKey(fxName))
|
||||||
|
{
|
||||||
|
logger.Warn($"TOC already contains fx '{fxName}'; this may be a bug");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tableOfContents.Add(fxName, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessEffects(BinaryReader binaryReader, IndentedTextWriter fileStream)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var kvp in this.tableOfContents)
|
||||||
|
{
|
||||||
|
this.ProcessEffect(binaryReader, fileStream, kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error(e.Message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessEffect(
|
||||||
|
BinaryReader reader,
|
||||||
|
IndentedTextWriter fileStream,
|
||||||
|
string name,
|
||||||
|
int offset)
|
||||||
|
{
|
||||||
|
logger.Info($"Processing '{name}'");
|
||||||
|
|
||||||
|
reader.BaseStream.Position = offset;
|
||||||
|
|
||||||
|
fileStream.WriteLine($"fxdef {name}");
|
||||||
|
fileStream.Indent = 1;
|
||||||
|
|
||||||
|
int lastOpcode = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int opcode = reader.ReadByte();
|
||||||
|
if (!this.macroDefinitionTable.MacroDefinitions.TryGetValue(opcode, out FxMacroDefinition macroDefinition))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Unable to map opcode to macro definition");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opcode == this.doneOpcode)
|
||||||
|
{
|
||||||
|
fileStream.Indent--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastOpcode == this.pushObjOpcode)
|
||||||
|
{
|
||||||
|
fileStream.Indent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lineBuilder = new StringBuilder();
|
||||||
|
lineBuilder.Append(macroDefinition.Name);
|
||||||
|
lineBuilder.Append(" ");
|
||||||
|
foreach (var line in macroDefinition.FxDefGroup)
|
||||||
|
{
|
||||||
|
string stringValue = line switch
|
||||||
|
{
|
||||||
|
DataDefinitionMacroLine primitiveMacroLine => primitiveMacroLine.Deserialize(reader, this.macroDefinitionTable.SymbolTable),
|
||||||
|
_ => throw new NotSupportedException()
|
||||||
|
};
|
||||||
|
|
||||||
|
lineBuilder.Append(stringValue);
|
||||||
|
lineBuilder.Append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opcode == this.popObjOpcode)
|
||||||
|
{
|
||||||
|
fileStream.Indent--;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStream.WriteLine(lineBuilder);
|
||||||
|
fileStream.Flush();
|
||||||
|
|
||||||
|
lastOpcode = opcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error($"Exception processing {name}, last opcode was {lastOpcode}. Trace: {e}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStream.WriteLine("fxdone" + Environment.NewLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7894
Giants.EffectCompiler/Definitions.json
Normal file
7894
Giants.EffectCompiler/Definitions.json
Normal file
File diff suppressed because it is too large
Load Diff
33
Giants.EffectCompiler/FxBinaryData.cs
Normal file
33
Giants.EffectCompiler/FxBinaryData.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
namespace Giants.EffectCompiler
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
public class FxBinaryData
|
||||||
|
{
|
||||||
|
public const int CurrentVersion = 2;
|
||||||
|
|
||||||
|
public int Version { get; private set; }
|
||||||
|
|
||||||
|
public int DataSize { get; private set; }
|
||||||
|
|
||||||
|
public int EffectCount { get; private set; }
|
||||||
|
|
||||||
|
public byte[] Data { get; private set; }
|
||||||
|
|
||||||
|
public FxBinaryData(Stream stream)
|
||||||
|
{
|
||||||
|
using var reader = new BinaryReader(stream);
|
||||||
|
|
||||||
|
this.Version = reader.ReadInt32();
|
||||||
|
if (this.Version != CurrentVersion)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The version number is incorrect.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.DataSize = reader.ReadInt32();
|
||||||
|
this.EffectCount = reader.ReadInt32();
|
||||||
|
this.Data = reader.ReadBytes(this.DataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
Giants.EffectCompiler/FxMacroDefinition.cs
Normal file
14
Giants.EffectCompiler/FxMacroDefinition.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace Giants.EffectCompiler
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Giants.BinTools.Macro;
|
||||||
|
|
||||||
|
public class FxMacroDefinition
|
||||||
|
{
|
||||||
|
public int Opcode { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<MacroLine> FxDefGroup { get; set; }
|
||||||
|
}
|
||||||
|
}
|
161
Giants.EffectCompiler/FxMacroDefinitionTable.cs
Normal file
161
Giants.EffectCompiler/FxMacroDefinitionTable.cs
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
namespace Giants.EffectCompiler
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Giants.BinTools.Macro;
|
||||||
|
using Giants.BinTools.Symbol;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
public class FxMacroDefinitionTable
|
||||||
|
{
|
||||||
|
private static readonly Logger logger = LogManager.GetLogger(nameof(FxMacroDefinitionTable));
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public SymbolTable SymbolTable { get; } = new SymbolTable();
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public IDictionary<int, FxMacroDefinition> MacroDefinitions { get; } = new Dictionary<int, FxMacroDefinition>();
|
||||||
|
|
||||||
|
public FxMacroDefinitionTable(MacroDefinitionTable macroDefinitionTable)
|
||||||
|
{
|
||||||
|
this.SymbolTable = macroDefinitionTable.SymbolTable;
|
||||||
|
|
||||||
|
this.ProcessMacroDefinitions(macroDefinitionTable.MacroDefinitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
internal FxMacroDefinitionTable() { }
|
||||||
|
|
||||||
|
private void ProcessMacroDefinitions(IList<MacroDefinition> macroDefinitions)
|
||||||
|
{
|
||||||
|
// Try to map each opcode we know about to a pre-processed form of the macro definition with conditional branches eliminated
|
||||||
|
foreach (int opcode in this.SymbolTable.GetSymbolGroup(KnownSymbolGroupNames.Fx).Values)
|
||||||
|
{
|
||||||
|
FxMacroDefinition fxMacroDefinition = this.GetFxMacroDefinition(macroDefinitions, opcode);
|
||||||
|
if (fxMacroDefinition != null)
|
||||||
|
{
|
||||||
|
this.MacroDefinitions[opcode] = fxMacroDefinition;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Warn($"Opcode {opcode} has no macro defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FxMacroDefinition GetFxMacroDefinition(IList<MacroDefinition> macroDefinitions, int opcode)
|
||||||
|
{
|
||||||
|
foreach (var macroDefinition in macroDefinitions
|
||||||
|
.Where(x => x.Groups.ContainsKey(KnownMacroGroupNames.FxDefGroup) && x.Groups[KnownMacroGroupNames.FxDefGroup].Any()))
|
||||||
|
{
|
||||||
|
var fxDefGroup = macroDefinition.Groups[KnownMacroGroupNames.FxDefGroup];
|
||||||
|
for (int lineIndex = 0; lineIndex < fxDefGroup.Count; lineIndex++)
|
||||||
|
{
|
||||||
|
if (!(fxDefGroup[lineIndex] is DataDefinitionMacroLine line))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(line.ConstantName)
|
||||||
|
&& Convert.ToInt32(line.Constant) == opcode)
|
||||||
|
{
|
||||||
|
logger.Debug($"Matched opcode {opcode} to '{line.ConstantName}'");
|
||||||
|
return new FxMacroDefinition
|
||||||
|
{
|
||||||
|
Opcode = opcode,
|
||||||
|
Name = macroDefinition.Name,
|
||||||
|
FxDefGroup = SelectOptimalBranch(fxDefGroup.Skip(lineIndex + 1).ToList()).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Handle macros with instructions after the conditional (if they exist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<MacroLine> SelectOptimalBranch(List<MacroLine> macroLines)
|
||||||
|
{
|
||||||
|
var outLines = new List<MacroLine>();
|
||||||
|
|
||||||
|
int startIndex = 0;
|
||||||
|
while (startIndex < macroLines.Count)
|
||||||
|
{
|
||||||
|
if (!IsConditional(macroLines[startIndex]))
|
||||||
|
{
|
||||||
|
outLines.Add(macroLines[startIndex]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
startIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startIndex == macroLines.Count)
|
||||||
|
{
|
||||||
|
// No branches
|
||||||
|
return outLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
int longestBranchLength = 0;
|
||||||
|
int branchIndex = startIndex;
|
||||||
|
IEnumerable<MacroLine> branchLines = null;
|
||||||
|
while (branchIndex >= 0)
|
||||||
|
{
|
||||||
|
var argSet = new HashSet<int>();
|
||||||
|
|
||||||
|
int endIndex = 0;
|
||||||
|
for (int i = branchIndex + 1; i < macroLines.Count; i++)
|
||||||
|
{
|
||||||
|
if (IsOpcodeDefinition(macroLines[i]))
|
||||||
|
{
|
||||||
|
return outLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsConditional(macroLines[i]))
|
||||||
|
{
|
||||||
|
endIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (macroLines[i] is DataDefinitionMacroLine dataDefinitionLine)
|
||||||
|
{
|
||||||
|
argSet.Add(dataDefinitionLine.ArgumentIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argSet.Count > longestBranchLength)
|
||||||
|
{
|
||||||
|
longestBranchLength = branchIndex;
|
||||||
|
branchLines = macroLines.Skip(branchIndex + 1).Take(endIndex - branchIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
branchIndex = macroLines.FindIndex(branchIndex + 1, l => l is IfMacroLine || l is ElseMacroLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branchLines != null)
|
||||||
|
{
|
||||||
|
outLines.AddRange(branchLines);
|
||||||
|
}
|
||||||
|
|
||||||
|
return outLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsOpcodeDefinition(MacroLine line)
|
||||||
|
{
|
||||||
|
return line is DataDefinitionMacroLine dataDefinitionMacroLine
|
||||||
|
&& !string.IsNullOrWhiteSpace(dataDefinitionMacroLine.ConstantName)
|
||||||
|
&& !string.IsNullOrWhiteSpace(dataDefinitionMacroLine.Constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsConditional(MacroLine line)
|
||||||
|
{
|
||||||
|
return line is IfMacroLine || line is ElseMacroLine || line is EndIfMacroLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
Giants.EffectCompiler/Giants.EffectCompiler.csproj
Normal file
37
Giants.EffectCompiler/Giants.EffectCompiler.csproj
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<AssemblyName>fxbc</AssemblyName>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="Definitions.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Definitions.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
|
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20427.1" />
|
||||||
|
<PackageReference Include="System.CommandLine.DragonFruit" Version="0.3.0-alpha.20427.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Giants.BinTools\Giants.BinTools.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="NLog.config">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
12
Giants.EffectCompiler/NLog.config
Normal file
12
Giants.EffectCompiler/NLog.config
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
|
||||||
|
<targets>
|
||||||
|
<target name="console" xsi:type="ColoredConsole" layout="${level:uppercase=true}: ${message}" />
|
||||||
|
</targets>
|
||||||
|
|
||||||
|
<rules>
|
||||||
|
<logger name="*" minlevel="Info" writeTo="console" />
|
||||||
|
</rules>
|
||||||
|
</nlog>
|
49
Giants.EffectCompiler/Program.cs
Normal file
49
Giants.EffectCompiler/Program.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
namespace Giants.EffectCompiler
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using Giants.BinTools.Macro;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mode">The mode to operate in. Supported modes are: 'decompile', 'compile'.</param>
|
||||||
|
/// <param name="input">The input path.</param>
|
||||||
|
/// <param name="output">The output path.</param>
|
||||||
|
/// <param name="definitionsPath">The path to the definitions file.</param>
|
||||||
|
public static void Main(string mode, string input, string output, string definitionsPath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(mode))
|
||||||
|
{
|
||||||
|
Console.WriteLine("--mode is required. Type --help for example usage.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode.ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "generatedefinitions":
|
||||||
|
MacroDefinitionTable macroDefinitionTable = MacroDefinitionTable.GenerateFromLegacyBuildSystem(bldFilePath: input);
|
||||||
|
FxMacroDefinitionTable fxMacroDefinitionTable = new FxMacroDefinitionTable(macroDefinitionTable);
|
||||||
|
string serializedDefintions = JsonConvert.SerializeObject(fxMacroDefinitionTable, Formatting.Indented);
|
||||||
|
File.WriteAllText(output, serializedDefintions);
|
||||||
|
break;
|
||||||
|
case "decompile":
|
||||||
|
var decompiler = new FxDecompiler(Utilities.LoadDefinitions(definitionsPath));
|
||||||
|
decompiler.Decompile(
|
||||||
|
inputPath: input,
|
||||||
|
outputPath: output);
|
||||||
|
break;
|
||||||
|
case "compile":
|
||||||
|
var compiler = new FxCompiler(Utilities.LoadDefinitions(definitionsPath));
|
||||||
|
compiler.Compile(
|
||||||
|
inputPath: input,
|
||||||
|
outputPath: output);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
Giants.EffectCompiler/Utilities.cs
Normal file
49
Giants.EffectCompiler/Utilities.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
namespace Giants.EffectCompiler
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using Giants.BinTools.Macro;
|
||||||
|
using Giants.BinTools.Symbol;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
public static class Utilities
|
||||||
|
{
|
||||||
|
public static readonly string[] SplitCharacters = new string[] { " ", "\t" };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the symbolic value of an FX name.
|
||||||
|
/// </summary>
|
||||||
|
public static int GetFxSymbolValue(SymbolTable symbolTable, string symbolName)
|
||||||
|
{
|
||||||
|
if (!symbolTable.TryGetSymbolFromName(
|
||||||
|
KnownSymbolGroupNames.Fx,
|
||||||
|
symbolName,
|
||||||
|
out int symbolValue))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"No symbol definition for '{symbolName}' found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbolValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FxMacroDefinitionTable LoadDefinitions(string definitionPath = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(definitionPath))
|
||||||
|
{
|
||||||
|
using var definitionStream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Program).Namespace}.Definitions.json");
|
||||||
|
if (definitionStream == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Could not load the definition resource.");
|
||||||
|
}
|
||||||
|
|
||||||
|
using var streamReader = new StreamReader(definitionStream);
|
||||||
|
string serializedTable = streamReader.ReadToEnd();
|
||||||
|
return JsonConvert.DeserializeObject<FxMacroDefinitionTable>(serializedTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroDefinitionTable macroDefinitionTable = MacroDefinitionTable.GenerateFromLegacyBuildSystem(bldFilePath: definitionPath);
|
||||||
|
return new FxMacroDefinitionTable(macroDefinitionTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -59,7 +59,7 @@ namespace Giants.Web.Controllers
|
|||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
string requestIpAddress = this.GetRequestIpAddress();
|
string requestIpAddress = this.GetRequestIpAddress();
|
||||||
logger.LogInformation("Returning {Count} servers to {IPAddress}", mappedServers.Count, requestIpAddress);
|
this.logger.LogInformation("Returning {Count} servers to {IPAddress}", mappedServers.Count, requestIpAddress);
|
||||||
|
|
||||||
return mappedServers;
|
return mappedServers;
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ namespace Giants.Web.Controllers
|
|||||||
|
|
||||||
this.logger.LogInformation("Request to add server from {IPAddress}", requestIpAddress);
|
this.logger.LogInformation("Request to add server from {IPAddress}", requestIpAddress);
|
||||||
|
|
||||||
var serverInfoEntity = mapper.Map<Services.ServerInfo>(serverInfo);
|
var serverInfoEntity = this.mapper.Map<Services.ServerInfo>(serverInfo);
|
||||||
serverInfoEntity.HostIpAddress = requestIpAddress.ToString();
|
serverInfoEntity.HostIpAddress = requestIpAddress.ToString();
|
||||||
serverInfoEntity.LastHeartbeat = DateTime.UtcNow;
|
serverInfoEntity.LastHeartbeat = DateTime.UtcNow;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace Giants.WebApi.Controllers
|
|||||||
{
|
{
|
||||||
Services.VersionInfo versionInfo = await this.updaterService.GetVersionInfo(appName);
|
Services.VersionInfo versionInfo = await this.updaterService.GetVersionInfo(appName);
|
||||||
|
|
||||||
return mapper.Map<DataContract.V1.VersionInfo>(versionInfo);
|
return this.mapper.Map<DataContract.V1.VersionInfo>(versionInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoMapper" Version="10.0.0" />
|
<PackageReference Include="AutoMapper" Version="10.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.14.0" />
|
||||||
<PackageReference Include="NSwag.AspNetCore" Version="13.7.0" />
|
<PackageReference Include="NSwag.AspNetCore" Version="13.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace Giants.Web
|
|||||||
{
|
{
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
this.Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
@ -29,7 +29,7 @@ namespace Giants.Web
|
|||||||
services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
|
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
|
||||||
|
|
||||||
ServicesModule.RegisterServices(services, Configuration);
|
ServicesModule.RegisterServices(services, this.Configuration);
|
||||||
|
|
||||||
IMapper mapper = Services.Mapper.GetMapper();
|
IMapper mapper = Services.Mapper.GetMapper();
|
||||||
services.AddSingleton(mapper);
|
services.AddSingleton(mapper);
|
||||||
|
@ -15,6 +15,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Giants.WebApi.Clients", "Gi
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Shaders", "Shaders\Shaders.vcxproj", "{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Shaders", "Shaders\Shaders.vcxproj", "{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Giants.BinTools", "Giants.BinTools\Giants.BinTools.csproj", "{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.EffectCompiler", "Giants.EffectCompiler\Giants.EffectCompiler.csproj", "{F5F3D216-9787-4CFF-88DF-8259CF667F88}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.EffectCompiler.Tests", "Giants.EffectCompiler.Tests\Giants.EffectCompiler.Tests.csproj", "{49423BA5-4A9F-47A3-9D2D-E83936272DD0}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -95,6 +101,42 @@ Global
|
|||||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|x64.Build.0 = Release|x64
|
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|x64.Build.0 = Release|x64
|
||||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|x86.ActiveCfg = Release|Win32
|
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|x86.ActiveCfg = Release|Win32
|
||||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|x86.Build.0 = Release|Win32
|
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
Loading…
Reference in New Issue
Block a user