JD2022-TU1/main/tools/apps/DjRedoConsole/DjRedoProgram.cs

492 lines
20 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Media;
using System.Net;
using System.Text;
using System.Threading;
using DjRedo.Core;
using DjRedo.Core.Configuration;
using DjRedo.Core.Extensions;
using DjRedo.Core.Managers;
using DjRedo.Core.Trees;
using DjRedoConsole.TplTemplates;
using JD.Serialization;
using Microsoft.Win32;
using NLog;
using NLog.Conditions;
using NLog.Targets;
using Waapinet.Core;
using Waapinet.Core.GeneratedWwiseApi;
using WaapiNet.Ak;
using WaapiNet.Wwise.Objects;
namespace DjRedo.Console
{
public static class DjRedoProgram
{
private static readonly ILogger Logs = LogManager.GetCurrentClassLogger();
/// <summary>
/// Method starter
/// </summary>
/// <param name="args"></param>
static void Main(params string[] args)
{
ConfigureNLog();
DjRedoArgsManager.Current.Initialize(args);
CatchAllUnHandledException();
System.Media.SoundPlayer sound = new System.Media.SoundPlayer(Resources.BreizhMaBro);
if (DjRedoArgsManager.Current.IsBreizhMaBro)
{
sound.Play();
Logs.Info("En avant Guigamp!");
Logs.Info(@"
! ! ! !
! ! ! ████████████
! ! ! !
████████████████████
████████████████████
████████████████████");
}
if (DjRedoArgsManager.Current.CleanAudioTplFiles)
{
PerforceInfos infos = new PerforceInfos();
DjRedoTreeManager.Current.BuildPerforceTree(infos);
List<AudioNode> tplToRefactor = new List<AudioNode>();
DjRedoTreeManager.Current.Tree.Seed.Traverse(node => Visitor(node, tplToRefactor));
int currentFile = 0;
//I need to exclude the tpl that are related to a trk file because tempoblaster needs the trk files
var filteredTplToRefactor = tplToRefactor.Select(node =>
{
try
{
//LoadTpl
var serializer = new LuaSerializer
{
IgnoreDefaultValues = true
};
return new
{
AudioNode = node,
Serializer = serializer,
Tpl = (Actor_Template)serializer.LoadObjectFromFile(node.DiskPath.Path, typeof(Actor_Template))
};
}
catch (Exception e)
{
Logs.Error(node.DiskPath.Path);
File.AppendAllLines("RefactoReport.log", new[]
{
"#######################################################################################################",
$"{node.DiskPath.Path} couldn't be read",
e.Message,
"#######################################################################################################"
});
return null;
}
}).Where(a => a != null && !a.Tpl.__AdditionalInstructions.Any(i => i.Instruction.EndsWith(".trk\")\r"))).ToArray();
foreach (var audioNode in filteredTplToRefactor)
{
audioNode.Serializer.InitializeEngineTypes();
//I remove the tablepath from the components
foreach (ActorComponent_Template component in audioNode.Tpl.COMPONENTS)
{
component.__TablePath = null;
}
//remove all the additionalInstruction
audioNode.Tpl.__AdditionalInstructions.Clear();
//Add the sound_base reference
audioNode.Tpl.__AdditionalInstructions.Add(new SpecialCustomTypeDescriptor.AdditionalInstruction("includeReference(\"EngineData/Helpers/sound_base.ilu\")", 0));
//Checkout tpl file
DjRedoPerforceManager.Current.CheckoutFile(audioNode.AudioNode.DiskPath.Path, "RefactoCL");
//write into the file the virgin content
File.WriteAllText(audioNode.AudioNode.DiskPath.Path, new VirginTpl().TransformText(), Encoding.UTF8);
//save the tpl into the file
audioNode.Serializer.SaveObjectToFile(audioNode.Tpl, audioNode.AudioNode.DiskPath.Path);
//check that the first line is the includeReference("EngineData/Helpers/sound_base.ilu")
if (File.ReadLines(audioNode.AudioNode.DiskPath.Path).First() != "includeReference(\"EngineData/Helpers/sound_base.ilu\")")
{
throw new Exception("The first line does not match expectation");
}
DrawTextProgressBar(++currentFile, filteredTplToRefactor.Length);
}
}
else
{
#region Check that wwise is alive
Logs.Info("Check that wwise is alive");
string WwiseProcessName = "Wwise";
string wwisePath = $"{Environment.GetEnvironmentVariable("WWISEROOT")}\\Authoring\\x64\\Release\\bin\\Wwise.exe";
Process[] wwiseProcess = Process.GetProcessesByName(WwiseProcessName);
if (!wwiseProcess.Any())
{
//wwise is not started and should be
try
{
bool isWwiseInstalled = false;
string registry_key = @"SOFTWARE\Audiokinetic Inc.\Wwise";
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subkey_name))
{
isWwiseInstalled = true;
}
}
}
if (isWwiseInstalled)
{
//
// Setup the process with the ProcessStartInfo class.
//
ProcessStartInfo start = new ProcessStartInfo
{
FileName = wwisePath,
UseShellExecute = false,
RedirectStandardOutput = true,
};
Process p = Process.Start(start);
p.OutputDataReceived += WwiseProcessOutputDataReceived;
}
else
{
throw new Exception("Please Installed Wwise before trying to start it");
}
}
catch (NullReferenceException)
{
}
}
Logs.Info("Alive!");
#endregion
#region Deserialize DjRedoConfiguration
DjRedoBindingManager.Current.Initialize(DjRedoConfigurationManager.Current.Configuration.ExtractBindingsIncludingProviders());
#endregion
#region Build the Perforce tree and extract the nodes to push to Wwise
Logs.Info("Build the Perforce tree and extract the nodes to push to Wwise");
PerforceInfos infos = new PerforceInfos();
DjRedoTreeManager.Current.BuildPerforceTree(infos);
int numberOfNodes = 0;
if (DjRedoTreeManager.Current.Tree.HasBeenBuilt)
{
numberOfNodes = DjRedoTreeManager.Current.Tree.Where(DjRedoTreeManager.IsValidNode).Count();
}
Logs.Info($"Done! node number: {numberOfNodes}");
#endregion
#region Start using Wwise Service
using (IWwiseService wwiseService = WwiseChannelFactory.CreateChannel<IWwiseService>(new DnsEndPoint(DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.WwiseEndpoint.Uri, DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.WwiseEndpoint.Port)))
{
try
{
#region Open WwiseProject
Logs.Info($"Opening JD Wwise project");
wwiseService.Ui.BringToForeground();
//watch out we bypass the save so the previous work might be erased
wwiseService.Ui.Project.Open(infos.WwiseProjectPath, OnUpgradeValues.Migrate, _bypasssave: true);
Logs.Info($"JD Wwise project openned");
#endregion
#region Extract all plateforms to work on. JD uses only windows plateform
Logs.Info("Fetching all declared platforms");
IPlatform[] allPlatforms = (IPlatform[])wwiseService.Core.Object.Get(FromFactory.StringOfType(WwiseObjectReference.PlatformObjectReference));
Guid windowsPlatformId = allPlatforms.Single(p => p.Name == "Windows").Id;
foreach (IPlatform platform in allPlatforms)
{
Logs.Info($"Platform found: {platform.Name} ({platform.Id})");
}
#endregion
#region Initialize wwise service for managers
Logs.Info("Start and Initialize managers");
DjRedoTreeManager.Current.InitializeWwiseService(wwiseService);
DjRedoWwiseSelectionManager.Current.InitializeWwiseService(wwiseService);
DjRedoBindingManager.Current.InitializeWwiseService(wwiseService);
DjRedoTplLoadManager.Current.InitializeWwiseService(wwiseService);
DjRedoTplFlushManager.Current.InitializeWwiseService(wwiseService);
DjRedoWwiseAssetUpdater.Current.InitializeWwiseService(wwiseService);
DjRedoChildrenManager.Current.InitializeWwiseService(wwiseService);
DjRedoAssetManager.Current.InitializeWwiseService(wwiseService);
//Todo activate this manager as soon as the profiler receiving the datas has been identified
//DjRedoWwiseMessageManager.Current.InitializeWwiseService(wwiseService);
Logs.Info("Managers ready");
#endregion
DjRedoWwiseMessageManager.Current.PostMessage("Ceci est un test");
#region clean Wwise buses
Logs.Info("Start cleaning Wwise buses");
object allBuses = wwiseService.Core.Object.Get(FromFactory.Path(DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.MasterMixerHierarchyPath), TransformFactory.InitialTransform(TransformFactory.Select(SelectType.Children)));
CleanWwiseHierarchy(wwiseService, allBuses);
Logs.Info("Wwise buses cleaned");
#endregion
#region clean Wwise tree
object allChildren = wwiseService.Core.Object.Get(FromFactory.Path(DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.ActorMixerHierarchyPath), TransformFactory.InitialTransform(TransformFactory.Select(SelectType.Children)));
CleanWwiseHierarchy(wwiseService, allChildren);
#endregion
#region Extract all buses and push them into the Master-Mixer hierarchy
Logs.Info("Extract buses from SoundConfig");
var serializer = new LuaSerializer();
serializer.InitializeEngineTypes();
SoundConfig_Template rakiBuses = (SoundConfig_Template)serializer.LoadObjectFromFile(DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.SoundConfigPath, typeof(SoundConfig_Template));
if (rakiBuses != null)
{
Logs.Info("Generate bus tree");
DjRedoBindingManager.Current.Buses = GenerateBusHierarchy(rakiBuses.Busses.ToArray());
DjRedoBindingManager.Current.Buses.Traverse(node =>
{
if (node.BusDef.Name != "master")
{
string fullNodePath = $"{DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.MasterMixerHierarchyPath}\\{node.WwisePath}".TrimEnd('\\');
wwiseService.Core.Object.Create(node.BusDef.Name, fullNodePath, _platform: windowsPlatformId, _purpletype: WwiseObjectReference.BusObjectReference.RealName);
object createdBus = wwiseService.Core.Object.Get(FromFactory.Path($"{fullNodePath}\\{node.BusDef.Name}".TrimEnd('\\')));
node.WwiseBus = (IBus)createdBus;
}
else
{
node.WwiseBus = (IBus)wwiseService.Core.Object.Get(FromFactory.Path(DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.MasterMixerHierarchyPath));
}
});
Logs.Info("Bus tree done");
}
#endregion
#region create Wwise treeView
Logs.Info("Createaudio tree");
DjRedoTreeManager.Current.CreateWwiseTreeView(windowsPlatformId, (i, node) =>
{
DrawTextProgressBar(i, numberOfNodes);
});
#endregion
#region Save project
wwiseService.Core.Project.Save();
#endregion
}
catch (Exception ex)
{
StringBuilder sb = new StringBuilder(ex.Message);
sb.Append(ex.StackTrace);
Logs.Debug(sb.ToString());
}
if (DjRedoArgsManager.Current.IsBreizhMaBro)
{
sound.Stop();
}
while (true)
{
Thread.Sleep(10);
}
#region CleanEverything
//DjRedoWwiseSelectionManager.Current.Dispose();
#endregion
}
#endregion
}
}
private static void Visitor(AudioNode n, List<AudioNode> audioNodes)
{
if (n.IsOnDisk && n.NodeType == NodeType.File && new FileInfo(n.DiskPath.Path).Extension == ".tpl")
{
audioNodes.Add(n);
}
}
public static bool CleanTplFile { get; private set; }
private static void CleanWwiseHierarchy(IWwiseService wwiseService, object allBuses)
{
if (allBuses == null) return;
if (allBuses.GetType().IsArray)
{
IObjectReturn[] allValue = allBuses as IObjectReturn[];
if (allValue == null) return;
for (int i = 0; i < allValue.Length; i++)
{
IObjectReturn objectReturn = allValue[i];
wwiseService.Core.Object.Delete(objectReturn.Path);
DrawTextProgressBar(i, allValue.Length);
}
}
else
{
IObjectReturn child = allBuses as IObjectReturn;
if (child != null)
{
wwiseService.Core.Object.Delete(child.Path);
}
}
}
private static void DrawTextProgressBar(int progress, int total)
{
//draw empty progress bar
System.Console.CursorLeft = 0;
System.Console.Write("["); //start
System.Console.CursorLeft = 32;
System.Console.Write("]"); //end
System.Console.CursorLeft = 1;
float onechunk = 30.0f / total;
//draw filled part
int position = 1;
for (int i = 0; i < onechunk * progress; i++)
{
System.Console.BackgroundColor = ConsoleColor.Gray;
System.Console.CursorLeft = position++;
System.Console.Write(" ");
}
//draw unfilled part
for (int i = position; i <= 31; i++)
{
System.Console.BackgroundColor = ConsoleColor.Green;
System.Console.CursorLeft = position++;
System.Console.Write(" ");
}
//draw totals
System.Console.CursorLeft = 35;
System.Console.BackgroundColor = ConsoleColor.Black;
System.Console.Write(progress.ToString() + " of " + total.ToString() + " "); //blanks at the end remove any excess
}
private static void WwiseProcessOutputDataReceived(object sender, DataReceivedEventArgs e)
{
Debug.WriteLine($"Wwise process is talking: {e.Data}");
}
private static readonly Dictionary<string, BusNode> m_currentBusesState = new Dictionary<string, BusNode>();
private static BusNode GenerateBusHierarchy(BusDef[] rakiBuses)
{
BusNode[] busNodes = rakiBuses.Select(b => new BusNode(b)).ToArray();
foreach (BusNode busNode in busNodes)
{
m_currentBusesState.Add(busNode.BusDef.Name ?? "master", busNode);
}
SortBusesByParents();
return m_currentBusesState.First().Value;
}
private static void SortBusesByParents()
{
foreach (KeyValuePair<string, BusNode> pair in m_currentBusesState)
{
BusNode def = pair.Value;
if (def.BusDef.Outputs.Any() && def.BusDef.Outputs.First() != "")
{
def.Parent = m_currentBusesState[def.BusDef.Outputs.First()];
// add the bus to his parent's children list
m_currentBusesState[def.BusDef.Outputs.First()].Children.Add(def.BusDef.Name, def);
}
}
KeyValuePair<string, BusNode>[] allToRemove = m_currentBusesState.Where(b => b.Key != "master").ToArray();
foreach (KeyValuePair<string, BusNode> keyValuePair in allToRemove)
{
m_currentBusesState.Remove(keyValuePair.Key);
}
}
private static void CatchAllUnHandledException()
{
System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
}
static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e)
{
Logs.Error((Exception)e.ExceptionObject, "Exception unhandled");
}
private static void ConfigureNLog()
{
var config = new NLog.Config.LoggingConfiguration();
var logconsole = new NLog.Targets.ColoredConsoleTarget("logconsole");
var highlightRule = new ConsoleRowHighlightingRule
{
Condition = ConditionParser.ParseExpression("level == LogLevel.Debug"),
ForegroundColor = ConsoleOutputColor.Yellow,
};
logconsole.RowHighlightingRules.Add(highlightRule);
#if DEBUG
config.AddRule(LogLevel.Debug, LogLevel.Fatal, logconsole);
#else
config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole);
#endif
NLog.LogManager.Configuration = config;
}
}
}