diff --git a/kanimal-cli/Options.cs b/kanimal-cli/Options.cs index d31b4e8..703f47e 100644 --- a/kanimal-cli/Options.cs +++ b/kanimal-cli/Options.cs @@ -19,6 +19,13 @@ public abstract class ConversionOptions : ProgramOptions { [Option('S', "strict", Required = false, HelpText = "When writing to scml, enabling this flag ")] public bool Strict { get; set; } + + [Option('i', "interpolate", Required = false, HelpText = "Enable interpolating scml files on load.")] + public bool Interp { get; set; } + + [Option('b', "debone", Required = false, HelpText = "Enable deboning scml files on load.")] + public bool Debone { get; set; } + } [Verb("dump", HelpText = "Output a dump of the specified kanim.")] diff --git a/kanimal-cli/Program.cs b/kanimal-cli/Program.cs index aec1125..5da1998 100644 --- a/kanimal-cli/Program.cs +++ b/kanimal-cli/Program.cs @@ -58,7 +58,10 @@ private static void Convert(string inputFormat, string outputFormat, List path.EndsWith(".scml")); var scmlreader = new ScmlReader(scml) { - AllowMissingSprites = !opt.Strict + AllowMissingSprites = !opt.Strict, + AllowInFramePivots = !opt.Strict, + InterpolateMissingFrames = opt.Interp, + Debone = opt.Debone }; scmlreader.Read(); reader = scmlreader; @@ -112,7 +115,8 @@ private static void Convert(string inputFormat, string outputFormat, List inputSprites; // The keys in this dictionary are filenames, *with* the file extension, if it exists. public bool AllowMissingSprites = true; + public bool AllowInFramePivots = true; public bool InterpolateMissingFrames = true; public bool Debone = true; @@ -128,6 +129,17 @@ public override void Read() Logger.Info("Reading image files."); ReadProjectSprites(); + // Only use the sprites that are included in the project + List allSprites = inputSprites.Select(sprite => sprite.Key.ToSpriteName()).ToList(); + inputSprites = inputSprites.Where(sprite => projectSprites.ContainsKey(sprite.Key.ToSpriteName())).ToDictionary(x => x.Key, x => x.Value); + List usedSprites = inputSprites.Select(sprite => sprite.Key.ToSpriteName()).ToList(); + + List unusedSprites = allSprites.FindAll(sprite => !usedSprites.Contains(sprite)).Select(sprite => sprite.ToFilename().ToString()).ToList(); + if (unusedSprites.Count > 0) + { + Logger.Warn($"There were unused sprites in the SCML project folder: {unusedSprites.Join()}. Did you forget to included these in the SCML file? You must manually add in files that are part of a symbol_override if they aren't explicitly placed into any animations in the SCML. "); + } + // Also set the output list of sprites Sprites = new List(); Sprites = inputSprites.Select(sprite => new Sprite {Bitmap = sprite.Value, Name = sprite.Key.ToSpriteName()}).ToList(); @@ -587,15 +599,26 @@ float Interpolate(string attrName, float defaultValue) if (hasInconsistentIntervals) { var anims = inconsistentAnims.ToList().Join(); - throw new ProjectParseException( - $"SCML format exception: The intervals in the anims {anims} were inconsistent. Aborting read."); + string error = $"SCML format exception: The intervals in the anims {anims} were inconsistent. Aborting read."; + if (!InterpolateMissingFrames) + { + error += " Try enabling keyframe interpolation with the \"-i\" flag and try again."; + } + throw new ProjectParseException(error); } if (hasPivotsSpecifiedInTimeline) { var anims = pivotAnims.ToList().Join(); - throw new ProjectParseException( - $"SCML format exception: There were pivot points specified in timelines rather than only on the sprites in anims {anims}. Aborting read."); + if (AllowInFramePivots) + { + Logger.Warn($"Encountered pivot points specified in timelines in anims {anims}. These pivot point changes will not be respected. Strict-mode is off. Converting anyway."); + } + else + { + throw new ProjectParseException($"SCML format exception: There were pivot points specified in timelines rather than only on the sprites in anims {anims}. Aborting read."); + } + } AnimData.AnimCount = animCount; diff --git a/kanimal/Writer/ScmlWriter.cs b/kanimal/Writer/ScmlWriter.cs index edb4543..41598ee 100644 --- a/kanimal/Writer/ScmlWriter.cs +++ b/kanimal/Writer/ScmlWriter.cs @@ -22,6 +22,7 @@ public class ScmlWriter : Writer protected XmlElement Entity; public bool FillMissingSprites = true; // When true, if a file is referenced in frames but doesn't exist as a sprite, add it as a blank 1x1 sprite. + public bool AllowDuplicateSprites = true; // When true if a sprite is defined multiple times, only utilize the first definition. public ScmlWriter(Reader reader) { @@ -97,7 +98,14 @@ protected virtual void AddFolderInfo() var key = row.GetSpriteName().ToFilename(); if (filenameindex.ContainsKey(key)) { - throw new Exception($"filenameindex already contains a key for the sprite {key.Value}!"); + if (AllowDuplicateSprites) + { + Logger.Warn($"Duplicate sprite for {key.Value}. This may be indicative of a problem with the source file."); + } + else + { + throw new Exception($"filenameindex already contains a key for the sprite {key.Value}! Try again without strict mode if you believe this is in error."); + } } filenameindex[key] = fileIndex; @@ -112,7 +120,7 @@ protected virtual void AddFolderInfo() var fileNode = Scml.CreateElement("file"); fileNode.SetAttribute("id", fileIndex.ToString()); - fileNode.SetAttribute("name", $"{row.Name}_{row.Index}"); + fileNode.SetAttribute("name", $"{row.Name}_{row.Index}.png"); fileNode.SetAttribute("width", ((int) row.Width).ToString()); fileNode.SetAttribute("height", ((int) row.Height).ToString()); fileNode.SetAttribute("pivot_x", pivotX.ToStringInvariant());