mirror of
https://github.com/ncblakely/GiantsTools
synced 2024-11-23 22:55:37 +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)
|
||||
*.userprefs
|
||||
launchSettings.json
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
|
@ -1,12 +1,18 @@
|
||||
xcopy "%GIANTS_PATH%\gg_dx7r.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%\GiantsMain.exe" "Files\" /Y
|
||||
xcopy "%GIANTS_PATH%\GiantsDedicated.exe" "Files\" /Y
|
||||
xcopy "%GIANTS_PATH%\gs_ds.dll" "Files\" /Y
|
||||
xcopy "%GIANTS_PATH%\Giants.WebApi.Clients.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%\Newtonsoft.Json.dll" "Files\" /Y
|
||||
xcopy "%GIANTS_PATH%\zlib1.dll" "Files\" /Y
|
||||
|
||||
pause
|
@ -42,7 +42,7 @@ SetCompressor /SOLID lzma
|
||||
; MUI end ------
|
||||
|
||||
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
|
||||
OutFile "Output\GPatch1_498_204_0.exe"
|
||||
OutFile "Output\GPatch1_498_206_0.exe"
|
||||
InstallDir "$PROGRAMFILES\Giants\"
|
||||
InstallDirRegKey HKCU "SOFTWARE\PlanetMoon\Giants" "DestDir"
|
||||
ShowInstDetails hide
|
||||
@ -77,6 +77,7 @@ Section
|
||||
Delete $INSTDIR\gg_dx8r.dll
|
||||
Delete $INSTDIR\gg_dx9r.dll
|
||||
Delete $INSTDIR\Giants.exe
|
||||
Delete $INSTDIR\BugTrap.dll
|
||||
Delete $INSTDIR\GiantsMain.exe
|
||||
Delete $INSTDIR\*.vso
|
||||
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)
|
||||
{
|
||||
return obj is AppVersion info &&
|
||||
Build == info.Build &&
|
||||
Major == info.Major &&
|
||||
Minor == info.Minor &&
|
||||
Revision == info.Revision;
|
||||
this.Build == info.Build &&
|
||||
this.Major == info.Major &&
|
||||
this.Minor == info.Minor &&
|
||||
this.Revision == info.Revision;
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -23,16 +23,16 @@ namespace Giants.DataContract.V1
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is PlayerInfo info &&
|
||||
Index == info.Index &&
|
||||
Name == info.Name &&
|
||||
Frags == info.Frags &&
|
||||
Deaths == info.Deaths &&
|
||||
TeamName == info.TeamName;
|
||||
this.Index == info.Index &&
|
||||
this.Name == info.Name &&
|
||||
this.Frags == info.Frags &&
|
||||
this.Deaths == info.Deaths &&
|
||||
this.TeamName == info.TeamName;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return obj is ServerInfo info &&
|
||||
GameName == info.GameName &&
|
||||
EqualityComparer<AppVersion>.Default.Equals(Version, info.Version) &&
|
||||
SessionName == info.SessionName &&
|
||||
Port == info.Port &&
|
||||
MapName == info.MapName &&
|
||||
GameType == info.GameType &&
|
||||
NumPlayers == info.NumPlayers &&
|
||||
GameState == info.GameState &&
|
||||
TimeLimit == info.TimeLimit &&
|
||||
FragLimit == info.FragLimit &&
|
||||
TeamFragLimit == info.TeamFragLimit &&
|
||||
FirstBaseComplete == info.FirstBaseComplete &&
|
||||
PlayerInfo.SequenceEqual(info.PlayerInfo);
|
||||
this.GameName == info.GameName &&
|
||||
EqualityComparer<AppVersion>.Default.Equals(this.Version, info.Version) &&
|
||||
this.SessionName == info.SessionName &&
|
||||
this.Port == info.Port &&
|
||||
this.MapName == info.MapName &&
|
||||
this.GameType == info.GameType &&
|
||||
this.NumPlayers == info.NumPlayers &&
|
||||
this.GameState == info.GameState &&
|
||||
this.TimeLimit == info.TimeLimit &&
|
||||
this.FragLimit == info.FragLimit &&
|
||||
this.TeamFragLimit == info.TeamFragLimit &&
|
||||
this.FirstBaseComplete == info.FirstBaseComplete &&
|
||||
this.PlayerInfo.SequenceEqual(info.PlayerInfo);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
HashCode hash = new HashCode();
|
||||
hash.Add(GameName);
|
||||
hash.Add(Version);
|
||||
hash.Add(SessionName);
|
||||
hash.Add(Port);
|
||||
hash.Add(MapName);
|
||||
hash.Add(GameType);
|
||||
hash.Add(NumPlayers);
|
||||
hash.Add(GameState);
|
||||
hash.Add(TimeLimit);
|
||||
hash.Add(FragLimit);
|
||||
hash.Add(TeamFragLimit);
|
||||
hash.Add(FirstBaseComplete);
|
||||
hash.Add(PlayerInfo);
|
||||
hash.Add(this.GameName);
|
||||
hash.Add(this.Version);
|
||||
hash.Add(this.SessionName);
|
||||
hash.Add(this.Port);
|
||||
hash.Add(this.MapName);
|
||||
hash.Add(this.GameType);
|
||||
hash.Add(this.NumPlayers);
|
||||
hash.Add(this.GameState);
|
||||
hash.Add(this.TimeLimit);
|
||||
hash.Add(this.FragLimit);
|
||||
hash.Add(this.TeamFragLimit);
|
||||
hash.Add(this.FirstBaseComplete);
|
||||
hash.Add(this.PlayerInfo);
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
}
|
||||
|
@ -12,14 +12,14 @@
|
||||
{
|
||||
return obj is ServerInfoWithHostAddress address &&
|
||||
base.Equals(obj) &&
|
||||
HostIpAddress == address.HostIpAddress;
|
||||
this.HostIpAddress == address.HostIpAddress;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
HashCode hash = new HashCode();
|
||||
hash.Add(base.GetHashCode());
|
||||
hash.Add(HostIpAddress);
|
||||
hash.Add(this.HostIpAddress);
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
@ -73,7 +73,7 @@ namespace Giants.Web.Controllers
|
||||
|
||||
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.LastHeartbeat = DateTime.UtcNow;
|
||||
|
||||
|
@ -25,7 +25,7 @@ namespace Giants.WebApi.Controllers
|
||||
{
|
||||
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>
|
||||
<PackageReference Include="AutoMapper" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.14.0" />
|
||||
<PackageReference Include="NSwag.AspNetCore" Version="13.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace Giants.Web
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
this.Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
@ -29,7 +29,7 @@ namespace Giants.Web
|
||||
services.AddHttpContextAccessor();
|
||||
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
|
||||
|
||||
ServicesModule.RegisterServices(services, Configuration);
|
||||
ServicesModule.RegisterServices(services, this.Configuration);
|
||||
|
||||
IMapper mapper = Services.Mapper.GetMapper();
|
||||
services.AddSingleton(mapper);
|
||||
|
@ -15,6 +15,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Giants.WebApi.Clients", "Gi
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Shaders", "Shaders\Shaders.vcxproj", "{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}"
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|x86.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
Loading…
Reference in New Issue
Block a user