Skip to content

Commit

Permalink
Add Import and Export Sprite Mask scripts (#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
Grossley authored Dec 8, 2020
1 parent 9ebc1a4 commit 06db303
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 1 deletion.
55 changes: 55 additions & 0 deletions UndertaleModTool/ExperimentalScripts/ExportMasks.csx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Made by Grossley
// Version 1
// 12/07/2020

using System.Text;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using UndertaleModLib.Util;

int progress = 0;
string texFolder = GetFolder(FilePath) + "Export_Masks" + Path.DirectorySeparatorChar;
TextureWorker worker = new TextureWorker();

if (Directory.Exists(texFolder))
{
ScriptError("A texture export already exists. Please remove it.", "Error");
return;
}

Directory.CreateDirectory(texFolder);

UpdateProgress();
await DumpSprites();
worker.Cleanup();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + texFolder);

void UpdateProgress()
{
UpdateProgressBar(null, "Sprites", progress++, Data.Sprites.Count);
}

string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}

async Task DumpSprites()
{
await Task.Run(() => Parallel.ForEach(Data.Sprites, DumpSprite));
}

void DumpSprite(UndertaleSprite sprite)
{
for (int i = 0; i < sprite.CollisionMasks.Count; i++)
{
if ((sprite.CollisionMasks[i]?.Data != null))
{
TextureWorker.ExportCollisionMaskPNG(sprite, sprite.CollisionMasks[i], texFolder + sprite.Name.Content + "_" + i + ".png");
}
}
UpdateProgress();
}
108 changes: 108 additions & 0 deletions UndertaleModTool/ExperimentalScripts/ImportMasks.csx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Made by Grossley
// Version 1
// 12/07/2020

using System;
using System.IO;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UndertaleModLib.Util;

EnsureDataLoaded();

// Get import folder
string importFolder = PromptChooseDirectory("Import From Where");
if (importFolder == null)
throw new System.Exception("The import folder was not set.");

//Stop the script if there's missing sprite entries or w/e.
string[] dirFiles = Directory.GetFiles(importFolder);
foreach (string file in dirFiles)
{
string FileNameWithExtension = Path.GetFileName(file);
if (!FileNameWithExtension.EndsWith(".png"))
continue; // Restarts loop if file is not a valid mask asset.
string stripped = Path.GetFileNameWithoutExtension(file);
int lastUnderscore = stripped.LastIndexOf('_');
string spriteName = "";
try
{
spriteName = stripped.Substring(0, lastUnderscore);
}
catch
{
throw new System.Exception("Getting the sprite name of " + FileNameWithExtension + " failed.");
}
if (Data.Sprites.ByName(spriteName) == null) // Reject non-existing sprites
{
throw new System.Exception(FileNameWithExtension + " could not be imported as the sprite " + spriteName + " does not exist.");
}
Image img = Image.FromFile(file);
if ((Data.Sprites.ByName(spriteName).Width != (uint) img.Width) || (Data.Sprites.ByName(spriteName).Height != (uint) img.Height))
throw new System.Exception(FileNameWithExtension + " is not the proper size to be imported! Please correct this before importing! The proper dimensions are width: " + Data.Sprites.ByName(spriteName).Width.ToString() + " px, height: " + Data.Sprites.ByName(spriteName).Height.ToString() + " px.");
Int32 validFrameNumber = 0;
try
{
validFrameNumber = Int32.Parse(stripped.Substring(lastUnderscore + 1));
}
catch
{
throw new System.Exception("The index of " + FileNameWithExtension + " could not be determined.");
}
int frame = 0;
try
{
frame = Int32.Parse(stripped.Substring(lastUnderscore + 1));
}
catch
{
throw new System.Exception(FileNameWithExtension + " is using letters instead of numbers. The script has stopped for your own protection.");
}
int prevframe = 0;
if (frame != 0)
{
prevframe = (frame - 1);
}
if (frame < 0)
{
throw new System.Exception(spriteName + " is using an invalid numbering scheme. The script has stopped for your own protection.");
}
var prevFrameName = spriteName + "_" + prevframe.ToString() + ".png";
string[] previousFrameFiles = Directory.GetFiles(importFolder, prevFrameName);
if (previousFrameFiles.Length < 1)
throw new System.Exception(spriteName + " is missing one or more indexes. The detected missing index is: " + prevFrameName);
}

int progress = 0;
foreach (string file in dirFiles)
{
UpdateProgressBar(null, "Files", progress++, dirFiles.Length);
string FileNameWithExtension = Path.GetFileName(file);
if (!FileNameWithExtension.EndsWith(".png"))
continue; // Restarts loop if file is not a valid mask asset.
string stripped = Path.GetFileNameWithoutExtension(file);
int lastUnderscore = stripped.LastIndexOf('_');
string spriteName = stripped.Substring(0, lastUnderscore);
int frame = Int32.Parse(stripped.Substring(lastUnderscore + 1));
UndertaleSprite sprite = Data.Sprites.ByName(spriteName);
int collision_mask_count = sprite.CollisionMasks.Count;
while (collision_mask_count <= frame)
{
sprite.CollisionMasks.Add(sprite.NewMaskEntry());
collision_mask_count += 1;
}
try
{
sprite.CollisionMasks[frame].Data = TextureWorker.ReadMaskData(file);
}
catch
{
throw new System.Exception(FileNameWithExtension + " has an error that prevents its import and so the operation has been aborted! Please correct this before trying again!");
}
}

HideProgressBar();
ScriptMessage("Import Complete!");
6 changes: 5 additions & 1 deletion UndertaleModTool/ExperimentalScripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ Please report any bugs or issues with the experimental scripts to the Underminer
- `ReloadDeltaruneJSON.csx`: This script adds a F12 hotkey for Deltarune, to reload the JSON language file located externally from the game, while it's running
- `CheckDecompiler.csx`: This script checks the decompiler accuracy of a game and returns the inaccurately decompiled scripts in the game directory.
- `UndertaleWithJSONs.csx`: This script JSONifies all Undertale versions with Japanese support, 1.05+. Switch languages using F11. Reload text for curent language from JSON on command using F12. Reloading from JSON may take about 10 seconds.
- `ExportMasks.csx`: Exports all sprite masks to "Export_Masks" in the game directory.
- `ImportMasks.csx`: Imports sprite masks in bulk from a directory.

## Credits

Expand All @@ -61,4 +63,6 @@ Please report any bugs or issues with the experimental scripts to the Underminer
- `ImportASM.csx`: By samuelroy21 of the DSG team, mono21400
- `ReloadDeltaruneJSON.csx`: By Grossley
- `CheckDecompiler.csx`: By Grossley
- `UndertaleWithJSONs.csx`: By Grossley and Colinator
- `UndertaleWithJSONs.csx`: By Grossley and Colinator
- `ExportMasks.csx`: By Grossley
- `ImportMasks.csx`: By Grossley
6 changes: 6 additions & 0 deletions UndertaleModTool/UndertaleModTool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,12 @@
<None Include="ExperimentalScripts\UndertaleWithJSONs.csx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="ExperimentalScripts\ExportMasks.csx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="ExperimentalScripts\ImportMasks.csx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="SampleScripts\RunSwitchOnPC.csx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down

0 comments on commit 06db303

Please sign in to comment.