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

355 lines
15 KiB
C#

using System;
using System.Drawing;
using System.Linq;
using System.Text.RegularExpressions;
using JD.Core;
using JD.Serialization;
using TeaBox.Macros;
using FrameConverter = JD.Serialization.FrameConverter;
namespace JDSongConverter.Tasks
{
internal enum LayerTypes
{
Events_0 = 12,
Moves = 13,
KinectMoves = 14,
Lyrics = 15,
Pictos = 16,
KaraokeScoring = 17,
};
public class ConvertDtapeToTimelineTask : Task
{
public string TimelineFile { get; set; }
public string DanceTapeFile { get; set; }
public string OutputDirectoryPath { get; set; }
public void Init(string timelineFile, string danceTapeFile)
{
TimelineFile = timelineFile;
DanceTapeFile = danceTapeFile;
}
public override string Name
{
get { return "Convert dance tape to timeline"; }
set { }
}
public override string ProgressText
{
get { return "Converting dance tape to timeline"; }
}
public override TaskResult Process(IExecutionContext executionContext)
{
OutputDirectoryPath = Context.OutputMap.Folder;
var tape = Tape.CreateTape(DanceTapeFile);
CreateReadableTimelineTemplateFile();
Convert(tape, TimelineFile);
return TaskResult.Ok;
}
private void CreateReadableTimelineTemplateFile()
{
var outputTimelineDirectory = System.IO.Path.Combine(OutputDirectoryPath, "Timeline");
if (!System.IO.Directory.Exists(outputTimelineDirectory))
{
System.IO.Directory.CreateDirectory(outputTimelineDirectory);
}
var timelineTemplateDirectory = GetTimelineTemplateDirectory(OutputDirectoryPath);
var timelineTemplateFilePath = System.IO.Path.Combine(timelineTemplateDirectory, "timeline.tpl");
System.IO.File.Copy(timelineTemplateFilePath, TimelineFile, true);
System.IO.FileInfo fileInfo = new System.IO.FileInfo(timelineTemplateFilePath);
fileInfo.IsReadOnly = false;
}
private string GetTimelineTemplateDirectory(string outputDir)
{
string temp = outputDir;
return Regex.Replace(temp, @"data.*", @"data\EngineData\Level_Structure\MapTemplateALT\Timeline");
}
private void Convert(Tape tape, string timeLinefileName)
{
var serializer = new LuaSerializer();
UAFDictionary<string, int> layerNameId = new UAFDictionary<string, int>();
JD_Timeline_Template timeline;
var actorTemplate = ReadTimelineTemplateFile(timeLinefileName, serializer, out timeline);
ClearExistingTimelineData(timeline);
CreateTimelineLayers(tape, timeline, layerNameId);
foreach (var clip in tape.Clips)
{
ConvertClipToTimeline(clip, layerNameId, timeline);
}
actorTemplate.Save(timeLinefileName);
}
private void ClearExistingTimelineData(JD_Timeline_Template timeline)
{
timeline.Song = Context.Song.Name;
timeline.Layers = new UAFList<TimelineLayer>();
timeline.Pictos = new UAFList<PictoClip>();
timeline.Moves = new UAFList<MoveClip>();
timeline.MovesKinect = new UAFList<MoveClip>();
timeline.MoveModels = new UAFList<TimelineModelMove>();
timeline.Block = new UAFList<TimelineBlock>();
timeline.BlockModel = new UAFList<TimelineModelBlock>();
timeline.PictoModel = new UAFList<TimelineModelPicto>();
timeline.KinectModelMoves = new UAFList<TimelineKinectModelMove>();
timeline.SongGeneralData = new TimelineGeneralData();
}
private static Actor_Template ReadTimelineTemplateFile(string timeLinefileName, LuaSerializer serializer, out JD_Timeline_Template timeline)
{
var actorTemplate = (Actor_Template)serializer.LoadObjectFromFile(timeLinefileName);
if (actorTemplate == null)
{
throw new Exception(string.Format("No timeline file {0} not found at the target directory", timeLinefileName));
}
timeline = actorTemplate.COMPONENTS.OfType<JD_Timeline_Template>().FirstOrDefault();
if (timeline == null)
{
throw new Exception(string.Format("The timeline file {0} format is wrong", timeLinefileName));
}
return actorTemplate;
}
private void ConvertClipToTimeline(Clip clip, UAFDictionary<string, int> layerNameId, JD_Timeline_Template timeline)
{
// Create Pictos and PictoModels in the timeline file
if (clip.Type == typeof(PictogramClip))
{
WritePictoClip(clip, layerNameId, timeline);
}
// Create moves and moveModels
else if (clip.Type == typeof(MotionClip))
{
string moveName;
var motionClip = ExtractClipName(clip, out moveName);
if (motionClip.MoveType == MotionClip.MoveType_Enum.MoveType_HandOnly)
{
WriteControllerMoveClip(layerNameId, timeline, moveName, motionClip);
}
else // Create movesKinect and kinectMoveModels
{
WriteKinectMotionClip(layerNameId, timeline, moveName, motionClip);
}
}
else if (clip.Type == typeof(GoldEffectClip))
{
WriteBlockModelWithGoldMoveClip(clip, timeline);
WriteBlockWithGoldMove(clip, timeline);
}
}
private void WriteBlockWithGoldMove(Clip clip, JD_Timeline_Template timeline)
{
GoldEffectClip goldClip = clip as GoldEffectClip;
TimelineBlock timelineBlock = new TimelineBlock();
timelineBlock.StartPosition = goldClip.StartBeat;
timelineBlock.StopPosition = goldClip.StopBeat;
timelineBlock.LayerID = timeline.Layers.FirstOrDefault(x => x.LayerName == "Events_0").LayerID;
timelineBlock.ModelName = "goldmove";
timelineBlock.Parameters = new UAFList<BlockParameter>();
BlockParameterString blockParameterString = new BlockParameterString();
blockParameterString.Value = "GoldMove";
timelineBlock.Parameters.Add(blockParameterString);
timeline.Block.Add(timelineBlock);
}
private MotionClip ExtractClipName(Clip clip, out string name)
{
MotionClip motionClip = clip as MotionClip;
name = motionClip.ClassifierPath.getRelativePath();
Regex rgx = new Regex(@"\w*\.");
Match m = rgx.Match(name.ToLower());
name = m.Value.Substring(Context.Song.Name.Length + 1, m.Value.Length - (Context.Song.Name.Length + 1) - 1);
return motionClip;
}
private static void WriteBlockModelWithGoldMoveClip(Clip clip, JD_Timeline_Template timeline)
{
GoldEffectClip goldClip = clip as GoldEffectClip;
TimelineModelBlock blockModel = new TimelineModelBlock();
if (goldClip.EffectType == GoldEffectClip.EffectType_Enum.GoldEffect_Auto)
{
blockModel.Name = "goldmove";
}
else if (goldClip.EffectType == GoldEffectClip.EffectType_Enum.GoldEffect_Cascade)
{
blockModel.Name = "goldmovecascade";
}
else if (goldClip.EffectType == GoldEffectClip.EffectType_Enum.GoldEffect_Classic)
{
blockModel.Name = "goldmoveclassic";
}
timeline.BlockModel.Add(blockModel);
}
private static void WriteKinectMotionClip(UAFDictionary<string, int> layerNameId, JD_Timeline_Template timeline, string moveName, MotionClip motionClip)
{
WriteTilmelineKinectMove(layerNameId, timeline, moveName, motionClip);
WriteTimelineKinectModelMove(timeline, moveName, motionClip);
}
private static void WriteTimelineKinectModelMove(JD_Timeline_Template timeline, string moveName, MotionClip motionClip)
{
TimelineKinectModelMove kinectMoveModel = new TimelineKinectModelMove();
kinectMoveModel.Name = moveName;
kinectMoveModel.Color =
(uint) Color.FromArgb(0, motionClip.Color.R, motionClip.Color.G, motionClip.Color.B).ToArgb();
kinectMoveModel.ScoreSmoothing = motionClip.MotionPlatformSpecifics[Platform.X360].ScoreSmoothing;
kinectMoveModel.ScoreScale = motionClip.MotionPlatformSpecifics[Platform.X360].ScoreScale;
//TODO
//kinectMoveModel.ScoringMode = motionClip.MotionPlatformSpecifics[Platform.X360].ScoringMode;
//kinectMoveModel.ScoreSmoothingDurango = motionClip.MotionPlatformSpecifics[Platform.DURANGO].ScoreSmoothing;
//kinectMoveModel.ScoreScaleDurango = motionClip.MotionPlatformSpecifics[Platform.DURANGO].ScoreScale;
//kinectMoveModel.ScoringModeDurango = motionClip.MotionPlatformSpecifics[Platform.DURANGO].ScoringMode;
// Add code for writing the Length in Subdivisions and subdivision in beats
if (timeline.KinectModelMoves.FirstOrDefault(item => item.Name == moveName) == null)
{
timeline.KinectModelMoves.Add(kinectMoveModel);
}
}
private static void WriteTilmelineKinectMove(UAFDictionary<string, int> layerNameId, JD_Timeline_Template timeline, string moveName, MotionClip motionClip)
{
MoveClip kinectMove = new MoveClip();
kinectMove.MoveName = moveName;
kinectMove.LayerID = layerNameId["KinectMoves" + (int) (motionClip.CoachId + 1)];
kinectMove.StartPosition = FrameConverter.TimeFromFrame(motionClip.StartFrame);
kinectMove.StopPosition = FrameConverter.TimeFromFrame(motionClip.StopFrame);
kinectMove.ClassifierPath = motionClip.ClassifierPath;
kinectMove.GoldMove = motionClip.GoldMove;
timeline.MovesKinect.Add(kinectMove);
}
private static void WriteControllerMoveClip(UAFDictionary<string, int> layerNameId, JD_Timeline_Template timeline, string moveName, MotionClip motionClip)
{
WriteTimelineMove(layerNameId, timeline, moveName, motionClip);
WriteTimelineMoveModel(timeline, moveName, motionClip);
}
private static void WriteTimelineMoveModel(JD_Timeline_Template timeline, string moveName, MotionClip motionClip)
{
TimelineModelMove moveModel = new TimelineModelMove();
moveModel.Name = moveName;
// Add code for writing the Length in Subdivisions and subdivision in beats
moveModel.Color = (uint) Color.FromArgb(0, motionClip.Color.R, motionClip.Color.G, motionClip.Color.B).ToArgb();
moveModel.GoldenMove = motionClip.GoldMove;
moveModel.SubdivisionsInBeat = 2;
var startPosition = FrameConverter.TimeFromFrame(motionClip.StartFrame);
var stopPosition = FrameConverter.TimeFromFrame(motionClip.StopFrame);
moveModel.LengthInSubdivisions = (uint)((stopPosition - startPosition) * (float)moveModel.SubdivisionsInBeat);
if (!timeline.MoveModels.Any(item => (item.Name == moveName && item.LengthInSubdivisions == moveModel.LengthInSubdivisions)))
{
timeline.MoveModels.Add(moveModel);
}
}
private static void WriteTimelineMove(UAFDictionary<string, int> layerNameId, JD_Timeline_Template timeline, string moveName, MotionClip motionClip)
{
MoveClip move = new MoveClip();
move.MoveName = moveName;
move.LayerID = layerNameId["Moves" + (int) (motionClip.CoachId + 1)];
move.StartPosition = FrameConverter.TimeFromFrame(motionClip.StartFrame);
move.StopPosition = FrameConverter.TimeFromFrame(motionClip.StopFrame);
move.ClassifierPath = motionClip.ClassifierPath;
move.GoldMove = motionClip.GoldMove;
timeline.Moves.Add(move);
}
private static void WritePictoClip(Clip clip, UAFDictionary<string, int> LayerNameId, JD_Timeline_Template timeline)
{
PictogramClip pictoClip = clip as PictogramClip;
PictoClip picto = new PictoClip();
TimelineModelPicto pictoModel = new TimelineModelPicto();
string name = pictoClip.PictoPath.getRelativePath();
Regex rgx = new Regex(@"\w*\.");
Match m = rgx.Match(name.ToLower());
name = m.Value.Substring(0, m.Value.Length - 1);
picto.Position = FrameConverter.TimeFromFrame(pictoClip.StartFrame);
picto.Pictoname = name;
picto.LayerID = LayerNameId["Pictos"];
picto.TexturePath = pictoClip.PictoPath;
pictoModel.Pictoname = name;
timeline.PictoModel.Add(pictoModel);
timeline.Pictos.Add(picto);
}
private static void CreateTimelineLayers(Tape tape, JD_Timeline_Template timeline, UAFDictionary<string, int> layerNameId)
{
int layerCount = 0;
foreach (var track in tape.Tracks)
{
if (track.Name != "GoldMoveEffects")
{
TimelineLayer layer = new TimelineLayer();
layer.LayerID = layerCount++;
layer.LayerPosition = layer.LayerID;
if (track.Name.Contains("CameraMoves"))
{
layer.LayerName = "KinectMoves" + track.Name.ElementAt(track.Name.Length - 1);
layer.LayerType = (uint)LayerTypes.KinectMoves;
}
else if (track.Name == "Pictos")
{
layer.LayerType = (uint)LayerTypes.Pictos;
layer.LayerName = track.Name;
}
else if (track.Name.Contains("Moves"))
{
layer.LayerType = (uint)LayerTypes.Moves;
layer.LayerName = track.Name;
}
timeline.Layers.Add(layer);
layerNameId.Add(layer.LayerName, layer.LayerID);
}
}
AddTimelineEventsLayer(layerCount, timeline);
}
private static void AddTimelineEventsLayer(int layerCount, JD_Timeline_Template timeline)
{
//Add the Events_0 Layer
TimelineLayer eLayer = new TimelineLayer();
eLayer.LayerID = ++layerCount;
eLayer.LayerPosition = eLayer.LayerID;
eLayer.LayerName = "Events_0";
eLayer.LayerType = (uint)LayerTypes.Events_0;
timeline.Layers.Add(eLayer);
}
}
}