492 lines
20 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|