JD2022-TU1/main/tools/apps/JDSongConverter/Tasks/ConvertTimelineToDtapeTask.cs

389 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using JD.Asset.Template.Utils;
using JD.Collections.Extensions;
using TeaBox.Macros;
using JD.Core;
using JD.Serialization;
using JD.Timeline.Model;
using JDSongConverter.Utils;
namespace JDSongConverter.Tasks
{
/// <summary>
/// Converts different deprecated timeline files to dance tape file
/// </summary>
public class ConvertTimelineToDtapeTask : Task
{
public string TimelineFile { get; set; }
public string DanceTapeFile { get; set; }
public void Init(string timelineFile, string danceTapeFile)
{
TimelineFile = timelineFile;
DanceTapeFile = danceTapeFile;
}
public override string Name
{
get { return "Convert timeline to dance tape"; }
set { }
}
public override string ProgressText
{
get { return "Converting timeline to dance tape"; }
}
public override TaskResult Process(IExecutionContext executionContext)
{
var tape = new Tape();
if (TimelineFile.EndsWith(".tpl", StringComparison.CurrentCultureIgnoreCase))
{
ImportTpl(tape, TimelineFile);
}
else if (TimelineFile.EndsWith(".tml", StringComparison.CurrentCultureIgnoreCase))
{
ImportTml(tape, TimelineFile);
}
tape.Save(DanceTapeFile);
return TaskResult.Ok;
}
private void ImportTpl(Tape tape, string fileName)
{
var serializer = new LuaSerializer();
var actorTemplate = (Actor_Template)serializer.LoadObjectFromFile(fileName);
if (actorTemplate == null)
return;
JD_Timeline_Template timeline = actorTemplate.COMPONENTS.OfType<JD_Timeline_Template>().FirstOrDefault();
if (timeline == null)
return;
tape.Id = DanceTapeFile;
tape.IsLoading = true;
tape.TapeClock = Tape.TapeClock_Enum.TapeClock_ConductorGameplay;
tape.MapName = Context.Song.Name;
//Import of tracks
foreach (var layer in timeline.Layers)
{
if (MoveTrack.NameValidationRegexHandOnly.IsMatch(layer.LayerName))
{
var moveTrack = tape.GetOrCreateTrack<MoveTrack>((uint)layer.LayerID);
moveTrack.MoveType = MotionClip.MoveType_Enum.MoveType_HandOnly;
moveTrack.CoachId = (MotionClip.CoachId_Enum)(Int32.Parse(MoveTrack.NameValidationRegexHandOnly.Match(layer.LayerName).Groups[2].Value) - 1);
moveTrack.Name = layer.LayerName;
}
else if (MoveTrack.NameValidationRegexTplKinect.IsMatch(layer.LayerName))
{
var moveTrack = tape.GetOrCreateTrack<MoveTrack>((uint)layer.LayerID);
moveTrack.MoveType = MotionClip.MoveType_Enum.MoveType_FullBody;
moveTrack.CoachId = (MotionClip.CoachId_Enum)(Int32.Parse(MoveTrack.NameValidationRegexTplKinect.Match(layer.LayerName).Groups[2].Value) - 1);
moveTrack.Name = "CameraMoves" + (int)(moveTrack.CoachId + 1);
}
else if (PictoTrack.NameValidationRegex.IsMatch(layer.LayerName))
{
var pictoTrack = tape.GetOrCreateTrack<PictoTrack>((uint)layer.LayerID);
pictoTrack.Name = layer.LayerName;
}
}
var goldMoveEventsTrack = tape.GetOrCreateTrack<GoldEffectTrack>(GoldEffectTrack.DefaultName);
//Import of move colors
var moveColors = new Dictionary<string, Color>();
foreach (var moveModel in timeline.MoveModels)
{
var color = Color.FromArgb((int)moveModel.Color);
moveColors[moveModel.Name] = Color.FromArgb(color.R, color.G, color.B);
}
uint clipId = 0;
//Import of standard moves
foreach (var move in timeline.Moves)
{
var clip = new MotionClip
{
Id = clipId++,
TrackId = (uint)move.LayerID,
StartBeat = move.StartPosition,
BeatDuration = move.StopPosition - move.StartPosition,
ClassifierPath = move.ClassifierPath,
MoveType = MotionClip.MoveType_Enum.MoveType_HandOnly,
GoldMove = move.GoldMove,
CoachId = tape.GetOrCreateTrack<MoveTrack>((uint)move.LayerID).CoachId,
Color = moveColors.ContainsKey(move.MoveName) ? moveColors[move.MoveName] : Color.WhiteSmoke
};
tape.Clips.Add(clip);
}
//Import of kinect moves
foreach (var move in timeline.MovesKinect)
{
var clip = new MotionClip
{
Id = clipId++,
TrackId = (uint)move.LayerID,
StartBeat = move.StartPosition,
BeatDuration = move.StopPosition - move.StartPosition,
ClassifierPath = move.ClassifierPath,
MoveType = MotionClip.MoveType_Enum.MoveType_FullBody,
GoldMove = move.GoldMove,
CoachId = tape.GetOrCreateTrack<MoveTrack>((uint)move.LayerID).CoachId,
Color = moveColors.ContainsKey(move.MoveName) ? moveColors[move.MoveName] : Color.WhiteSmoke
};
clip.MotionPlatformSpecifics[Platform.X360] = new MotionClip.MotionPlatformSpecific();
clip.MotionPlatformSpecifics[Platform.X360].ScoreSmoothing = 2;
tape.Clips.Add(clip);
}
//Import of kinect models
foreach (var kinectModel in timeline.KinectModelMoves)
{
var model = tape.MoveModels().FirstOrDefault(x => x.MoveType == MotionClip.MoveType_Enum.MoveType_FullBody &&
x.Name.Equals(kinectModel.Name, StringComparison.OrdinalIgnoreCase));
if (model != null)
{
//TODO
//model.ScoreScale = kinectModel.ScoreScale;
//model.Kinect.ScoreSmoothing = kinectModel.ScoreSmoothing;
//model.Kinect.ScoringMode = kinectModel.ScoringMode;
//model.Kinect2.ScoreScale = kinectModel.ScoreScaleDurango;
//model.Kinect2.ScoreSmoothing = kinectModel.ScoreSmoothingDurango;
//model.Kinect2.ScoringMode = kinectModel.ScoringModeDurango;
}
}
//Import of pictos
foreach (var picto in timeline.Pictos)
{
var clip = new PictogramClip
{
Id = clipId++,
TrackId = (uint)picto.LayerID,
StartBeat = picto.Position,
BeatDuration = 1,
PictoPath = picto.TexturePath
};
tape.Clips.Add(clip);
}
//Import of gold move effects
foreach (var block in timeline.Block)
{
if (block.ModelName == "goldmove")
{
var clip = new GoldEffectClip
{
Id = clipId++,
TrackId = goldMoveEventsTrack.Id,
StartBeat = block.StartPosition,
BeatDuration = 1,
EffectType = GoldEffectClip.EffectType_Enum.GoldEffect_Auto
};
tape.Clips.Add(clip);
}
else if (block.ModelName == "goldmovecascade")
{
var clip = new GoldEffectClip
{
Id = clipId++,
TrackId = goldMoveEventsTrack.Id,
StartBeat = block.StartPosition,
BeatDuration = 1,
EffectType = GoldEffectClip.EffectType_Enum.GoldEffect_Cascade
};
tape.Clips.Add(clip);
}
}
foreach (var clip in tape.Clips.OfType<MotionClip>())
{
var movePathName = Context.OutputMap.Folder.RelativeUri + "/timeline/moves/" + Context.Song.Name + "_" + clip.Model.Name;
movePathName += clip.MoveType == MotionClip.MoveType_Enum.MoveType_HandOnly ? ".msm" : ".gesture";
clip.ClassifierPath = new Path(movePathName);
}
foreach (var clip in tape.Clips.OfType<PictogramClip>())
{
var pictoPathName = Context.OutputMap.Folder.RelativeUri + "/timeline/pictos/" + clip.Model.Name + ".tga";
clip.PictoPath = new Path(pictoPathName);
}
tape.Tracks.RemoveAll(track => track.Clips().IsEmpty());
tape.Tracks.ForEach(track => track.Tape = tape);
tape.IsLoading = false;
}
private void ImportTml(Tape tape, string fileName)
{
tape.Id = DanceTapeFile;
tape.IsLoading = true;
tape.TapeClock = Tape.TapeClock_Enum.TapeClock_ConductorGameplay;
tape.MapName = Context.Song.Name;
XDocument xmlFile = XDocument.Load(fileName);
var moveModels = xmlFile.XPathSelectElements("/JustDanceToolLD/partition/databank/MoveBank/Move").ToList();
var kinectmoveModels = xmlFile.XPathSelectElements("/JustDanceToolLD/partition/databank/KinectBank/KinectMove").ToList();
var pictoModels = xmlFile.XPathSelectElements("/JustDanceToolLD/partition/databank/PictoBank/Picto").ToList();
var layers = xmlFile.XPathSelectElements("/JustDanceToolLD/partition/layer").ToList();
//We create Tracks
foreach (var layer in layers)
{
var layerName = layer.Attribute("name").Value;
if (MoveTrack.NameValidationRegexHandOnly.IsMatch(layerName))
{
var track = tape.GetOrCreateTrack<MoveTrack>(IdGenerator.Instance.Generate());
track.Name = layerName;
track.MoveType = MotionClip.MoveType_Enum.MoveType_HandOnly;
int layerId;
if (Int32.TryParse(MoveTrack.NameValidationRegexHandOnly.Match(layerName).Groups[2].Value, out layerId))
{
track.CoachId = (MotionClip.CoachId_Enum) (layerId - 1);
}
else
{
track.CoachId = MotionClip.CoachId_Enum.COACH_0;
}
track.Extensions.Layer = layer;
}
else if (MoveTrack.NameValidationRegexTplKinect.IsMatch(layerName))
{
var track = tape.GetOrCreateTrack<MoveTrack>(IdGenerator.Instance.Generate());
track.MoveType = MotionClip.MoveType_Enum.MoveType_FullBody;
int layerId;
if (Int32.TryParse(MoveTrack.NameValidationRegexTplKinect.Match(layerName).Groups[2].Value, out layerId))
{
track.CoachId = (MotionClip.CoachId_Enum)(layerId - 1);
}
else
{
track.CoachId = MotionClip.CoachId_Enum.COACH_0;
}
track.Name = "CameraMoves" + (int)(track.CoachId + 1);
track.Extensions.Layer = layer;
}
else if (PictoTrack.NameValidationRegex.IsMatch(layerName))
{
var track = tape.GetOrCreateTrack<PictoTrack>(IdGenerator.Instance.Generate());
track.Name = layerName;
track.Extensions.Layer = layer;
}
else if (layerName.StartsWith("Events"))
{
if (layer.Descendants("instance").Any(x => x.Attribute("model").Value == "GoldMove"))
{
var track = tape.GetOrCreateTrack<GoldEffectTrack>(GoldEffectTrack.DefaultName);
track.Extensions.Layer = layer;
}
}
}
//We parse move layers
foreach (var track in tape.Tracks.OfType<MoveTrack>())
{
foreach (var instance in track.Extensions.Layer.Descendants("instance"))
{
int position = Int32.Parse(instance.Attribute("position").Value)-1;
string modelName = instance.Attribute("model").Value;
var model = track.MoveType == MotionClip.MoveType_Enum.MoveType_HandOnly ?
moveModels.FirstOrDefault(x => x.Attribute("name").Value == modelName) :
kinectmoveModels.FirstOrDefault(x => x.Attribute("name").Value == modelName);
if (model == null)
continue;
int duration = XmlUtils.ReadIntValue(model.Element("duration"), 0);
int subdivisionInBeat = XmlUtils.ReadIntValue(model.Element("SubdivisionsInBeat"), 1);
bool isGoldenMove = XmlUtils.ReadBoolValue(model.Element("GoldenMove"), false) ||
XmlUtils.ReadBoolValue(instance.Element("GoldenMove"), false);
var moveColor = XmlUtils.ReadColorValue(model.Element("color"), Color.Orange);
moveColor = Color.FromArgb(255, moveColor.B, moveColor.G, moveColor.R);
var offsetInSubdivision = XmlUtils.ReadIntValue(instance.Element("OffsetInSubdivisions"), 0);
var movePathName = Context.OutputMap.Folder.RelativeUri + "/timeline/moves/" + Context.Song.Name + "_" + modelName;
movePathName += track.MoveType == MotionClip.MoveType_Enum.MoveType_HandOnly ? ".msm" : ".gesture";
var clip = new MotionClip
{
Id = IdGenerator.Instance.Generate(),
TrackId = track.Id,
StartBeat = position + offsetInSubdivision/(float)subdivisionInBeat,
BeatDuration = duration / (float)subdivisionInBeat,
ClassifierPath = new Path(movePathName),
MoveType = track.MoveType,
CoachId = track.CoachId,
GoldMove = isGoldenMove,
Color = moveColor
};
tape.Clips.Add(clip);
}
}
//We parse picto layers
foreach (var track in tape.Tracks.OfType<PictoTrack>())
{
foreach (var instance in track.Extensions.Layer.Descendants("instance"))
{
int position = Int32.Parse(instance.Attribute("position").Value)-1;
string modelName = instance.Attribute("model").Value;
var model = pictoModels.FirstOrDefault(x => x.Attribute("name").Value == modelName);
if (model == null)
continue;
var offset = (float)XmlUtils.ReadDoubleValue(instance.Element("Offset"), 0);
var pictoPathName = Context.OutputMap.Folder.RelativeUri + "/timeline/pictos/" + modelName + ".tga";
var clip = new PictogramClip
{
Id = IdGenerator.Instance.Generate(),
TrackId = track.Id,
StartBeat = tape.TimeInBeats(position, offset),
BeatDuration = 1,
PictoPath = new Path(pictoPathName)
};
tape.Clips.Add(clip);
}
}
//We parse gold effects layers
foreach (var track in tape.Tracks.OfType<GoldEffectTrack>())
{
XElement layer = track.Extensions.Layer;
var goldEffects = layer.Descendants("instance").Where(x => x.Attribute("model").Value.StartsWith("GoldMove"));
foreach (var instance in goldEffects)
{
int position = Int32.Parse(instance.Attribute("position").Value)-1;
var offset = (float)XmlUtils.ReadDoubleValue(instance.Element("Offset"), 0);
var clip = new GoldEffectClip
{
Id = IdGenerator.Instance.Generate(),
TrackId = track.Id,
StartBeat = tape.TimeInBeats(position, offset),
BeatDuration = 1,
EffectType = GoldEffectClip.EffectType_Enum.GoldEffect_Auto
};
tape.Clips.Add(clip);
}
}
}
}
}