Add binary tools assembly and FX decompiler.

This commit is contained in:
Nick Blakely 2020-09-05 16:47:00 -07:00
parent 1f4d4e846c
commit d2bc9454ed
44 changed files with 9407 additions and 47 deletions

1
.gitignore vendored
View File

@ -14,6 +14,7 @@ profile.arm.json
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
launchSettings.json
# Build results
[Dd]ebug/

View File

@ -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
xcopy "%GIANTS_PATH%\zlib1.dll" "Files\" /Y
pause

View File

@ -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

View 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');
}
}
}

View 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>

View 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();
}
}
}
}

View File

@ -0,0 +1,7 @@
namespace Giants.BinTools.Macro
{
public class ElseMacroLine : MacroLine
{
public MacroLineType Type => MacroLineType.Else;
}
}

View File

@ -0,0 +1,7 @@
namespace Giants.BinTools.Macro
{
public class EndIfMacroLine : MacroLine
{
public MacroLineType Type => MacroLineType.EndIf;
}
}

View 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() { }
}
}

View 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() { }
}
}

View File

@ -0,0 +1,7 @@
namespace Giants.BinTools.Macro
{
public static class KnownMacroGroupNames
{
public const string FxDefGroup = "fxdefgroup";
}
}

View 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;
}
}
}

View 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);
}
}
}
}
}

View 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() { }
}
}

View 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";
}
}

View File

@ -0,0 +1,10 @@
using Newtonsoft.Json;
namespace Giants.BinTools.Macro
{
[JsonConverter(typeof(MacroLineJsonConverter))]
public interface MacroLine
{
public MacroLineType Type { get; }
}
}

View 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,
};
}
}
}

View 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();
}
}
}

View File

@ -0,0 +1,12 @@
namespace Giants.BinTools.Macro
{
public enum MacroLineType
{
None = 0,
DataDefinition,
If,
Else,
EndIf,
GroupUse
}
}

View 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) { }
}
}
}

View File

@ -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()

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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>

View File

@ -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));
}
}
}
}

Binary file not shown.

View File

@ -0,0 +1,8 @@
namespace Giants.EffectCompiler
{
public class ContentEntry
{
public string Name { get; set; }
public int Offset { get; set; }
}
}

View 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,
};
}
}
}

View 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>();
}
}

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

View 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; }
}
}

View 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;
}
}
}

View 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>

View 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>

View 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;
}
}
}
}

View 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);
}
}
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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);

View File

@ -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