Skip to content

Commit

Permalink
Feat cli: Batch convert kanim to scml
Browse files Browse the repository at this point in the history
  • Loading branch information
skairunner committed Nov 16, 2019
1 parent 1204bc9 commit 5c0203d
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 12 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ To specify a directory, you can use the `-o/--output` switch:
$ kanimal-cli.exe kanim [NAME].png [NAME]_anim.bytes [NAME]_build.bytes -o my/output/path
```

#### Batch conversion

It is possible to batch convert *Oxygen Not Included* assets to Spriter files.

1. Unpack the Unity asset bundles. Ensure that the root directory is `Assets`, which contains `Texture2D` and `TextAsset`.
2. Run the following command:
```
$ kanimal-cli batch-convert /path/to/assets/directory
```
3. The result files will be output in the `output/` directory relative to the current working directory. You can specify a different path with the `-o/--output` flag, as always.

### scml → kanim
The process is very similar to the previous one.

Expand All @@ -56,12 +67,13 @@ Just like in the kanim → scml case, the files are output by default into the `
$ ./kanimal-cli convert -I [INPUT_FORMAT] -O [OUTPUT_FORMAT] [FILES ...]
```

Other available switches are as follows:
Other available switches are as follows:
| switch | effect |
|--------|--------|
| `-o/--output` | Specify an output directory |
| `-v/--verbose` | Set verbosity level to DEBUG (default INFO)|
| `-s/--silent` | Set verbosity level to FATAL (default INFO). This means no messages are logged on successful conversion, including warnings. |
|`-S/--strict` | Enforce strict conversion.|

### Kanim dump
KSE supports dumping the contents of a kanim file to a (relatively) readable text file. The command is:
Expand Down
18 changes: 15 additions & 3 deletions kanimal-cli/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ internal abstract class ProgramOptions
public string OutputPath { get; set; } = "output";
}

internal abstract class ConversionOptions : ProgramOptions
{
[Option('S', "strict", Required = false, HelpText = "When writing to scml, enabling this flag ")]
public bool Strict { get; set; }
}

[Verb("dump", HelpText = "Output a dump of the specified kanim.")]
internal class DumpOptions : ProgramOptions
{
Expand All @@ -23,7 +29,7 @@ internal class DumpOptions : ProgramOptions

// For ones with Output and Input specifiers
[Verb("convert", HelpText = "Convert between formats.")]
internal class GenericOptions : ProgramOptions
internal class GenericOptions : ConversionOptions
{
[Option('I', "input-format", Required = true, HelpText = "The input format, from [kanim, scml]")]
public string InputFormat { get; set; }
Expand All @@ -35,14 +41,20 @@ internal class GenericOptions : ProgramOptions
}

[Verb("scml", HelpText = "Convert kanim to scml. Convenience verb equivalent to 'convert -I kanim -O scml'.")]
internal class KanimToScmlOptions : ProgramOptions
internal class KanimToScmlOptions : ConversionOptions
{
[Value(0)] public IEnumerable<string> Files { get; set; }
}

[Verb("kanim", HelpText = "Convert scml to kanim. Convenience verb equivalent to 'convert -I scml -O kanim'.")]
internal class ScmlToKanimOptions : ProgramOptions
internal class ScmlToKanimOptions : ConversionOptions
{
[Value(0)] public string ScmlFile { get; set; }
}

[Verb("batch-convert", HelpText = "Given an Assets/ directory, attempt to batch convert kanim to scml.")]
internal class BatchConvertOptions : ConversionOptions
{
[Value(0)] public string AssetDirectory { get; set; }
}
}
96 changes: 88 additions & 8 deletions kanimal-cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.ExceptionServices;
using NLog;
using CommandLine;
using kanimal;
using NLog.Config;
using NLog.Filters;
using NLog.Fluent;

namespace kanimal_cli
{
internal class Program
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

private static void SetVerbosity(ProgramOptions o)
private static LoggingConfiguration GetLoggerConfig(ProgramOptions o)
{
var config = new NLog.Config.LoggingConfiguration();
var targetConsole = new NLog.Targets.ConsoleTarget("logconsole");
Expand All @@ -31,10 +35,15 @@ private static void SetVerbosity(ProgramOptions o)
else
config.AddRule(LogLevel.Info, LogLevel.Fatal, targetConsole);

LogManager.Configuration = config;
return config;
}

private static void SetVerbosity(ProgramOptions o)
{
LogManager.Configuration = GetLoggerConfig(o);
}

private static void Convert(string inputFormat, string outputFormat, List<string> files, ProgramOptions opt)
private static void Convert(string inputFormat, string outputFormat, List<string> files, ConversionOptions opt)
{
SetVerbosity(opt);

Expand All @@ -57,10 +66,11 @@ private static void Convert(string inputFormat, string outputFormat, List<string
var png = files.Find(path => path.EndsWith(".png"));
var build = files.Find(path => path.EndsWith("build.bytes"));
var anim = files.Find(path => path.EndsWith("anim.bytes"));

reader = new KanimReader(
new FileStream(png, FileMode.Open),
new FileStream(build, FileMode.Open),
new FileStream(anim, FileMode.Open));
new FileStream(anim, FileMode.Open),
new FileStream(png, FileMode.Open));
reader.Read();
break;
default:
Expand All @@ -76,6 +86,7 @@ private static void Convert(string inputFormat, string outputFormat, List<string
{
case "scml":
var scmlWriter = new ScmlWriter(reader);
scmlWriter.FillMissingSprites = !opt.Strict;
scmlWriter.SaveToDir(Path.Join(opt.OutputPath));
break;
case "kanim":
Expand All @@ -93,7 +104,7 @@ private static void Convert(string inputFormat, string outputFormat, List<string

private static void Main(string[] args)
{
Parser.Default.ParseArguments<KanimToScmlOptions, ScmlToKanimOptions, GenericOptions, DumpOptions>(args)
Parser.Default.ParseArguments<KanimToScmlOptions, ScmlToKanimOptions, GenericOptions, DumpOptions, BatchConvertOptions>(args)
.WithParsed<KanimToScmlOptions>(o => Convert(
"kanim",
"scml",
Expand All @@ -107,7 +118,7 @@ private static void Main(string[] args)
var png = files.Find(path => path.EndsWith(".png"));
var build = files.Find(path => path.EndsWith("build.bytes"));
var anim = files.Find(path => path.EndsWith("anim.bytes"));
Directory.CreateDirectory(o.OutputPath);
Utilities.Dump =
new StreamWriter(new FileStream(Path.Join(o.OutputPath, "dump.log"), FileMode.Create));
var reader = new KanimReader(
Expand All @@ -122,7 +133,76 @@ private static void Main(string[] args)
"kanim",
new List<string> {o.ScmlFile},
o))
.WithParsed<GenericOptions>(o => Convert(o.InputFormat, o.OutputFormat, o.Files.ToList(), o));
.WithParsed<GenericOptions>(o => Convert(o.InputFormat, o.OutputFormat, o.Files.ToList(), o))
.WithParsed<BatchConvertOptions>(o =>
{
// Silence Info output from kanimal
var config = new LoggingConfiguration();
var target = new NLog.Targets.ConsoleTarget("logconsole");
target.Layout = "[${level}] ${message}";
var loggingRule1 = new LoggingRule("kanimal_cli.*", target);
loggingRule1.SetLoggingLevels(LogLevel.Info, LogLevel.Fatal);
config.LoggingRules.Add(loggingRule1);
var loggingRule2 = new LoggingRule("kanimal.*", target);
loggingRule2.SetLoggingLevels(LogLevel.Warn, LogLevel.Fatal);
config.LoggingRules.Add(loggingRule2);
LogManager.Configuration = config;
if (!Directory.Exists(Path.Join(o.AssetDirectory, "Texture2D")))
{
Logger.Fatal($"The path \"{o.AssetDirectory}/Texture2D\" does not exist.");
Environment.Exit((int)ExitCodes.IncorrectArguments);
}
if (!Directory.Exists(Path.Join(o.AssetDirectory, "TextAsset")))
{
Logger.Fatal($"The path \"{o.AssetDirectory}/TextAsset\" does not exist.");
Environment.Exit((int)ExitCodes.IncorrectArguments);
}
foreach (var filepath in Directory.GetFiles(Path.Join(o.AssetDirectory, "Texture2D"), "*.png"))
{
var filename = Path.GetFileName(filepath);
var basename = Utilities.GetSpriteBaseName(filename);
if (basename == "")
{
Logger.Warn($"Skipping \"{filename}\" as it does not seem to be a valid anim.");
continue;
}
var png = new FileStream(filepath, FileMode.Open);
var animPath = Path.Join(o.AssetDirectory, "TextAsset", $"{basename}_anim.bytes");
var buildPath = Path.Join(o.AssetDirectory, "TextAsset", $"{basename}_build.bytes");
if (!File.Exists(animPath))
{
Logger.Warn($"Skipping \"{basename}\" because it does not have a corresponding anim.bytes file.");
continue;
}
if (!File.Exists(buildPath))
{
Logger.Warn($"Skipping \"{basename}\" because it does not have a corresponding build.bytes file.");
continue;
}
var anim = new FileStream(animPath, FileMode.Open);
var build = new FileStream(buildPath, FileMode.Open);
var reader = new KanimReader(build, anim, png);
try
{
reader.Read();
var writer = new ScmlWriter(reader);
writer.SaveToDir(Path.Join(o.OutputPath, reader.BuildData.Name));
}
catch (Exception e)
{
Logger.Error($"The following error occured while exporting \"{reader.BuildData.Name}\":");
Logger.Error(e.ToString());
Logger.Error("Skipping.");
continue;
}
Logger.Info($"Exported \"{reader.BuildData.Name}\".");
}
});
}
}
}

0 comments on commit 5c0203d

Please sign in to comment.