JD2022-TU1/main/tools/modules/JD.DjRedo/Core/DjRedoLauncher.cs

470 lines
No EOL
23 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using DjRedo.Controls;
using DjRedo.Core.Configuration;
using DjRedo.Core.Extensions;
using DjRedo.Core.Managers;
using DjRedo.Core.Trees;
using DjRedo.ViewModels;
using JD.Serialization;
using Microsoft.Win32;
using NLog;
using Plume.Interfaces.WPF.Modules;
using Plume.Perforce.Service.Api;
using Waapinet.Core;
using Waapinet.Core.GeneratedWwiseApi;
using WaapiNet.Ak;
using WaapiNet.Wwise.Objects;
namespace DjRedo.Core
{
public class DjRedoLauncher : IDjRedoStepProvider
{
private Dispatcher _dispatcher;
private IWpfModuleContext _context;
private static readonly ILogger Logs = LogManager.GetCurrentClassLogger();
private Process _currentWwiseProcess;
private static void WwiseProcessOutputDataReceived(object sender, DataReceivedEventArgs e)
{
Debug.WriteLine($"Wwise process is talking: {e.Data}");
}
private async Task CleanWwiseHierarchy(IStepData stepData,IWwiseService wwiseService, object allBuses)
{
if (allBuses == null) return;
await Task.Factory.StartNew(() =>
{
if (allBuses.GetType().IsArray)
{
if (!(allBuses is IObjectReturn[] allValue)) return;
float stepDataProgress = 100f / allValue.Length;
foreach (IObjectReturn objectReturn in allValue)
{
wwiseService.Core.Object.Delete(objectReturn.Path);
stepData.Progress += stepDataProgress;
}
}
else
{
if (allBuses is IObjectReturn child)
{
wwiseService.Core.Object.Delete(child.Path);
}
}
});
}
private static BusNode GenerateBusHierarchy(DjRedoLauncherContext context, BusDef[] rakiBuses)
{
BusNode[] busNodes = rakiBuses.Select(b => new BusNode(b)).ToArray();
foreach (BusNode busNode in busNodes)
{
context.CurrentBusesState.Add(busNode.BusDef.Name ?? "master", busNode);
}
SortBusesByParents(context);
return context.CurrentBusesState.First().Value;
}
private static void SortBusesByParents(DjRedoLauncherContext context)
{
foreach (KeyValuePair<string, BusNode> pair in context.CurrentBusesState)
{
BusNode def = pair.Value;
if (def.BusDef.Outputs.Any() && def.BusDef.Outputs.First() != "")
{
def.Parent = context.CurrentBusesState[def.BusDef.Outputs.First()];
// add the bus to his parent's children list
context.CurrentBusesState[def.BusDef.Outputs.First()].Children.Add(def.BusDef.Name, def);
}
}
KeyValuePair<string, BusNode>[] allToRemove = context.CurrentBusesState.Where(b => b.Key != "master").ToArray();
foreach (KeyValuePair<string, BusNode> keyValuePair in allToRemove)
{
context.CurrentBusesState.Remove(keyValuePair.Key);
}
}
/// <inheritdoc />
public RunnableStepTaskCollection ProvideSteps(Dispatcher dispatcher)
{
_dispatcher = dispatcher;
StepTask[] allSteps =
{
new StepTask(new DjRedoStepViewModel(1 , "Chech Wwise Alive", "Check Wwise Alive", infinitespin: true), CheckWwiseAlive),
new StepTask(new DjRedoStepViewModel(2 , "Deserialize DjRedoConfiguration", "Deserialize DjRedoConfiguration", infinitespin: true), DeserializeConfiguration),
new StepTask(new DjRedoStepViewModel(3 , "Build P4 tree", "Build P4 tree", infinitespin: true), BuildP4Tree),
new StepTask(new DjRedoStepViewModel(4 , "Extract Nodes to push to wwise", "Extract Nodes to push to wwise", infinitespin: true), ExtractNodes),
new StepTask(new DjRedoStepViewModel(5 , "Open Wwise Project", "Open Wwise Project", infinitespin: true), OpenWwise),
new StepTask(new DjRedoStepViewModel(6 , "Extract Windows plateform", "Extract Windows plateform", infinitespin: true), ExtractWindowsPlatform),
new StepTask(new DjRedoStepViewModel(7 , "Initialize Wwise service managers", "Initialize Wwise service managers"), InitializeManagers),
new StepTask(new DjRedoStepViewModel(8 , "Clean Wwise Buses", "Clean Wwise Buses", infinitespin: true), CleanBuses),
new StepTask(new DjRedoStepViewModel(9 , "Clean audio tree", "Clean Wwise tree", infinitespin: true), CleanAudioNodes),
new StepTask(new DjRedoStepViewModel(10, "Push buses to wwise", "Push buses to wwise"), PushBusesToWwise),
new StepTask(new DjRedoStepViewModel(11, "Create Wwise audio tree", "Create Wwise audio tree"), PushAudioNodesToWwise),
new StepTask(new DjRedoStepViewModel(12, "Save Project", "Save Project", infinitespin: true), SaveProject),
new StepTask(new DjRedoStepViewModel(SocketListenningOrder, "Listen to Wwise", "Listen to Wwise - READY to work", infinitespin: true), ListenToWwise),
new StepTask(new DjRedoStepViewModel(14, "Close Wwise channel", "Close Wwise channel", infinitespin: true), CloseWwiseChannel),
};
return new RunnableStepTaskCollection(allSteps);
}
public const int SocketListenningOrder = 13;
private async Task<object[]> CheckWwiseAlive(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
Logs.Info("Check that wwise is alive");
string WwiseProcessName = "Wwise";
string wwisePath = $"{Environment.GetEnvironmentVariable("WWISEROOT")}\\Authoring\\x64\\Release\\bin\\Wwise.exe";
await Task.Factory.StartNew(() =>
{
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,
};
_currentWwiseProcess?.Kill();
_currentWwiseProcess = Process.Start(start);
_currentWwiseProcess.OutputDataReceived += WwiseProcessOutputDataReceived;
}
else
{
throw new Exception("Please Installed Wwise before trying to start it");
}
}
catch (NullReferenceException)
{
}
}
});
Logs.Info("Alive!");
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return new object[]{ new DjRedoLauncherContext()};
}
private async Task<object[]> DeserializeConfiguration(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
await Task.Factory.StartNew(() =>
DjRedoBindingManager.Current.Initialize(DjRedoConfigurationManager.Current.Configuration.ExtractBindingsIncludingProviders()));
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> BuildP4Tree(IStepData stepdata, object[] parameters)
{
DjRedoLauncherContext context = (DjRedoLauncherContext) parameters.First();
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
Logs.Info("Build the Perforce tree and extract the nodes to push to Wwise");
IPerforceService perforceService = _context.ServiceManager.Get<IPerforceService>();
if (perforceService == null)
{
throw new Exception("The perforce service is missing");
}
context.DatasInfos = new DatasInfos(perforceService);
await DjRedoTreeManager.Current.BuildPerforceTree(context.DatasInfos);
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> ExtractNodes(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
int numberOfNodes = 0;
if (DjRedoTreeManager.Current.Tree.HasBeenBuilt)
{
numberOfNodes = await Task.Factory.StartNew(()=>
{
int count = DjRedoTreeManager.Current.Tree.Yield().Count(DjRedoTreeManager.IsValidNode);
return count;
});
context.ExtractedNodeCount = numberOfNodes;
}
Logs.Info($"Done! node number: {numberOfNodes}");
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> OpenWwise(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
DjRedoPerforceManager.Current.CheckoutWwiseProject(context.DatasInfos);
context.WwiseService = await Task.Factory.StartNew(() =>
{
return WwiseChannelFactory.CreateChannel<IWwiseService>(new DnsEndPoint(
DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.WwiseEndpoint.Uri,
DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.WwiseEndpoint.Port));
});
Logs.Info($"Opening JD Wwise project");
await Task.Factory.StartNew(() =>
{
context.WwiseService.Ui.BringToForeground();
//watch out we bypass the save so the previous work might be erased
context.WwiseService.Ui.Project.Open(context.DatasInfos.WwiseProjectPath, OnUpgradeValues.Migrate, _bypasssave: true);
});
Logs.Info($"JD Wwise project openned");
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> ExtractWindowsPlatform(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
Logs.Info("Fetching all declared platforms");
await Task.Factory.StartNew(() =>
{
IPlatform[] allPlatforms =
(IPlatform[]) context.WwiseService.Core.Object.Get(FromFactory.StringOfType(WwiseObjectReference.PlatformObjectReference));
context.WindowsPlatformId = allPlatforms.Single(p => p.Name == "Windows").Id;
foreach (IPlatform platform in allPlatforms)
{
Logs.Info($"Platform found: {platform.Name} ({platform.Id})");
}
});
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> InitializeManagers(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
Logs.Info("Start and Initialize managers");
DjRedoTreeManager.Current.InitializeWwiseService(context.WwiseService);
const float managerCount = 8f;
const float managersStepProgress = 100 / managerCount;
await _dispatcher.InvokeAsync(() => stepdata.Progress += managersStepProgress);
DjRedoWwiseSelectionManager.Current.InitializeWwiseService(context.WwiseService);
await _dispatcher.InvokeAsync(() => stepdata.Progress += managersStepProgress);
DjRedoBindingManager.Current.InitializeWwiseService(context.WwiseService);
await _dispatcher.InvokeAsync(() => stepdata.Progress += managersStepProgress);
DjRedoTplLoadManager.Current.InitializeWwiseService(context.WwiseService);
await _dispatcher.InvokeAsync(() => stepdata.Progress += managersStepProgress);
DjRedoTplFlushManager.Current.InitializeWwiseService(context.WwiseService);
await _dispatcher.InvokeAsync(() => stepdata.Progress += managersStepProgress);
DjRedoWwiseAssetUpdater.Current.InitializeWwiseService(context.WwiseService);
await _dispatcher.InvokeAsync(() => stepdata.Progress += managersStepProgress);
DjRedoChildrenManager.Current.InitializeWwiseService(context.WwiseService);
await _dispatcher.InvokeAsync(() => stepdata.Progress += managersStepProgress);
DjRedoAssetManager.Current.InitializeWwiseService(context.WwiseService);
await _dispatcher.InvokeAsync(() => stepdata.Progress += managersStepProgress);
//Todo activate this manager as soon as the profiler receiving the datas has been identified
//DjRedoWwiseMessageManager.Current.InitializeWwiseService(wwiseService);
Logs.Info("Managers ready");
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> CleanBuses(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
Logs.Info("Start cleaning Wwise buses");
object allBuses = await Task.Factory.StartNew(()=>
{
return context.WwiseService.Core.Object.Get(
FromFactory.Path(DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.MasterMixerHierarchyPath),
TransformFactory.InitialTransform(TransformFactory.Select(SelectType.Children)));
});
await CleanWwiseHierarchy(stepdata, context.WwiseService, allBuses);
Logs.Info("Wwise buses cleaned");
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> CleanAudioNodes(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
object allChildren = await Task.Factory.StartNew(() =>
{
return context.WwiseService.Core.Object.Get(
FromFactory.Path(DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.ActorMixerHierarchyPath),
TransformFactory.InitialTransform(TransformFactory.Select(SelectType.Children)));
});
await CleanWwiseHierarchy(stepdata, context.WwiseService, allChildren);
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> PushBusesToWwise(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
Logs.Info("Extract buses from SoundConfig");
await Task.Factory.StartNew(async () =>
{
var serializer = new LuaSerializer();
serializer.InitializeEngineTypes();
//"D:\\JD_DATA_STREAM\\JD2020\\data\\EngineData\\GameConfig\\soundconfig.isg"
string wwiseConfigurationSoundConfigPath = DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.SoundConfigPath;
string soundconfigPath = System.IO.Path.Combine(context.DatasInfos.ProjectRoot,
context.DatasInfos.DiskRootFolder, wwiseConfigurationSoundConfigPath);
Logs.Info($"SoundConfig path: {soundconfigPath}");
SoundConfig_Template rakiBuses = (SoundConfig_Template)serializer.LoadObjectFromFile(soundconfigPath, typeof(SoundConfig_Template));
if (rakiBuses != null)
{
Logs.Info("Generate bus tree");
BusDef[] busDefs = rakiBuses.Busses.ToArray();
DjRedoBindingManager.Current.Buses = GenerateBusHierarchy(context, busDefs);
await DjRedoBindingManager.Current.Buses.TraverseAsync(async node =>
{
if (node.BusDef.Name != "master")
{
string fullNodePath = $"{DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.MasterMixerHierarchyPath}\\{node.WwisePath}".TrimEnd('\\');
context.WwiseService.Core.Object.Create(node.BusDef.Name, fullNodePath, _platform: context.WindowsPlatformId, _purpletype: WwiseObjectReference.BusObjectReference.RealName);
object createdBus = context.WwiseService.Core.Object.Get(FromFactory.Path($"{fullNodePath}\\{node.BusDef.Name}".TrimEnd('\\')));
node.WwiseBus = (IBus)createdBus;
}
else
{
node.WwiseBus = (IBus)context.WwiseService.Core.Object.Get(FromFactory.Path(DjRedoConfigurationManager.Current.Configuration.WwiseConfiguration.MasterMixerHierarchyPath));
}
await _dispatcher.InvokeAsync(() => stepdata.Progress += 100f / busDefs.Length);
});
Logs.Info("Bus tree done");
}
});
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> PushAudioNodesToWwise(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
Logs.Info("Createaudio tree");
int fileNode = 0;
await DjRedoTreeManager.Current.CreateWwiseTreeView(context.WindowsPlatformId, async (i, node) =>
{
if (node.LoadedTpl != null)
{
await _dispatcher.InvokeAsync(() => stepdata.Progress += ++fileNode / (float)context.ExtractedNodeCount);
}
});
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> SaveProject(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
context.WwiseService.Core.Project.Save();
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> ListenToWwise(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
while (stepdata.State == DjRedoStepState.Started)
{
await Task.Delay(10);
}
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
private async Task<object[]> CloseWwiseChannel(IStepData stepdata, object[] parameters)
{
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Started);
DjRedoLauncherContext context = (DjRedoLauncherContext)parameters.First();
context.WwiseService.CloseRelatedChannel();
DjRedoConfigurationManager.Current.Reset();
DjRedoPerforceManager.Current.CleanWwiseProject(context.DatasInfos);
_currentWwiseProcess.Kill();
_currentWwiseProcess = null;
Application.Current.Shutdown();
await _dispatcher.InvokeAsync(() => stepdata.State = DjRedoStepState.Successed);
return parameters;
}
public void Initialize(IWpfModuleContext context)
{
_context = context;
}
}
public class DjRedoLauncherContext
{
public Dictionary<string, BusNode> CurrentBusesState { get; } = new Dictionary<string, BusNode>();
public IWwiseService WwiseService { get; set; }
public DatasInfos DatasInfos { get; set; }
public int ExtractedNodeCount { get; set; }
public Guid WindowsPlatformId { get; set; }
}
}