using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Threading; using DjRedo.Controls; using DjRedo.Core.Configuration; using DjRedo.Core.Managers; using DjRedo.Core.Trees; using DjRedo.TplTemplates; using DjRedo.ViewModels; using JD.Serialization; using NLog; using Plume.Interfaces.WPF.Modules; using Plume.Perforce.Service.Api; namespace DjRedo.Core { public class TplCleaner : IDjRedoStepProvider { private Dispatcher _dispatcher; private IWpfModuleContext _context; private static readonly ILogger Logs = LogManager.GetCurrentClassLogger(); private async Task BuildPerforcetree(IStepData stepData, params object[] parameters) { await _dispatcher.InvokeAsync(() => stepData.State = DjRedoStepState.Started); DatasInfos infos = new DatasInfos(_context.ServiceManager.Get() ?? throw new Exception("Perforce service is missing")); await DjRedoTreeManager.Current.BuildPerforceTree(infos); await _dispatcher.InvokeAsync(() => { stepData.Progress = 100; stepData.State = DjRedoStepState.Successed; }); return new object[0]; } private async Task CreateAssetTree(IStepData stepData, params object[] parameters) { await _dispatcher.InvokeAsync(() => stepData.State = DjRedoStepState.Started); AudioNode[] tplToRefactor = await ProvideTplToRefactor(stepData); await _dispatcher.InvokeAsync(() => stepData.State = DjRedoStepState.Successed); return tplToRefactor.Cast().ToArray(); } private async Task ProvideTplToRefactor(IStepData stepData) { return await Task.Factory.StartNew(() => { int nodeCount = 0; return DjRedoTreeManager.Current.Tree.Where(node => { _dispatcher.BeginInvoke((System.Action)(() => { int progressPercent = (int)((++nodeCount / (float)DjRedoTreeManager.Current.Tree.NodeCount) * 100); stepData.Progress = progressPercent; })); return CheckNode(node); }).ToArray(); }); } /// /// I need to exclude the tpl that are related to a trk file because tempoblaster needs the trk files /// /// /// /// private async Task ExludeTplRelatedToTrk(IStepData stepData, params object[] parameters) { await _dispatcher.InvokeAsync(() => stepData.State = DjRedoStepState.Started); object[] result = await ExcludeTplWithTrk(parameters.Cast(), parameters.Length, stepData); await _dispatcher.InvokeAsync(() => stepData.State = DjRedoStepState.Successed); return result; } private async Task ExcludeTplWithTrk(IEnumerable allNodesToFilter, int nodeToFilterCount, IStepData currentStep) { return await Task.Factory.StartNew(() => { int nodeCount = 0; return allNodesToFilter.Select(node => { _dispatcher.BeginInvoke((System.Action)(() => { int progressPercent = (int)((++nodeCount / (float)nodeToFilterCount) * 100); currentStep.Progress = progressPercent; })); try { //LoadTpl var serializer = new LuaSerializer { IgnoreDefaultValues = true }; return new AudioNodeInfos { 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 AudioNodeInfos.Empty; } }).Where(a => !a.Equals(AudioNodeInfos.Empty) && !a.Tpl.__AdditionalInstructions.Any(i => i.Instruction.EndsWith(".trk\")\r"))).Cast().ToArray(); }); } private async Task ProcessTpl(IStepData stepData, params object[] parameters) { await _dispatcher.InvokeAsync(() => stepData.State = DjRedoStepState.Started); int parametersCount = parameters.Length; int currentFile = 0; foreach (var audioNode in parameters.Cast()) { int progressPercent = (int)((++currentFile / (float)parametersCount) * 100); await _dispatcher.InvokeAsync(() => { stepData.Progress = progressPercent; }); await ProcessCurrentNodeTpl(audioNode); } await _dispatcher.InvokeAsync(() => stepData.State = DjRedoStepState.Successed); DjRedoConfigurationManager.Current.Reset(); return new object[0]; } private async Task ProcessCurrentNodeTpl(AudioNodeInfos audioNode) { await Task.Factory.StartNew(() => { 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"); } }); } private static bool CheckNode(AudioNode n) { return n.IsOnDisk && n.NodeType == NodeType.File && n.IsTpl; } public RunnableStepTaskCollection ProvideSteps(Dispatcher dispatcher) { _dispatcher = dispatcher; var allSteps = new[] { new StepTask(new DjRedoStepViewModel(1, "Build Perforce Tree", "Build Perforce Tree", infinitespin: true), BuildPerforcetree), new StepTask(new DjRedoStepViewModel(2, "Create asset Tree", "Create the memory tree to be pushed into Wwise"), CreateAssetTree), new StepTask(new DjRedoStepViewModel(3, "Exlude Tpl related to trk", "Exclude TPL related to TRK because tempoblaster needs the trk files"), ExludeTplRelatedToTrk), new StepTask(new DjRedoStepViewModel(4, "Clean Tpl", "Clean Tpl"), ProcessTpl), }; return new RunnableStepTaskCollection(allSteps); } public void Initialize(IWpfModuleContext context) { _context = context; } } }