using System; using System.Collections.Generic; using System.Linq; using JD.Kernel.Structs; using JD.LogService; using TeaBox; using JD.Serialization; namespace JD.Timeline.Dance { /// /// Validation to check that dance tape is valid /// public class DanceDocumentValidation { public static void Validate(Tape tape, ILogger context) { ValidateMoveModels(context, tape); ValidatePictoModels(context, tape); foreach (var track in tape.Tracks) { if (track is MoveTrack) { var moveTrack = track as MoveTrack; switch (moveTrack.MoveType) { case MotionClip.MoveType_Enum.MoveType_HandOnly: ValidateMoveTrack(context, moveTrack); break; case MotionClip.MoveType_Enum.MoveType_FullBody: ValidateCameraMoveTrack(context, moveTrack); break; } } else if (track is PictoTrack) { ValidatePictoTrack(context, track as PictoTrack); } else if (track is GoldEffectTrack) { ValidateGoldEffectTrack(context, track as GoldEffectTrack); } else if (track is CommunityDancerTrack) { //No validation yet } else { context.LogError("Track '{0}' has to be a MoveTrack or a PictoTrack.", track.Name); } } foreach (var clip in tape.Clips) { if (clip.CollisionsWithOther) { context.LogWarning(new FileLocation(tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has a collision with an other clip."); } var sameIdClipCount = tape.Clips.Count(x => x.Id == clip.Id); if (sameIdClipCount != 1) { context.LogError(new FileLocation(tape.Id, new List { clip.Id }), $"{sameIdClipCount} clips have the same id '{clip.Id}'"); } } } private static void ValidateMoveTrack(ILogger context, MoveTrack track) { if (!MoveTrack.NameValidationRegexHandOnly.IsMatch(track.Name)) { context.LogError($"Track '{track.Name}' has an invalid name."); } foreach (var clip in track.Clips()) { if (clip is MotionClip) { var motionClip = clip as MotionClip; if (motionClip.CoachId != track.CoachId) { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} CoachId is different from Track one."); } if (motionClip.MoveType != MotionClip.MoveType_Enum.MoveType_HandOnly) { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} MoveType is invalid."); } if (string.IsNullOrEmpty(motionClip.Model.Name)) { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has a model with empty name."); } } else { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has in an invalid type."); } } } private static void ValidateMoveModels(ILogger context, Tape tape) { foreach (var moveModel in tape.MoveModels()) { foreach (var clip in moveModel.Instances) { if (Math.Abs(clip.BeatDuration - moveModel.BeatDuration) > float.Epsilon) { context.LogError(new FileLocation(tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has a different duration than its model."); } if (clip.Color != moveModel.Color) { context.LogError(new FileLocation(tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has a different color than its model."); } if (!clip.ClassifierPath.Equals(moveModel.ClassifierPath)) { context.LogError(new FileLocation(tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has a different classifierpath than its model."); } if (clip.MoveType != moveModel.MoveType) { context.LogError(new FileLocation(tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has a different move type than its model."); } } } } private static void ValidateCameraMoveTrack(ILogger context, MoveTrack track) { if (!MoveTrack.NameValidationRegexFullBody.IsMatch(track.Name)) { context.LogError($"Track '{track.Name}' has an invalid name."); } foreach (var clip in track.Clips()) { if (clip is MotionClip) { var motionClip = clip as MotionClip; if (motionClip.CoachId != track.CoachId) { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} CoachId is different from Track one."); } if (motionClip.MoveType != MotionClip.MoveType_Enum.MoveType_FullBody) { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} MoveType is invalid."); } if (string.IsNullOrEmpty(motionClip.Model.Name)) { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has a model with empty name."); } } else { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has in an invalid type. It should be a MotionClip."); } } } private static void ValidatePictoTrack(ILogger context, PictoTrack track) { if (!PictoTrack.NameValidationRegex.IsMatch(track.Name)) { context.LogError($"Track '{track.Name}' has an invalid name."); } foreach (var clip in track.Clips()) { if (clip is PictogramClip) { var pictoClip = clip as PictogramClip; if (string.IsNullOrEmpty(pictoClip.Model.Name)) { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has a model with empty name."); } } else { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has in an invalid type. It shloud be a PictogramClip."); } } } private static void ValidatePictoModels(ILogger context, Tape tape) { foreach (var pictogramModel in tape.PictogramModels()) { foreach (var clip in pictogramModel.Instances) { if (!clip.PictoPath.Equals(pictogramModel.PictoPath)) { context.LogError(new FileLocation(tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has a different classifierpath than its model."); } } } } private static void ValidateGoldEffectTrack(ILogger context, GoldEffectTrack track) { if (track.Name != GoldEffectTrack.DefaultName) { context.LogError($"Track '{track.Name}' has an invalid name."); } foreach (var clip in track.Clips()) { if (clip is GoldEffectClip) { var goldEffect = clip as GoldEffectClip; if (Math.Abs(goldEffect.BeatDuration - GoldEffectClip.FixedDurationInBeats) > float.Epsilon) { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} duration needs to be {GoldEffectClip.FixedDurationInBeats}."); } } else { context.LogError(new FileLocation(track.Tape.Id, new List { clip.Id }), $"{clip.ToStringDetailed()} has in an invalid type. It should be a GoldEffectClip"); } } } } }