namespace Giants.EffectCompiler
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Giants.BinTools.Macro;
using NLog;
///
/// Effect binary compiler.
///
public class FxCompiler
{
private static readonly Logger logger = LogManager.GetLogger(nameof(FxCompiler));
private FxMacroDefinitionTable macroDefinitionTable;
private int doneOpcode;
///
/// Initializes a new instance of the class.
///
/// The table of macro and symbol definitions.
public FxCompiler(FxMacroDefinitionTable macroDefinitionTable)
{
this.macroDefinitionTable = macroDefinitionTable;
}
///
/// Compiles a textual effect file to the specified output path.
///
/// The path to the effect file.
/// The path to write to.
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