From 20389fff88bb03ee4bc23a0648bbad37f52ee321 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Thu, 24 Mar 2022 19:19:23 +0100
Subject: [PATCH 01/18] Document most of IScriptInterface.
---
UndertaleModCli/Program.cs | 28 +-
UndertaleModLib/Scripting/IScriptInterface.cs | 383 +++++++++++++++++-
UndertaleModTests/GameScriptTests.cs | 28 +-
UndertaleModTool/MainWindow.xaml.cs | 80 ++--
UndertaleModTool/ProfileSystem.cs | 46 +--
UndertaleModTool/ScriptingFunctions.cs | 42 --
UndertaleModTool/UndertaleModTool.csproj | 2 +
7 files changed, 440 insertions(+), 169 deletions(-)
diff --git a/UndertaleModCli/Program.cs b/UndertaleModCli/Program.cs
index f2f7cfa5b..e548cb9e4 100644
--- a/UndertaleModCli/Program.cs
+++ b/UndertaleModCli/Program.cs
@@ -20,8 +20,8 @@
using System.Linq;
using System.Collections.Generic;
using UndertaleModLib.Decompiler;
-using UndertaleModLib.Models;
-
+using UndertaleModLib.Models;
+
///
/// The supplied location of the data file did not exist
///
@@ -528,7 +528,7 @@ public void EnsureDataLoaded()
throw new Exception("No data file is loaded.");
}
- public async Task Make_New_File()
+ public async Task MakeNewDataFile()
{
await Task.Delay(1); //dummy await
@@ -676,12 +676,12 @@ public string GetDisassemblyText(UndertaleCode code)
throw new NotImplementedException();
}
- public bool AreFilesIdentical(string File01, string File02)
+ public bool AreFilesIdentical(string file1, string file2)
{
try
{
- using var fs1 = new FileStream(File01, FileMode.Open, FileAccess.Read, FileShare.Read);
- using var fs2 = new FileStream(File01, FileMode.Open, FileAccess.Read, FileShare.Read);
+ using var fs1 = new FileStream(file1, FileMode.Open, FileAccess.Read, FileShare.Read);
+ using var fs2 = new FileStream(file2, FileMode.Open, FileAccess.Read, FileShare.Read);
if (fs1.Length != fs2.Length) return false; // different size.
while (true)
@@ -702,7 +702,7 @@ public bool AreFilesIdentical(string File01, string File02)
}
}
- public string ScriptInputDialog(string titleText, string labelText, string defaultInputBoxText, string cancelButtonText, string submitButtonText, bool isMultiline, bool preventClose)
+ public string ScriptInputDialog(string title, string label, string defaultInput, string cancelText, string submitText, bool isMultiline, bool preventClose)
{
throw new NotImplementedException();
}
@@ -711,7 +711,7 @@ public string SimpleTextInput(string title, string label, string defaultValue, b
{
throw new NotImplementedException();
}
- public void SimpleTextOutput(string title, string label, string defaultText, bool allowMultiline)
+ public void SimpleTextOutput(string title, string label, string message, bool allowMultiline)
{
throw new NotImplementedException();
}
@@ -775,15 +775,15 @@ public void AddProgress(int amount)
{
progressValue += amount;
}
- public void IncProgress()
+ public void IncrementProgress()
{
progressValue++;
}
- public void AddProgressP(int amount) //P - Parallel (multithreaded)
+ public void AddProgressParallel(int amount) //P - Parallel (multithreaded)
{
Interlocked.Add(ref progressValue, amount); //thread-safe add operation (not the same as "lock ()")
}
- public void IncProgressP()
+ public void IncrementProgressParallel()
{
Interlocked.Increment(ref progressValue); //thread-safe increment
}
@@ -875,12 +875,12 @@ public async Task GenerateGMLCache(ThreadLocal dec
}
- public void ChangeSelection(object newsel)
+ public void ChangeSelection(object newSelection)
{
- Selected = newsel;
+ Selected = newSelection;
}
- public string PromptChooseDirectory(string prompt)
+ public string PromptChooseDirectory()
{
Console.WriteLine("Please type a path (or drag and drop) to a directory:");
Console.Write("Path: ");
diff --git a/UndertaleModLib/Scripting/IScriptInterface.cs b/UndertaleModLib/Scripting/IScriptInterface.cs
index a78fc1a3a..a083e49ff 100644
--- a/UndertaleModLib/Scripting/IScriptInterface.cs
+++ b/UndertaleModLib/Scripting/IScriptInterface.cs
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
+using System.IO;
+using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading;
@@ -22,64 +24,378 @@ public ScriptException(string msg) : base(msg)
public interface IScriptInterface
{
+ ///
+ /// The data file.
+ ///
UndertaleData Data { get; }
+
+ ///
+ /// The file path where resides.
+ ///
string FilePath { get; }
+
+ ///
+ /// The path of the current executed script.
+ ///
string ScriptPath { get; }
+
+ ///
+ /// The object that's currently highlighted in the GUI.
+ ///
object Highlighted { get; }
+
+ ///
+ /// The object that's currently selected in the GUI.
+ ///
object Selected { get; }
+
+ ///
+ /// Indicates whether saving is currently enabled.
+ ///
bool CanSave { get; }
+
+ ///
+ /// Indicates whether the last script executed successfully or not.
+ ///
bool ScriptExecutionSuccess { get; }
+
+ ///
+ /// Error message of the last executed script. Will be "" () if no error occured.
+ ///
string ScriptErrorMessage { get; }
+
+ ///
+ /// Path of the main executable that's currently running.
+ ///
+ /// For example C://Users/me/UMT/UMT.exe or /bin/UMTCLI.
string ExePath { get; }
+
+ ///
+ /// A string, detailing the type of the last encountered error.
+ ///
string ScriptErrorType { get; }
+ //TODO: no idea what this is. is not used per se anywhere, GUI implements its own thing and uses that instead.
bool GMLCacheEnabled { get; }
+ //TODO: this has no use. Only GUI uses this, and nothing should ever need to access this value.
bool IsAppClosed { get; }
- void EnsureDataLoaded();
- Task Make_New_File();
+ ///
+ /// Ensures that a valid data file () is loaded. An exception should be thrown if it isn't.
+ ///
+ void EnsureDataLoaded()
+ {
+ if (Data is null)
+ throw new ScriptException("No data file is currently loaded!");
+ }
+
+ ///
+ /// Creates a new Data file asynchronously.
+ ///
+ /// if task was successful, if not.
+ Task MakeNewDataFile();
+
+ //TODO: i have absolutely no idea what any of these do.
void ReplaceTempWithMain(bool ImAnExpertBTW = false);
void ReplaceMainWithTemp(bool ImAnExpertBTW = false);
void ReplaceTempWithCorrections(bool ImAnExpertBTW = false);
void ReplaceCorrectionsWithTemp(bool ImAnExpertBTW = false);
void UpdateCorrections(bool ImAnExpertBTW = false);
+ ///
+ /// Used in Scripts in order to show a message to the user.
+ ///
+ /// The message to show.
void ScriptMessage(string message);
+
+ //TODO: currently mostly used with GUI
void SetUMTConsoleText(string message);
+
+ ///
+ /// Used in Scripts in order to ask a yes/no question to the user which they can answer.
+ ///
+ /// The message to ask.
+ /// if user affirmed the question, if not.
bool ScriptQuestion(string message);
+
+ ///
+ /// Used in Scripts in order to show an error to the user.
+ ///
+ /// The error message to show.
+ /// A short-descriptive title.
+ /// TODO
void ScriptError(string error, string title = "Error", bool SetConsoleText = true);
+
+ ///
+ /// Used in Scripts in order to open a URL in the users' browser.
+ ///
+ /// The URL to open.
void ScriptOpenURL(string url);
- bool SendAUMIMessage(IpcMessage_t ipMessage, ref IpcReply_t outReply);
+
+ ///
+ /// Used for communicating with AUMI (Archie's Undertale Modding Interface).
+ ///
+ /// TODO
+ /// TODO
+ /// TODO
+ bool SendAUMIMessage(IpcMessage_t ipMessage, ref IpcReply_t outReply)
+ {
+ // By Archie
+ const int ReplySize = 132;
+
+ // Create the pipe
+ using var pPipeServer = new NamedPipeServerStream("AUMI-IPC", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
+
+ // Wait 1/8th of a second for AUMI to connect.
+ // If it doesn't connect in time (which it should), just return false to avoid a deadlock.
+ if (!pPipeServer.IsConnected)
+ {
+ pPipeServer.WaitForConnectionAsync();
+ Thread.Sleep(125);
+ if (!pPipeServer.IsConnected)
+ {
+ pPipeServer.DisposeAsync();
+ return false;
+ }
+ }
+
+ try
+ {
+ //Send the message
+ pPipeServer.Write(ipMessage.RawBytes());
+ pPipeServer.Flush();
+ }
+ catch (Exception e)
+ {
+ // Catch any errors that might arise if the connection is broken
+ ScriptError("Could not write data to the pipe!\nError: " + e.Message);
+ return false;
+ }
+
+ // Read the reply, the length of which is always a pre-set amount of bytes.
+ byte[] bBuffer = new byte[ReplySize];
+ pPipeServer.Read(bBuffer, 0, ReplySize);
+
+ outReply = IpcReply_t.FromBytes(bBuffer);
+ return true;
+ }
+
+ ///
+ /// Run a C# UndertaleModLib compatible script file.
+ ///
+ /// File path to the script file to execute.
+ /// A that indicates whether the execution of the script was successful.
bool RunUMTScript(string path);
+
+ ///
+ /// Lint whether a file is C# UndertaleModLib compatible.
+ ///
+ /// File path to the script file to lint.
+ /// A that indicates whether the linting was successful.
bool LintUMTScript(string path);
+
+ ///
+ /// Initializes a Script Dialog with default values
+ ///
void InitializeScriptDialog();
+
+ //TODO: some profile mod stuff, not quite sure on what its supposed to do.
void ReapplyProfileCode();
void NukeProfileGML(string codeName);
+
+ ///
+ ///Get the decompiled text from a code entry (like gml_Script_moveTo).
+ ///
+ /// he name of the code entry from which to get the decompiled code from.
+ /// The GlobalDecompileContext
+ /// Decompiled text as a .
+ /// This will return a string, even if the decompilation failed! Usually commented out and featuring
+ /// DECOMPILER FAILED! .
string GetDecompiledText(string codeName, GlobalDecompileContext context = null);
+
+ ///
+ /// Get the decompiled text from an object.
+ ///
+ /// The object from which to get the decompiled code from.
+ /// The GlobalDecompileContext
+ /// Decompiled text as a .
+ /// This will return a string, even if the decompilation failed! Usually commented out and featuring
+ /// DECOMPILER FAILED! .
string GetDecompiledText(UndertaleCode code, GlobalDecompileContext context = null);
+
+ ///
+ /// Get the disassembly from a code entry (like gml_Script_moveTo).
+ ///
+ /// The name of the code entry from which to get the disassembly from.
+ /// Disassembly as .
+ /// This will return a string, even if the disassembly failed! Usually commented out and featuring
+ /// DISASSEMBLY FAILED! .
string GetDisassemblyText(string codeName);
+
+ ///
+ /// Get the disassembly from an object.
+ ///
+ /// The object from which to get the disassembly from.
+ /// Disassembly as .
+ /// This will return a string, even if the disassembly failed! Usually commented out and featuring
+ /// DISASSEMBLY FAILED! .
string GetDisassemblyText(UndertaleCode code);
- bool AreFilesIdentical(string File01, string File02);
- string ScriptInputDialog(string titleText, string labelText, string defaultInputBoxText, string cancelButtonText, string submitButtonText, bool isMultiline, bool preventClose);
+
+ ///
+ /// Check whether two files are identical.
+ ///
+ /// File path to first file.
+ /// File path to second file.
+ /// A that indicates whether the files are identical or not.
+ bool AreFilesIdentical(string file1, string file2)
+ {
+ using FileStream fs1 = new FileStream(file1, FileMode.Open, FileAccess.Read, FileShare.Read);
+ using FileStream fs2 = new FileStream(file2, FileMode.Open, FileAccess.Read, FileShare.Read);
+
+ if (fs1.Length != fs2.Length) return false; // different size, files can't be the same
+
+ while (true)
+ {
+ int b1 = fs1.ReadByte();
+ int b2 = fs2.ReadByte();
+ if (b1 != b2) return false; // different contents, files are not the same
+ if (b1 == -1) break; // here both bytes are the same. Thus we only need to check if one is at end-of-file.
+ }
+
+ // identical
+ return true;
+ }
+
+ ///
+ /// Allows the user to input text with the option to cancel it.
+ ///
+ /// Short descriptive title.
+ /// A label describing what the user should input.
+ /// The default value of the input.
+ /// The text of the cancel button.
+ /// The text of the submit button.
+ /// Whether to allow the input to have multiple lines.
+ /// Whether the window is allowed to be closed.
+ /// Should this be set to , then there also won't be a close button.
+ ///
+ string ScriptInputDialog(string title, string label, string defaultInput, string cancelText, string submitText, bool isMultiline, bool preventClose);
+
+ ///
+ /// Allows the user to input text in a simple dialog.
+ ///
+ /// Short descriptive title.
+ /// A label describing what the user should input.
+ /// The default value of the input.
+ /// Whether to allow the input to have multiple lines.
+ /// Whether to block the parent window and only continue after the dialog is cleared.
+ /// The text that the user inputted.
string SimpleTextInput(string title, string label, string defaultValue, bool allowMultiline, bool showDialog = true);
- void SimpleTextOutput(string title, string label, string defaultText, bool allowMultiline);
+
+ ///
+ /// Shows simple output to the user.
+ ///
+ /// Short descriptive title.
+ /// A label describing the output.
+ /// The message to convey to the user.
+ /// Whether to allow the message to be multiline or not.
+ /// Should this be false but have multiple lines, then only the first line will be shown.
+ void SimpleTextOutput(string title, string label, string message, bool allowMultiline);
+
+ //TODO: not exactly sure about most of these.
Task ClickableTextOutput(string title, string query, int resultsCount, IOrderedEnumerable>> resultsDict, bool editorDecompile, IOrderedEnumerable failedList = null);
Task ClickableTextOutput(string title, string query, int resultsCount, IDictionary> resultsDict, bool editorDecompile, IEnumerable failedList = null);
+
+ ///
+ /// Sets .
+ ///
+ /// The state to set it to.
void SetFinishedMessage(bool isFinishedMessageEnabled);
+
+ ///
+ /// Updates the progress bar. Not to be called directly in scripts! Use instead!
+ ///
+ ///
+ ///
+ ///
+ ///
void UpdateProgressBar(string message, string status, double progressValue, double maxValue);
+
+ ///
+ /// Sets the progress bar dialog to a certain value.
+ ///
+ /// What the progress bar is describing.
+ /// What the current status is. For example Decompiling....
+ /// The value to set the progress bar to.
+ /// The max value of the progress bar.
void SetProgressBar(string message, string status, double progressValue, double maxValue);
+
+ ///
+ /// Show the progress bar.
+ ///
void SetProgressBar();
+
+ ///
+ /// Updates the value of the current running progress bar dialog.
+ ///
+ /// The new value to set the progress bar to.
void UpdateProgressValue(double progressValue);
+
+ ///
+ /// Updates the status of the current running progress bar dialog.
+ ///
+ /// The new status. For example Decompiling....
void UpdateProgressStatus(string status);
+
+ //TODO: considering this forces everything that implements this to have their own progressValue,
+ //why not make that a necessary attribute?
+ ///
+ /// Adds a certain amount to the variable holding a progress value.
+ ///
+ /// The amount to add.
void AddProgress(int amount);
- void IncProgress();
- void AddProgressP(int amount);
- void IncProgressP();
+
+ ///
+ /// Increments the variable holding a progress value by one.
+ ///
+ void IncrementProgress();
+
+ ///
+ /// Adds a certain amount to the variable holding a progress value in.
+ /// Used for parallel operations, as it is thread-safe.
+ ///
+ /// The amount to add.
+ void AddProgressParallel(int amount);
+
+ ///
+ /// Increments the variable holding a progress value by one.
+ /// Used for parallel operations, as it is thread-safe.
+ ///
+ void IncrementProgressParallel();
+
+ ///
+ /// Gets the value of the variable holding a progress value.
+ ///
+ /// The value as .
int GetProgress();
+
+ ///
+ /// Sets the value of the variable holding a progress variable to another value.
+ ///
+ /// The new value for the progress variable.
void SetProgress(int value);
+
+ ///
+ /// Hides the progress bar.
+ ///
void HideProgressBar();
+
+ ///
+ /// Enables the UI.
+ ///
void EnableUI();
+
+ // TODO: ask vlad about these.
void SyncBinding(string resourceType, bool enable);
void SyncBinding(bool enable = false);
void StartUpdater();
@@ -87,19 +403,58 @@ public interface IScriptInterface
Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool isSaving = false);
- void ChangeSelection(object newsel);
+ ///
+ /// Changes the currently selected in the GUI.
+ ///
+ /// The new object that should now be selected.
+ void ChangeSelection(object newSelection);
- string PromptChooseDirectory(string prompt);
+ ///
+ /// Used to prompt the user for a directory.
+ ///
+ /// The directory selected by the user.
+ string PromptChooseDirectory();
+ ///
+ /// Used to prompt the user for a file.
+ ///
+ /// The default extension that should be selected.
+ /// The filters used for the file select.
+ /// The file selected by the user.
string PromptLoadFile(string defaultExt, string filter);
+
+ //TODO: so much stuff....
void ImportGMLString(string codeName, string gmlCode, bool doParse = true, bool CheckDecompiler = false);
void ImportASMString(string codeName, string gmlCode, bool doParse = true, bool destroyASM = true, bool CheckDecompiler = false);
void ImportGMLFile(string fileName, bool doParse = true, bool CheckDecompiler = false, bool throwOnError = false);
void ImportASMFile(string fileName, bool doParse = true, bool destroyASM = true, bool CheckDecompiler = false, bool throwOnError = false);
void ReplaceTextInGML(string codeName, string keyword, string replacement, bool case_sensitive = false, bool isRegex = false, GlobalDecompileContext context = null);
void ReplaceTextInGML(UndertaleCode code, string keyword, string replacement, bool case_sensitive = false, bool isRegex = false, GlobalDecompileContext context = null);
- bool DummyBool();
- void DummyVoid();
- string DummyString();
+
+ ///
+ /// Method returning a dummy boolean value.
+ ///
+ /// Returns a dummy boolean value
+ bool DummyBool()
+ {
+ return true;
+ }
+
+ ///
+ /// Method doing nothing.
+ ///
+ void DummyVoid()
+ {
+
+ }
+
+ ///
+ /// Method returning a dummy string value.
+ ///
+ /// Returns a dummy string value.
+ string DummyString()
+ {
+ return "";
+ }
}
}
diff --git a/UndertaleModTests/GameScriptTests.cs b/UndertaleModTests/GameScriptTests.cs
index d4d4961ee..c6df1129c 100644
--- a/UndertaleModTests/GameScriptTests.cs
+++ b/UndertaleModTests/GameScriptTests.cs
@@ -36,14 +36,14 @@ public GameScriptTestBase(string path, string md5) : base(path, md5)
public bool IsAppClosed => throw new NotImplementedException();
- public void ChangeSelection(object newsel)
+ public void ChangeSelection(object newSelection)
{
}
public void EnsureDataLoaded()
{
}
- public async Task Make_New_File()
+ public async Task MakeNewDataFile()
{
await Task.Delay(1); //dummy await
return true;
@@ -127,15 +127,15 @@ public void AddProgress(int amount)
{
Console.WriteLine($"AddProgress(): {amount}");
}
- public void IncProgress()
+ public void IncrementProgress()
{
Console.WriteLine("IncProgress()");
}
- public void AddProgressP(int amount)
+ public void AddProgressParallel(int amount)
{
Console.WriteLine($"AddProgressP(): {amount}");
}
- public void IncProgressP()
+ public void IncrementProgressParallel()
{
Console.WriteLine("IncProgressP()");
}
@@ -149,9 +149,9 @@ public void SetProgress(int value)
Console.WriteLine($"SetProgress(): {value}");
}
- public string ScriptInputDialog(string titleText, string labelText, string defaultInputBoxText, string cancelButtonText, string submitButtonText, bool isMultiline, bool preventClose)
+ public string ScriptInputDialog(string title, string label, string defaultInput, string cancelText, string submitText, bool isMultiline, bool preventClose)
{
- Console.Write(labelText + " ");
+ Console.Write(label + " ");
string ret = Console.ReadLine();
return ret;
@@ -160,9 +160,9 @@ public string SimpleTextInput(string titleText, string labelText, string default
{
return ScriptInputDialog(titleText, labelText, defaultInputBoxText, "Cancel", "Submit", isMultiline, false);
}
- public void SimpleTextOutput(string titleText, string labelText, string defaultInputBoxText, bool isMultiline)
+ public void SimpleTextOutput(string titleText, string labelText, string message, bool isMultiline)
{
- Console.WriteLine($"SimpleTextOutput(): \"{titleText}\", \"{labelText}\", *defaultInputBoxText* (length - {defaultInputBoxText.Length}), {isMultiline}");
+ Console.WriteLine($"SimpleTextOutput(): \"{titleText}\", \"{labelText}\", *defaultInputBoxText* (length - {message.Length}), {isMultiline}");
}
public async Task ClickableTextOutput(string title, string query, int resultsCount, IOrderedEnumerable>> resultsDict, bool editorDecompile, IOrderedEnumerable failedList = null)
{
@@ -247,7 +247,7 @@ public async Task GenerateGMLCache(ThreadLocal dec
);
await Task.Delay(1); //dummy await
-
+
return false;
}
@@ -272,7 +272,7 @@ public void ScriptError(string error, string title = "Error", bool SetConsoleTex
throw new NotImplementedException();
}
- public string PromptChooseDirectory(string prompt)
+ public string PromptChooseDirectory()
{
throw new NotImplementedException();
}
@@ -301,9 +301,9 @@ public string GetDisassemblyText(UndertaleCode code)
Console.Write(output);
return output;
}
- public bool AreFilesIdentical(string File01, string File02)
+ public bool AreFilesIdentical(string file1, string file2)
{
- string output = "AreFilesIdentical(): " + File01 + ", " + File02;
+ string output = "AreFilesIdentical(): " + file1 + ", " + file2;
Console.Write(output);
return true;
}
@@ -355,7 +355,7 @@ public async Task ShowRoomName()
{
await RunScript("ShowRoomName.csx");
}
-
+
[TestMethod]
[Ignore] // TODO: path problems
public async Task BorderEnabler()
diff --git a/UndertaleModTool/MainWindow.xaml.cs b/UndertaleModTool/MainWindow.xaml.cs
index 764c4d929..6da0d6fc4 100644
--- a/UndertaleModTool/MainWindow.xaml.cs
+++ b/UndertaleModTool/MainWindow.xaml.cs
@@ -54,7 +54,7 @@ public partial class MainWindow : Window, INotifyPropertyChanged, IScriptInterfa
/// Note for those who don't know what is "PropertyChanged.Fody" -
/// it automatically adds "OnPropertyChanged()" to every property (or modify existing) of the class that implements INotifyPropertyChanged.
/// It does that on code compilation.
-
+
public UndertaleData Data { get; set; }
public string FilePath { get; set; }
public string ScriptPath { get; set; } // For the scripting interface specifically
@@ -170,9 +170,9 @@ public MainWindow()
scriptSetupTask = Task.Run(() =>
{
scriptOptions = ScriptOptions.Default
- .AddImports("UndertaleModLib", "UndertaleModLib.Models", "UndertaleModLib.Decompiler",
+ .AddImports("UndertaleModLib", "UndertaleModLib.Models", "UndertaleModLib.Decompiler",
"UndertaleModLib.Scripting", "UndertaleModLib.Compiler",
- "UndertaleModTool", "System", "System.IO", "System.Collections.Generic",
+ "UndertaleModTool", "System", "System.IO", "System.Collections.Generic",
"System.Text.RegularExpressions")
.AddReferences(typeof(UndertaleObject).GetTypeInfo().Assembly,
GetType().GetTypeInfo().Assembly,
@@ -303,7 +303,7 @@ private async void Window_Loaded(object sender, RoutedEventArgs e)
Thread.Sleep(1000);
}
-
+
if (!deleted)
ShowWarning($"The updater temp folder can't be deleted.\nError - {exMessage}.");
}
@@ -419,9 +419,9 @@ public async Task ListenChildConnection(string key)
private async void Command_New(object sender, ExecutedRoutedEventArgs e)
{
- await Make_New_File();
+ await MakeNewDataFile();
}
- public async Task Make_New_File()
+ public async Task MakeNewDataFile()
{
if (Data != null)
{
@@ -447,7 +447,7 @@ public async Task Make_New_File()
CanSave = true;
CanSafelySave = true;
- GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; //clean "GC holes" left in the memory by previous game data
+ GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; //clean "GC holes" left in the memory by previous game data
GC.Collect(); //https://docs.microsoft.com/en-us/dotnet/api/system.runtime.gcsettings.largeobjectheapcompactionmode?view=net-5.0
return true;
@@ -725,8 +725,8 @@ private async Task LoadFile(string filename, bool preventClose = false)
});
dialog.ShowDialog();
await t;
-
- GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; //clean "GC holes" left in the memory by previous game data
+
+ GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; //clean "GC holes" left in the memory by previous game data
GC.Collect(); //https://docs.microsoft.com/en-us/dotnet/api/system.runtime.gcsettings.largeobjectheapcompactionmode?view=net-5.0
}
@@ -1045,7 +1045,7 @@ await Task.Run(async () => {
{
fs.Write(Encoding.UTF8.GetBytes(hash + '\n'));
fs.Write(SystemJson.JsonSerializer.SerializeToUtf8Bytes(sortedCache));
-
+
if (Data.GMLCacheFailed.Count > 0)
{
fs.WriteByte((byte)'\n');
@@ -1071,7 +1071,7 @@ public async Task GenerateGMLCache(ThreadLocal dec
if (Data.GMLCache is null)
Data.GMLCache = new();
-
+
ConcurrentBag failedBag = new();
if (scriptDialog is null)
@@ -1120,7 +1120,7 @@ await Task.Run(() => Parallel.ForEach(Data.Code, (code) =>
}
}
- IncProgressP();
+ IncrementProgressParallel();
}));
Data.GMLEditedBefore = new(Data.GMLCacheChanged);
@@ -1170,7 +1170,7 @@ await Task.Run(() => Parallel.ForEach(codeToUpdate.Select(x => Data.Code.ByName(
}
}
- IncProgressP();
+ IncrementProgressParallel();
}));
if (isSaving)
@@ -1295,7 +1295,7 @@ private void TreeView_Drop(object sender, DragEventArgs e)
TreeViewItem targetTreeItem = VisualUpwardSearch(e.OriginalSource as UIElement);
UndertaleObject targetItem = targetTreeItem.DataContext as UndertaleObject;
- e.Effects = (e.AllowedEffects.HasFlag(DragDropEffects.Move) && sourceItem != null && targetItem != null && sourceItem != targetItem &&
+ e.Effects = (e.AllowedEffects.HasFlag(DragDropEffects.Move) && sourceItem != null && targetItem != null && sourceItem != targetItem &&
sourceItem.GetType() == targetItem.GetType() && SettingsWindow.AssetOrderSwappingEnabled)
? DragDropEffects.Move : DragDropEffects.None;
if (e.Effects == DragDropEffects.Move)
@@ -1532,7 +1532,7 @@ private void MenuItem_Add_Click(object sender, RoutedEventArgs e)
(obj as UndertaleRoom).Caption = Data.Strings.MakeString("");
if (IsGMS2 == Visibility.Visible)
- (obj as UndertaleRoom).Flags |= UndertaleRoom.RoomEntryFlags.IsGMS2;
+ (obj as UndertaleRoom).Flags |= UndertaleRoom.RoomEntryFlags.IsGMS2;
}
if (obj is UndertaleScript)
@@ -1682,15 +1682,15 @@ public void AddProgress(int amount)
{
progressValue += amount;
}
- public void IncProgress()
+ public void IncrementProgress()
{
progressValue++;
}
- public void AddProgressP(int amount) //P - Parallel (multithreaded)
+ public void AddProgressParallel(int amount) //P - Parallel (multithreaded)
{
Interlocked.Add(ref progressValue, amount); //thread-safe add operation (not the same as "lock ()")
}
- public void IncProgressP()
+ public void IncrementProgressParallel()
{
Interlocked.Increment(ref progressValue); //thread-safe increment
}
@@ -1702,13 +1702,13 @@ public void SetProgress(int value)
{
progressValue = value;
}
-
+
public void EnableUI()
{
if (!this.IsEnabled)
this.IsEnabled = true;
}
-
+
public void SyncBinding(string resourceType, bool enable)
{
if (resourceType.Contains(',')) //if several types are listed
@@ -1780,7 +1780,7 @@ private void ProgressUpdater()
return;
}
}
-
+
UpdateProgressValue(progressValue);
prevValue = progressValue;
@@ -1823,7 +1823,7 @@ public void OpenCodeFile(string name, CodeEditorMode editorDecompile)
if (code is not null)
{
Focus();
-
+
CodeEditorDecompile = editorDecompile;
HighlightObject(code);
@@ -1865,7 +1865,7 @@ public string ProcessException(in Exception exc, in string scriptText)
traceLines.AddRange(exc.InnerException.StackTrace.Split(Environment.NewLine));
}
- traceLines.AddRange(exc.StackTrace.Split(Environment.NewLine));
+ traceLines.AddRange(exc.StackTrace.Split(Environment.NewLine));
try
{
@@ -1929,7 +1929,7 @@ public async Task RunScript(string path)
scriptDialog.Owner = this;
scriptDialog.PreventClose = true;
this.IsEnabled = false; // Prevent interaction while the script is running.
-
+
await RunScriptNow(path); // Runs the script now.
HideProgressBar(); // Hide the progress bar.
scriptDialog = null;
@@ -1946,12 +1946,12 @@ private async Task RunScriptNow(string path)
{
if (!scriptSetupTask.IsCompleted)
await scriptSetupTask;
-
+
ScriptPath = path;
string compatScriptText = Regex.Replace(scriptText, @"\bDecompileContext\b", "GlobalDecompileContext", RegexOptions.None);
object result = await CSharpScript.EvaluateAsync(compatScriptText, scriptOptions, this, typeof(IScriptInterface));
-
+
if (FinishedMessageEnabled)
{
Dispatcher.Invoke(() => CommandBox.Text = result != null ? result.ToString() : Path.GetFileName(path) + " finished!");
@@ -1999,12 +1999,12 @@ public string PromptLoadFile(string defaultExt, string filter)
}
#pragma warning disable CA1416
- public string PromptChooseDirectory(string prompt)
+ public string PromptChooseDirectory()
{
VistaFolderBrowserDialog folderBrowser = new VistaFolderBrowserDialog();
return folderBrowser.ShowDialog() == true ? folderBrowser.SelectedPath : null;
}
-
+
#pragma warning disable CA1416
public void PlayInformationSound()
{
@@ -2094,26 +2094,26 @@ public string SimpleTextInput(string titleText, string labelText, string default
}
else //if we don't need to wait for result
{
- input.Show();
+ input.Show();
return null;
//no need to call input.Dispose(), because if form wasn't shown modally, Form.Close() (or closing it with "X") also calls Dispose()
}
}
- public void SimpleTextOutput(string titleText, string labelText, string defaultText, bool isMultiline)
+ public void SimpleTextOutput(string titleText, string labelText, string message, bool isMultiline)
{
- TextInput textOutput = new TextInput(labelText, titleText, defaultText, isMultiline, true); //read-only mode
+ TextInput textOutput = new TextInput(labelText, titleText, message, isMultiline, true); //read-only mode
textOutput.Show();
}
public async Task ClickableTextOutput(string title, string query, int resultsCount, IOrderedEnumerable>> resultsDict, bool editorDecompile, IOrderedEnumerable failedList = null)
{
await Task.Delay(150); //wait until progress bar status is displayed
-
+
ClickableTextOutput textOutput = new(title, query, resultsCount, resultsDict, editorDecompile, failedList);
await textOutput.Dispatcher.InvokeAsync(textOutput.GenerateResults);
_ = Task.Factory.StartNew(textOutput.FillingNotifier, TaskCreationOptions.LongRunning); //"LongRunning" = prefer creating a new thread
-
+
textOutput.Show();
PlayInformationSound();
@@ -2137,9 +2137,9 @@ public void ScriptOpenURL(string url)
OpenBrowser(url);
}
- public string ScriptInputDialog(string titleText, string labelText, string defaultInputBoxText, string cancelButtonText, string submitButtonText, bool isMultiline, bool preventClose)
+ public string ScriptInputDialog(string title, string label, string defaultInput, string cancelText, string submitText, bool isMultiline, bool preventClose)
{
- TextInputDialog dlg = new TextInputDialog(titleText, labelText, defaultInputBoxText, cancelButtonText, submitButtonText, isMultiline, preventClose);
+ TextInputDialog dlg = new TextInputDialog(title, label, defaultInput, cancelText, submitText, isMultiline, preventClose);
bool? dlgResult = dlg.ShowDialog();
if (!dlgResult.HasValue || dlgResult == false)
@@ -2348,7 +2348,7 @@ public async void UpdateApp(SettingsWindow window)
return;
}
}
-
+
JObject artifact = null;
for (int index = 0; index < artifactList.Count; index++) {
var currentArtifact = (JObject) artifactList[index];
@@ -2688,11 +2688,11 @@ public void UpdateObjectLabel(object obj)
SetIDString(foundIndex == -1 ? "None" : (foundIndex == -2 ? "N/A" : Convert.ToString(foundIndex)));
}
- public void ChangeSelection(object newsel)
+ public void ChangeSelection(object newSelection)
{
SelectionHistory.Add(Selected);
- Selected = newsel;
- UpdateObjectLabel(newsel);
+ Selected = newSelection;
+ UpdateObjectLabel(newSelection);
}
public void HighlightObject(object obj, bool silent = true)
{
@@ -2716,7 +2716,7 @@ public void HighlightObject(object obj, bool silent = true)
ScrollViewer mainTreeViewer = FindVisualChild(MainTree);
Type objType = res.GetType();
-
+
TreeViewItem resListView = (MainTree.Items[0] as TreeViewItem).Items.Cast()
.FirstOrDefault(x => (x.ItemTemplate?.DataType as Type) == objType);
IList resList;
diff --git a/UndertaleModTool/ProfileSystem.cs b/UndertaleModTool/ProfileSystem.cs
index 2d799d0c9..1eb235997 100644
--- a/UndertaleModTool/ProfileSystem.cs
+++ b/UndertaleModTool/ProfileSystem.cs
@@ -397,7 +397,7 @@ public void DirectoryCopy(string sourceDirName, string destDirName, bool copySub
DirectoryInfo[] dirs = dir.GetDirectories();
- // If the destination directory doesn't exist, create it.
+ // If the destination directory doesn't exist, create it.
Directory.CreateDirectory(destDirName);
// Get the files in the directory and copy them to the new location.
@@ -434,49 +434,5 @@ public void DirectoryCopy(string sourceDirName, string destDirName, bool copySub
MessageBox.Show("DirectoryCopy error! Send this to Grossley#2869 and make an issue on Github\n" + exc.ToString());
}
}
-
- public bool AreFilesIdentical(string file1, string file2)
- {
- int file1byte, file2byte;
- FileStream fs1, fs2;
-
- // Open the two files.
- fs1 = new FileStream(file1, FileMode.Open);
- fs2 = new FileStream(file2, FileMode.Open);
-
- // Check the file sizes. If they are not the same, the files
- // are not the same.
- if (fs1.Length != fs2.Length)
- {
- // Close the files
- fs1.Close();
- fs2.Close();
-
- // Return false to indicate files are different
- return false;
- }
- else
- {
- // Read and compare a byte from each file until either a
- // non-matching set of bytes is found or until the end of
- // file1 is reached.
- do
- {
- // Read one byte from each file.
- file1byte = fs1.ReadByte();
- file2byte = fs2.ReadByte();
- }
- while (file1byte == file2byte && file1byte != -1);
-
- // Close the files.
- fs1.Close();
- fs2.Close();
-
- // Return the success of the comparison. "file1byte" is
- // equal to "file2byte" at this point only if the files are
- // the same.
- return (file1byte - file2byte) == 0;
- }
- }
}
}
diff --git a/UndertaleModTool/ScriptingFunctions.cs b/UndertaleModTool/ScriptingFunctions.cs
index deb165328..fc0b8f3bf 100644
--- a/UndertaleModTool/ScriptingFunctions.cs
+++ b/UndertaleModTool/ScriptingFunctions.cs
@@ -21,48 +21,6 @@ namespace UndertaleModTool
// Adding misc. scripting functions here
public partial class MainWindow : Window, INotifyPropertyChanged, IScriptInterface
{
- public bool SendAUMIMessage(IpcMessage_t ipMessage, ref IpcReply_t outReply)
- {
- // By Archie
- const int ReplySize = 132;
-
- // Create the pipe
- using var pPipeServer = new NamedPipeServerStream("AUMI-IPC", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
-
- // Wait 1/8th of a second for AUMI to connect.
- // If it doesn't connect in time (which it should), just return false to avoid a deadlock.
- if (!pPipeServer.IsConnected)
- {
- pPipeServer.WaitForConnectionAsync();
- Thread.Sleep(125);
- if (!pPipeServer.IsConnected)
- {
- pPipeServer.DisposeAsync();
- return false;
- }
- }
-
- try
- {
- //Send the message
- pPipeServer.Write(ipMessage.RawBytes());
- pPipeServer.Flush();
- }
- catch (Exception e)
- {
- // Catch any errors that might arise if the connection is broken
- ScriptError("Could not write data to the pipe!\nError: " + e.Message);
- return false;
- }
-
- // Read the reply, the length of which is always a pre-set amount of bytes.
- byte[] bBuffer = new byte[ReplySize];
- pPipeServer.Read(bBuffer, 0, ReplySize);
-
- outReply = IpcReply_t.FromBytes(bBuffer);
- return true;
- }
-
public bool RunUMTScript(string path)
{
// By Grossley
diff --git a/UndertaleModTool/UndertaleModTool.csproj b/UndertaleModTool/UndertaleModTool.csproj
index 62d6ee96a..71284c929 100644
--- a/UndertaleModTool/UndertaleModTool.csproj
+++ b/UndertaleModTool/UndertaleModTool.csproj
@@ -1,6 +1,7 @@
net5.0-windows
+ LatestMajor
WinExe
publish\
true
@@ -25,6 +26,7 @@
embedded
AnyCPU;x64
win-x64;win-x86
+ 10
UndertaleModTool.Program
From ad6caab0e41687920c088e42fee47b23fe633e79 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Thu, 24 Mar 2022 20:54:30 +0100
Subject: [PATCH 02/18] Mostly document UndertaleData and GeneralInfo
---
.../Models/UndertaleGeneralInfo.cs | 242 +++++++++++++++++-
UndertaleModLib/UndertaleBaseTypes.cs | 11 +-
UndertaleModLib/UndertaleData.cs | 208 ++++++++++++++-
3 files changed, 444 insertions(+), 17 deletions(-)
diff --git a/UndertaleModLib/Models/UndertaleGeneralInfo.cs b/UndertaleModLib/Models/UndertaleGeneralInfo.cs
index b6a41b999..6b8171b02 100644
--- a/UndertaleModLib/Models/UndertaleGeneralInfo.cs
+++ b/UndertaleModLib/Models/UndertaleGeneralInfo.cs
@@ -8,32 +8,82 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// General info about a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleGeneralInfo : UndertaleObject
{
+ ///
+ /// Information flags a data file can use.
+ ///
[Flags]
public enum InfoFlags : uint
{
- Fullscreen = 0x0001, // Start fullscreen
- SyncVertex1 = 0x0002, // Use synchronization to avoid tearing
+ ///
+ /// Start fullscreen
+ ///
+ Fullscreen = 0x0001,
+ ///
+ /// Use synchronization to avoid tearing
+ ///
+ SyncVertex1 = 0x0002,
+ ///
+ /// Use synchronization to avoid tearing
+ ///
SyncVertex2 = 0x0004,
- Interpolate = 0x0008, // Interpolate colours between pixels
- Scale = 0x0010, // Scaling: Keep aspect
- ShowCursor = 0x0020, // Display cursor
- Sizeable = 0x0040, // Allow window resize
- ScreenKey = 0x0080, // Allow fullscreen switching
+ ///
+ /// Interpolate colours between pixels
+ ///
+ Interpolate = 0x0008,
+ ///
+ /// Scaling: Keep aspect
+ ///
+ Scale = 0x0010,
+ ///
+ /// Display cursor
+ ///
+ ShowCursor = 0x0020,
+ ///
+ /// Allow window resize
+ ///
+ Sizeable = 0x0040,
+ ///
+ /// Allow fullscreen switching
+ ///
+ ScreenKey = 0x0080,
+
SyncVertex3 = 0x0100,
StudioVersionB1 = 0x0200,
StudioVersionB2 = 0x0400,
StudioVersionB3 = 0x0800,
- StudioVersionMask = 0x0E00, // studioVersion = (infoFlags & InfoFlags.StudioVersionMask) >> 9
- SteamEnabled = 0x1000, // Enable Steam
+
+ ///
+ /// studioVersion = (infoFlags & InfoFlags.StudioVersionMask) >> 9
+ ///
+ StudioVersionMask = 0x0E00,
+ ///
+ /// Enable Steam
+ ///
+ SteamEnabled = 0x1000,
+
LocalDataEnabled = 0x2000,
- BorderlessWindow = 0x4000, // Borderless Window
- JavaScriptMode = 0x8000, // Tells the runner to run Javascript code
+
+ ///
+ /// Borderless Window
+ ///
+ BorderlessWindow = 0x4000,
+ ///
+ /// Tells the runner to run Javascript code
+ ///
+ JavaScriptMode = 0x8000,
+
LicenseExclusions = 0x10000,
}
+ ///
+ /// Function classifications a data file can have.
+ ///
[Flags]
public enum FunctionClassification : ulong
{
@@ -106,38 +156,132 @@ public enum FunctionClassification : ulong
}
public bool DisableDebugger { get; set; } = true;
+
+ ///
+ /// The bytecode version of the data file.
+ ///
public byte BytecodeVersion { get; set; } = 0x10;
+
public ushort Unknown { get; set; } = 0;
+
public UndertaleString Filename { get; set; }
public UndertaleString Config { get; set; }
+
+ ///
+ /// The last object id of the data file.
+ ///
public uint LastObj { get; set; } = 100000;
+
+ ///
+ /// The last tile id of the data file.
+ ///
public uint LastTile { get; set; } = 10000000;
+
+ ///
+ /// The game id of the data file.
+ ///
public uint GameID { get; set; } = 13371337;
- public Guid DirectPlayGuid { get; set; } = Guid.Empty; // in Studio it's always empty.
+
+ ///
+ /// The DirectPlay GUID of the data file
+ ///
+ /// This is always empty in Game Maker: Studio.
+ public Guid DirectPlayGuid { get; set; } = Guid.Empty;
+
+
public UndertaleString Name { get; set; }
+
+ ///
+ /// The major version of the data file.
+ ///
public uint Major { get; set; } = 1;
+
+ ///
+ /// The minor version of the data file.
+ ///
public uint Minor { get; set; } = 0;
+
+ ///
+ /// The Release version of the data file.
+ ///
public uint Release { get; set; } = 0;
+
+ ///
+ /// The build version of the data file.
+ ///
public uint Build { get; set; } = 1337;
+
+ ///
+ /// The default window width of the game.
+ ///
public uint DefaultWindowWidth { get; set; } = 1024;
+
+ ///
+ /// The default window height of the game.
+ ///
public uint DefaultWindowHeight { get; set; } = 768;
+
+ ///
+ /// The info flags of the data file.
+ ///
public InfoFlags Info { get; set; } = InfoFlags.Interpolate | InfoFlags.Scale | InfoFlags.ShowCursor | InfoFlags.ScreenKey | InfoFlags.StudioVersionB3;
+
+ ///
+ /// The MD5 of the license used to compile the game.
+ ///
public byte[] LicenseMD5 { get; set; } = new byte[16];
+
+ ///
+ /// The CRC32 of the license used to compile the game.
+ ///
public uint LicenseCRC32 { get; set; }
+
+ ///
+ /// The UNIX timestamp the game was compiled.
+ ///
public ulong Timestamp { get; set; } = 0;
+
+ ///
+ /// The name that gets displayed in the window.
+ ///
public UndertaleString DisplayName { get; set; }
+
+
public ulong ActiveTargets { get; set; } = 0;
public FunctionClassification FunctionClassifications { get; set; } = FunctionClassification.None; // Initializing it with None is a very bad idea.
+
+ ///
+ /// The Steam app id of the game.
+ ///
public int SteamAppID { get; set; } = 0;
+
+ ///
+ /// The port the data file exposes for the debugger.
+ ///
public uint DebuggerPort { get; set; } = 6502;
+
+ ///
+ /// The room order of the data file.
+ ///
public UndertaleSimpleResourcesList RoomOrder { get; private set; } = new UndertaleSimpleResourcesList();
public List GMS2RandomUID { get; set; } = new List(); // Some sort of checksum
+ ///
+ /// The FPS of the data file. Game Maker Studio: 2 only.
+ ///
public float GMS2FPS { get; set; } = 30.0f;
+
+ ///
+ /// Whether the data file allows statistics. Game Maker Studio: 2 only.
+ ///
public bool GMS2AllowStatistics { get; set; } = true;
+
+
public byte[] GMS2GameGUID { get; set; } = new byte[16]; // more high entropy data
+ ///
+ /// If or has an invalid length.
public void Serialize(UndertaleWriter writer)
{
writer.Write(DisableDebugger ? (byte)1 : (byte)0);
@@ -305,20 +449,51 @@ public override string ToString()
}
}
+ ///
+ /// General options about a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleOptions : UndertaleObject
{
+ ///
+ /// Option flags a data file can use
+ ///
[Flags]
public enum OptionsFlags : ulong
{
+ ///
+ /// If game should start in fullscreen.
+ ///
FullScreen = 0x1,
+ ///
+ /// If pixels should be interpolated.
+ ///
InterpolatePixels = 0x2,
+ ///
+ /// If the new audio format should be used.
+ ///
UseNewAudio = 0x4,
+ ///
+ /// If borderless window should be used.
+ ///
NoBorder = 0x8,
+ ///
+ /// If the mouse cursor should be shown.
+ ///
ShowCursor = 0x10,
+ ///
+ /// If the window should be resizable.
+ ///
Sizeable = 0x20,
+ ///
+ /// If the window should stay on top.
+ ///
StayOnTop = 0x40,
+ ///
+ /// If the resolution can be changed.
+ ///
ChangeResolution = 0x80,
+
NoButtons = 0x100,
ScreenKey = 0x200,
HelpKey = 0x400,
@@ -344,26 +519,69 @@ public enum OptionsFlags : ulong
public uint Unknown1 { get; set; } = 0x80000000;
public uint Unknown2 { get; set; } = 0x00000002;
+
+ ///
+ /// Option flags the data file uses.
+ ///
public OptionsFlags Info { get; set; } = OptionsFlags.InterpolatePixels | OptionsFlags.UseNewAudio | OptionsFlags.ShowCursor | OptionsFlags.ScreenKey | OptionsFlags.QuitKey | OptionsFlags.SaveKey | OptionsFlags.ScreenShotKey | OptionsFlags.CloseSec | OptionsFlags.ScaleProgress | OptionsFlags.DisplayErrors | OptionsFlags.VariableErrors | OptionsFlags.CreationEventOrder;
+
+ ///
+ /// The window scale.
+ ///
public int Scale { get; set; } = -1;
+
+ ///
+ /// The window color.
+ ///
public uint WindowColor { get; set; } = 0;
+
+ ///
+ /// The Color depth.
+ ///
public uint ColorDepth { get; set; } = 0;
+
+ ///
+ /// The game's resolution.
+ ///
public uint Resolution { get; set; } = 0;
+
+ ///
+ /// The game's refresh rate.
+ ///
public uint Frequency { get; set; } = 0;
+
+ ///
+ /// Whether the game uses V-Sync.
+ ///
public uint VertexSync { get; set; } = 0;
+
public uint Priority { get; set; } = 0;
public UndertaleSprite.TextureEntry BackImage { get; set; } = new UndertaleSprite.TextureEntry(); // Apparently these exist, but I can't find any examples of it
public UndertaleSprite.TextureEntry FrontImage { get; set; } = new UndertaleSprite.TextureEntry();
public UndertaleSprite.TextureEntry LoadImage { get; set; } = new UndertaleSprite.TextureEntry();
public uint LoadAlpha { get; set; } = 255;
+
+ ///
+ /// A list of Constants that the game uses.
+ ///
public UndertaleSimpleList Constants { get; private set; } = new UndertaleSimpleList();
public bool NewFormat { get; set; } = true;
+ ///
+ /// A class for game constants.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class Constant : UndertaleObject
{
+ ///
+ /// The name of the constant.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The value of the constant.
+ ///
public UndertaleString Value { get; set; }
public void Serialize(UndertaleWriter writer)
diff --git a/UndertaleModLib/UndertaleBaseTypes.cs b/UndertaleModLib/UndertaleBaseTypes.cs
index 90a6f152f..e11dcf82e 100644
--- a/UndertaleModLib/UndertaleBaseTypes.cs
+++ b/UndertaleModLib/UndertaleBaseTypes.cs
@@ -9,7 +9,16 @@ namespace UndertaleModLib
{
public interface UndertaleObject
{
+ ///
+ /// Serializes the data file into a specified .
+ ///
+ /// Where to serialize to.
void Serialize(UndertaleWriter writer);
+
+ ///
+ /// Deserializes from a specified to the current data file.
+ ///
+ ///
void Unserialize(UndertaleReader reader);
}
@@ -39,7 +48,7 @@ public interface PrePaddedObject
void SerializePrePadding(UndertaleWriter writer);
void UnserializePrePadding(UndertaleReader reader);
}
-
+
public enum ResourceType : int
{
None = -1,
diff --git a/UndertaleModLib/UndertaleData.cs b/UndertaleModLib/UndertaleData.cs
index 2414457b6..5b9332b49 100644
--- a/UndertaleModLib/UndertaleData.cs
+++ b/UndertaleModLib/UndertaleData.cs
@@ -10,6 +10,9 @@
namespace UndertaleModLib
{
+ ///
+ /// An object representing a Game Maker: Studio data file.
+ ///
public class UndertaleData
{
// access resource list by its name
@@ -64,28 +67,111 @@ public object this[Type resourceType]
public UndertaleChunkFORM FORM;
+ ///
+ /// General info of the data file.
+ ///
public UndertaleGeneralInfo GeneralInfo => FORM.GEN8?.Object;
+
+ ///
+ /// General Options of the data file.
+ ///
public UndertaleOptions Options => FORM.OPTN?.Object;
+
+ ///
+ /// Languages of the data file.
+ ///
public UndertaleLanguage Language => FORM.LANG?.Object;
+
+ ///
+ /// The used extensions of the data file.
+ ///
public IList Extensions => FORM.EXTN?.List;
+
+ ///
+ /// The used sounds of the data file.
+ ///
public IList Sounds => FORM.SOND?.List;
+
+ ///
+ /// The audio groups of the data file.
+ ///
public IList AudioGroups => FORM.AGRP?.List;
+
+ ///
+ /// The sprites of the data file.
+ ///
public IList Sprites => FORM.SPRT?.List;
+
+ ///
+ /// The backgrounds (or Tilesets) of the data file.
+ ///
public IList Backgrounds => FORM.BGND?.List;
+
+ ///
+ /// The paths of the data file.
+ ///
public IList Paths => FORM.PATH?.List;
+
+ ///
+ /// The scripts of the data file.
+ ///
public IList Scripts => FORM.SCPT?.List;
+
+ ///
+ /// The global initialization scripts of the data file.
+ ///
public IList GlobalInitScripts => FORM.GLOB?.List;
+
+ ///
+ /// The global end scripts of the data file.
+ ///
public IList GameEndScripts => FORM.GMEN?.List;
+
+ ///
+ /// The used shaders of the data file.
+ ///
public IList Shaders => FORM.SHDR?.List;
+
+ ///
+ /// The fonts of the data file.
+ ///
public IList Fonts => FORM.FONT?.List;
+
+ ///
+ /// The Timelines of the data file.
+ ///
public IList Timelines => FORM.TMLN?.List;
+
+ ///
+ /// The game objects of the data file.
+ ///
public IList GameObjects => FORM.OBJT?.List;
+
+ ///
+ /// The rooms of the data file.
+ ///
public IList Rooms => FORM.ROOM?.List;
//[Obsolete("Unused")]
// DataFile
+
+ ///
+ /// The texture page items from the data file.
+ ///
public IList TexturePageItems => FORM.TPAG?.List;
+
+ ///
+ /// The code entries of the data file.
+ ///
public IList Code => FORM.CODE?.List;
+
+ ///
+ /// The used variables of the data file.
+ ///
public IList Variables => FORM.VARI?.List;
+
+ ///
+ /// TODO: no idea what these are.
+ ///
public uint VarCount1 { get => FORM.VARI.VarCount1; set => FORM.VARI.VarCount1 = value; }
public uint VarCount2 { get => FORM.VARI.VarCount2; set => FORM.VARI.VarCount2 = value; }
public bool DifferentVarCounts { get => FORM.VARI.DifferentVarCounts; set => FORM.VARI.DifferentVarCounts = value; }
@@ -94,33 +180,114 @@ public object this[Type resourceType]
[Obsolete]
public uint InstanceVarCountAgain { get => VarCount2; set => VarCount2 = value; }
public uint MaxLocalVarCount { get => FORM.VARI.MaxLocalVarCount; set => FORM.VARI.MaxLocalVarCount = value; }
+
+ ///
+ /// The functions of the data file.
+ ///
public IList Functions => FORM.FUNC?.Functions;
+
+ ///
+ /// The code locals of the data file.
+ ///
public IList CodeLocals => FORM.FUNC?.CodeLocals;
+
+ ///
+ /// The used strings of the data file.
+ ///
public IList Strings => FORM.STRG?.List;
+
+ ///
+ /// The embedded images of the data file. This is used to store built-in particle sprites,
+ /// every time you use part_sprite functions.
+ ///
public IList EmbeddedImages => FORM.EMBI?.List;
+
+ ///
+ /// The embedded textures of the data file.
+ ///
public IList EmbeddedTextures => FORM.TXTR?.List;
+
+
public IList TextureGroupInfo => FORM.TGIN?.List;
+
+ ///
+ /// The embedded audio of the data file.
+ ///
public IList EmbeddedAudio => FORM.AUDO?.List;
+ //TODO?
public UndertaleTags Tags => FORM.TAGS?.Object;
+
+ ///
+ /// The animation curves of the data file.
+ ///
public IList AnimationCurves => FORM.ACRV?.List;
+
+ ///
+ /// The sequences of the data file.
+ ///
public IList Sequences => FORM.SEQN?.List;
+ ///
+ /// Whether this is an unsupported bytecode version
+ ///
public bool UnsupportedBytecodeVersion = false;
+
+ ///
+ /// Whether the Texture Page Items (TPGA) chunk is 4 byte aligned.
+ ///
public bool IsTPAG4ByteAligned = false;
+
+ ///
+ /// Whether the data file has short circuiting enabled.
+ ///
public bool ShortCircuit = true;
+
+ ///
+ /// Whether the data file is from version GMS2.2.2.302
+ ///
public bool GMS2_2_2_302 = false;
+
+ ///
+ /// Whether the data file is from version GMS2.3
+ ///
public bool GMS2_3 = false;
+
+ ///
+ /// Whether the data file is from version GMS2.3.1
+ ///
public bool GMS2_3_1 = false;
+
+ ///
+ /// Whether the data file is from version GMS2.3.2
+ ///
public bool GMS2_3_2 = false;
+
+ ///
+ /// Whether the data file uses the QOI format for images.
+ ///
public bool UseQoiFormat = false;
+
+ ///
+ /// Whether the data file uses BZip compression.
+ ///
public bool UseBZipFormat = false;
+
+ ///
+ /// Whether the data file is from version GMS2022.1
+ ///
public bool GMS2022_1 = false;
+
+
public ToolInfo ToolInfo = new ToolInfo();
public int PaddingAlignException = -1;
public BuiltinList BuiltinList;
- public Dictionary KnownSubFunctions; // Cache for known 2.3-style function names for compiler speedups. Can be re-built by setting this to null.
+
+ ///
+ /// Cache for known 2.3-style function names for compiler speedups. Can be re-built by setting this to null.
+ ///
+ public Dictionary KnownSubFunctions;
public ConcurrentDictionary GMLCache { get; set; }
public List GMLCacheFailed { get; set; }
@@ -130,6 +297,12 @@ public object this[Type resourceType]
public bool GMLCacheIsReady { get; set; } = true;
+ ///
+ /// Get a resource from the data file by name.
+ ///
+ /// The name of the desired resource.
+ /// Whether to ignore casing while searching.
+ ///
public UndertaleNamedResource ByName(string name, bool ignoreCase = false)
{
// TODO: Check if those are all possible types
@@ -150,6 +323,14 @@ public UndertaleNamedResource ByName(string name, bool ignoreCase = false)
(UndertaleNamedResource)null;
}
+ ///
+ /// Reports the zero-based index of the first occurence of the specified .
+ ///
+ /// The object to get the index of.
+ /// Whether to throw if is not a valid object.
+ /// The zero-based index position of the parameter if it is found or -2 if it is not.
+ /// is
+ /// and could not be found.
public int IndexOf(UndertaleNamedResource obj, bool panicIfInvalid = true)
{
if (obj is UndertaleSound)
@@ -197,7 +378,10 @@ internal int IndexOfByName(string line)
throw new NotImplementedException();
}
- // Test if this data.win was built by GameMaker Studio 2.
+ ///
+ /// Reports whether the data file was build by GameMaker Studio 2.
+ ///
+ /// if yes, if not.
public bool IsGameMaker2()
{
return IsVersionAtLeast(2, 0, 0, 0);
@@ -212,6 +396,14 @@ public bool TestGMS1Version(uint stableBuild, uint betaBuild, bool allowGMS2 = f
return (allowGMS2 || !IsGameMaker2()) && (IsVersionAtLeast(1, 0, 0, stableBuild) || (IsVersionAtLeast(1, 0, 0, betaBuild) && !IsVersionAtLeast(1, 0, 0, 1000)));
}
+ ///
+ /// Reports whether the version of the data file is the same or higher than a specified version.
+ ///
+ /// The major version.
+ /// The minor version.
+ /// The release version.
+ /// The build version.
+ ///
public bool IsVersionAtLeast(uint major, uint minor, uint release, uint build)
{
if (GeneralInfo.Major != major)
@@ -236,6 +428,10 @@ public int GetBuiltinSoundGroupID()
return TestGMS1Version(1354, 161, true) ? 0 : 1;
}
+ ///
+ /// Reports whether the data file was compiled with YYD
+ ///
+ /// if yes, if not.
public bool IsYYC()
{
return GeneralInfo != null && Code == null;
@@ -267,6 +463,10 @@ public uint ExtensionFindLastId()
return id;
}
+ ///
+ /// Creates a new empty data file.
+ ///
+ /// The newly created data file.
public static UndertaleData CreateNew()
{
UndertaleData data = new UndertaleData();
@@ -419,13 +619,13 @@ public static UndertaleVariable EnsureDefined(this IList list
oldId = (uint)id;
}
else if (!data.DifferentVarCounts)
- {
+ {
// Bytecode 16+
data.VarCount1++;
data.VarCount2++;
}
else
- {
+ {
// Bytecode 15
if (inst == UndertaleInstruction.InstanceType.Self && !isBuiltin)
{
From 8ea45f4e73f4cee9997b7b72a99813318bb585a5 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Thu, 24 Mar 2022 22:11:38 +0100
Subject: [PATCH 03/18] Attempt to document more stuff
Background, font, globalinit, script, shader, sound, sprite.
---
UndertaleModLib/Models/UndertaleBackground.cs | 31 ++++++++
UndertaleModLib/Models/UndertaleFont.cs | 72 +++++++++++++++++
UndertaleModLib/Models/UndertaleGlobalInit.cs | 9 ++-
UndertaleModLib/Models/UndertaleScript.cs | 13 ++++
UndertaleModLib/Models/UndertaleShader.cs | 75 ++++++++++++++++--
UndertaleModLib/Models/UndertaleSound.cs | 62 ++++++++++++++-
UndertaleModLib/Models/UndertaleSprite.cs | 78 ++++++++++++++++++-
7 files changed, 332 insertions(+), 8 deletions(-)
diff --git a/UndertaleModLib/Models/UndertaleBackground.cs b/UndertaleModLib/Models/UndertaleBackground.cs
index 5433d54cc..7efb52180 100644
--- a/UndertaleModLib/Models/UndertaleBackground.cs
+++ b/UndertaleModLib/Models/UndertaleBackground.cs
@@ -8,6 +8,9 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// A background (and tileset) entry in a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleBackground : UndertaleNamedResource
{
@@ -30,14 +33,42 @@ public void Unserialize(UndertaleReader reader)
}
}
+ ///
+ /// The name of the background.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// Whether the background should be transparent.
+ ///
public bool Transparent { get; set; }
+
+ ///
+ /// Whether the background should get smoothed.
+ ///
public bool Smooth { get; set; }
+
+ ///
+ /// Whether to preload the background.
+ ///
public bool Preload { get; set; }
+
+ ///
+ /// The this background uses.
+ ///
public UndertaleTexturePageItem Texture { get; set; }
public uint GMS2UnknownAlways2 { get; set; } = 2;
+
+ ///
+ /// The tile width of the tileset. Game Maker Studio 2 only.
+ ///
public uint GMS2TileWidth { get; set; } = 32;
+
+ ///
+ /// The tile height of the tileset. Game Maker Studio 2 only.
+ ///
public uint GMS2TileHeight { get; set; } = 32;
+
public uint GMS2OutputBorderX { get; set; } = 2;
public uint GMS2OutputBorderY { get; set; } = 2;
public uint GMS2TileColumns { get; set; } = 32;
diff --git a/UndertaleModLib/Models/UndertaleFont.cs b/UndertaleModLib/Models/UndertaleFont.cs
index e279ddf16..7e9db0978 100644
--- a/UndertaleModLib/Models/UndertaleFont.cs
+++ b/UndertaleModLib/Models/UndertaleFont.cs
@@ -7,33 +7,105 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// A font entry of a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleFont : UndertaleNamedResource
{
+ ///
+ /// The name of the font.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The display name of the font.
+ ///
public UndertaleString DisplayName { get; set; }
+
+ ///
+ /// Whether the Em size is a float.
+ ///
public bool EmSizeIsFloat { get; set; }
+
+ ///
+ /// The font size in Ems
+ ///
public uint EmSize { get; set; }
+
+ ///
+ /// Whether to display the font in bold.
+ ///
public bool Bold { get; set; }
+
+ ///
+ /// Whether to display the font in italics
+ ///
public bool Italic { get; set; }
+
+
public ushort RangeStart { get; set; }
public byte Charset { get; set; }
public byte AntiAliasing { get; set; }
public uint RangeEnd { get; set; }
+
+
+ ///
+ /// The object that contains the texture for this font.
+ ///
public UndertaleTexturePageItem Texture { get; set; }
+
+ ///
+ /// The x scale this font uses.
+ ///
public float ScaleX { get; set; }
+
+ ///
+ /// The y scale this font uses.
+ ///
public float ScaleY { get; set; }
+
+ ///
+ /// The glyphs that this font uses.
+ ///
public UndertalePointerList Glyphs { get; private set; } = new UndertalePointerList();
+
+
public int AscenderOffset { get; set; }
+
+ ///
+ /// Glyphs that a font can use.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class Glyph : UndertaleObject
{
+ ///
+ /// The character for the glyph.
+ ///
public ushort Character { get; set; }
+
+ ///
+ /// The x position in the where the glyph can be found.
+ ///
public ushort SourceX { get; set; }
+
+ ///
+ /// The y position in the where the glyph can be found.
+ ///
public ushort SourceY { get; set; }
+
+ ///
+ /// The width of the glyph.
+ ///
public ushort SourceWidth { get; set; }
+
+ ///
+ /// The height of the glyph.
+ ///
public ushort SourceHeight { get; set; }
+
+
public short Shift { get; set; }
public short Offset { get; set; }
public UndertaleSimpleListShort Kerning { get; set; } = new UndertaleSimpleListShort();
diff --git a/UndertaleModLib/Models/UndertaleGlobalInit.cs b/UndertaleModLib/Models/UndertaleGlobalInit.cs
index 5486d6abf..18efb587d 100644
--- a/UndertaleModLib/Models/UndertaleGlobalInit.cs
+++ b/UndertaleModLib/Models/UndertaleGlobalInit.cs
@@ -7,10 +7,17 @@
namespace UndertaleModLib.Models
{
- // NOTE: Never seen in GMS1.4 so I'm not sure if the structure was the same
+ ///
+ /// A global initialization entry in a data file.
+ ///
+ /// Never seen in GMS1.4 so uncertain if the structure was the same.
public class UndertaleGlobalInit : UndertaleObject, INotifyPropertyChanged
{
private UndertaleResourceById _Code = new UndertaleResourceById();
+
+ ///
+ /// The object which contains the code.
+ ///
public UndertaleCode Code { get => _Code.Resource; set { _Code.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Code))); } }
public event PropertyChangedEventHandler PropertyChanged;
diff --git a/UndertaleModLib/Models/UndertaleScript.cs b/UndertaleModLib/Models/UndertaleScript.cs
index 6f67e86d0..87882f03d 100644
--- a/UndertaleModLib/Models/UndertaleScript.cs
+++ b/UndertaleModLib/Models/UndertaleScript.cs
@@ -7,11 +7,24 @@
namespace UndertaleModLib.Models
{
+
+ ///
+ /// A script entry in a data file.
+ ///
public class UndertaleScript : UndertaleNamedResource, INotifyPropertyChanged
{
+ ///
+ /// The name of the script entry.
+ ///
public UndertaleString Name { get; set; }
private UndertaleResourceById _Code = new UndertaleResourceById();
+
+ ///
+ /// The object which contains the code.
+ ///
public UndertaleCode Code { get => _Code.Resource; set { _Code.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Code))); } }
+
+
public bool Constructor { get; set; } = false;
public event PropertyChangedEventHandler PropertyChanged;
diff --git a/UndertaleModLib/Models/UndertaleShader.cs b/UndertaleModLib/Models/UndertaleShader.cs
index a3014453d..50e23d477 100644
--- a/UndertaleModLib/Models/UndertaleShader.cs
+++ b/UndertaleModLib/Models/UndertaleShader.cs
@@ -7,12 +7,21 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// A shader entry for a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleShader : UndertaleNamedResource
{
+ ///
+ /// The vertex shader attributes a shader can have.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class VertexShaderAttribute : UndertaleObject
{
+ ///
+ /// The name of the vertex shader attribute.
+ ///
public UndertaleString Name { get; set; }
public void Serialize(UndertaleWriter writer)
@@ -28,14 +37,44 @@ public void Unserialize(UndertaleReader reader)
public uint _EntryEnd;
+ ///
+ /// The name of the shader.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The type the shader uses.
+ ///
public ShaderType Type { get; set; }
+ ///
+ /// The GLSL ES vertex code this shader uses.
+ ///
public UndertaleString GLSL_ES_Vertex { get; set; }
+
+ ///
+ /// The GLSL ES fragment code this shader uses.
+ ///
public UndertaleString GLSL_ES_Fragment { get; set; }
+
+ ///
+ /// The GLSL vertex code this shader uses.
+ ///
public UndertaleString GLSL_Vertex { get; set; }
+
+ ///
+ /// The GLSL fragment code this shader uses.
+ ///
public UndertaleString GLSL_Fragment { get; set; }
+
+ ///
+ /// The HLSL9 vertex code this shader uses.
+ ///
public UndertaleString HLSL9_Vertex { get; set; }
+
+ ///
+ /// The HLSL9 fragment code this shader uses.
+ ///
public UndertaleString HLSL9_Fragment { get; set; }
public int Version { get; set; } = 2;
@@ -308,17 +347,43 @@ public void Unserialize(UndertaleReader reader)
}
}
- // PSSL is a shading language used only in PS4, based on HLSL11.
- // Cg stands for "C for graphics" made by NVIDIA and used in PSVita and PS3 (they have their own variants of Cg), based on HLSL9.
- // All console shaders (and HLSL11?) are compiled using confidential SDK tools when GMAssetCompiler builds the game (for PSVita it's psp2cgc shader compiler).
+ ///
+ /// Possible shader types a shader can have.
+ ///
+ /// All console shaders (and HLSL11?) are compiled using confidential SDK tools when
+ /// GMAssetCompiler builds the game (for PSVita it's psp2cgc shader compiler).
public enum ShaderType : uint
{
+ ///
+ /// Shader uses GLSL_ES
+ ///
GLSL_ES = 1,
+ ///
+ /// Shader uses GLSL
+ ///
GLSL = 2,
+ ///
+ /// Shader uses HLSL9
+ ///
HLSL9 = 3,
+ ///
+ /// Shader uses HLSL11
+ ///
HLSL11 = 4,
+ ///
+ /// Shader uses PSSL
+ ///
+ /// PSSL is a shading language used only in PS4, based on HLSL11.
PSSL = 5,
+ ///
+ /// Shader uses for the PSVita
+ ///
+ /// Cg stands for "C for graphics" made by NVIDIA and used in PSVita and PS3 (they have their own variants of Cg), based on HLSL9.
Cg_PSVita = 6,
+ ///
+ /// Shader uses Cg for the PS3
+ ///
+ /// Cg stands for "C for graphics" made by NVIDIA and used in PSVita and PS3 (they have their own variants of Cg), based on HLSL9.
Cg_PS3 = 7
}
@@ -348,14 +413,14 @@ public void Serialize(UndertaleWriter writer, bool writeLength = true)
if (writeLength)
writer.Write((Data == null) ? 0 : Data.Length);
}
-
+
public void Unserialize(UndertaleReader reader, bool readLength = true)
{
_PointerLocation = reader.Position;
_Position = reader.ReadUInt32();
if (readLength)
_Length = reader.ReadUInt32();
-
+
IsNull = (_Position == 0x00000000u);
}
diff --git a/UndertaleModLib/Models/UndertaleSound.cs b/UndertaleModLib/Models/UndertaleSound.cs
index cd9d11f0d..1c9401576 100644
--- a/UndertaleModLib/Models/UndertaleSound.cs
+++ b/UndertaleModLib/Models/UndertaleSound.cs
@@ -7,31 +7,88 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// Sound entry in a data file.
+ ///
public class UndertaleSound : UndertaleNamedResource, INotifyPropertyChanged
{
+ ///
+ /// Audio entry flags a sound entry can use.
+ ///
[Flags]
public enum AudioEntryFlags : uint
{
+ ///
+ /// Whether the sound is embedded.
+ ///
IsEmbedded = 0x1,
+ ///
+ /// Whether the sound is compressed.
+ ///
IsCompressed = 0x2,
+
IsDecompressedOnLoad = 0x3,
Regular = 0x64, // also means "Use New Audio System?" Set by default on GMS 2.
}
+ ///
+ /// The name of the sound entry.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The flags the sound entry uses.
+ ///
public AudioEntryFlags Flags { get; set; } = AudioEntryFlags.IsEmbedded;
+
+ ///
+ /// The file format of the audio entry.
+ ///
public UndertaleString Type { get; set; }
+
+ ///
+ /// The file name of the audio entry.
+ ///
public UndertaleString File { get; set; }
+
public uint Effects { get; set; } = 0;
+
+ ///
+ /// The volume the audio entry is played at.
+ ///
public float Volume { get; set; } = 1;
+
+ ///
+ /// Whether the audio entry should be preloaded.
+ ///
public bool Preload { get; set; } = true;
+
+ ///
+ /// The pitch change of the audio entry.
+ ///
public float Pitch { get; set; } = 0;
private UndertaleResourceById _AudioGroup = new UndertaleResourceById();
private UndertaleResourceById _AudioFile = new UndertaleResourceById();
+
+ ///
+ /// The audio group this audio entry belongs to.
+ ///
public UndertaleAudioGroup AudioGroup { get => _AudioGroup.Resource; set { _AudioGroup.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AudioGroup))); } }
+
+ ///
+ /// The reference to the audio file.
+ ///
public UndertaleEmbeddedAudio AudioFile { get => _AudioFile.Resource; set { _AudioFile.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AudioFile))); } }
+
+ ///
+ /// The id of .
+ ///
public int AudioID { get => _AudioFile.CachedId; set { _AudioFile.CachedId = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AudioID))); } }
+
+ ///
+ /// The id of .
+ ///
public int GroupID { get => _AudioGroup.CachedId; set { _AudioGroup.CachedId = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GroupID))); } }
public event PropertyChangedEventHandler PropertyChanged;
@@ -78,7 +135,7 @@ public void Unserialize(UndertaleReader reader)
Preload = reader.ReadBoolean();
}
- if (GroupID == reader.undertaleData.GetBuiltinSoundGroupID())
+ if (GroupID == reader.undertaleData.GetBuiltinSoundGroupID())
{
_AudioFile = reader.ReadUndertaleObject>();
}
@@ -94,6 +151,9 @@ public override string ToString()
}
}
+ ///
+ /// Audio group entry in a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleAudioGroup : UndertaleNamedResource
{
diff --git a/UndertaleModLib/Models/UndertaleSprite.cs b/UndertaleModLib/Models/UndertaleSprite.cs
index c0197ab11..cb8d32d36 100644
--- a/UndertaleModLib/Models/UndertaleSprite.cs
+++ b/UndertaleModLib/Models/UndertaleSprite.cs
@@ -44,23 +44,84 @@ public override string ToString()
}
}
+ ///
+ /// Sprite entry in the data file.
+ ///
public class UndertaleSprite : UndertaleNamedResource, PrePaddedObject, INotifyPropertyChanged
{
+ ///
+ /// The name of the sprite.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The width of the sprite.
+ ///
public uint Width { get; set; }
+
+ ///
+ /// The height of the sprite.
+ ///
public uint Height { get; set; }
+
+ ///
+ /// The left margin of the sprite.
+ ///
public int MarginLeft { get; set; }
+
+ ///
+ /// The right margin of the sprite.
+ ///
public int MarginRight { get; set; }
+
+ ///
+ /// The bottom margin of the sprite.
+ ///
public int MarginBottom { get; set; }
+
+ ///
+ /// The top margin of the sprite.
+ ///
public int MarginTop { get; set; }
+
+ ///
+ /// Whether the sprite should be transparent.
+ ///
public bool Transparent { get; set; }
+
+ ///
+ /// Whether the sprite should get smoothed.
+ ///
public bool Smooth { get; set; }
+
+ ///
+ /// Whether the sprite should get preloaded.
+ ///
public bool Preload { get; set; }
+
+
public uint BBoxMode { get; set; }
public SepMaskType SepMasks { get; set; }
+
+
+ ///
+ /// The x-coordinate of the origin of the sprite.
+ ///
public int OriginX { get; set; }
+
+ ///
+ /// The y-coordinate of the origin of the sprite.
+ ///
public int OriginY { get; set; }
+
+ ///
+ /// The frames of the sprite.
+ ///
public UndertaleSimpleList Textures { get; private set; } = new UndertaleSimpleList();
+
+ ///
+ /// The collision masks of the sprite.
+ ///
public ObservableCollection CollisionMasks { get; } = new ObservableCollection();
// Special sprite types (always used in GMS2)
@@ -103,13 +164,28 @@ public MaskEntry NewMaskEntry()
return newEntry;
}
+ ///
+ /// Different formats a sprite can have.
+ ///
public enum SpriteType : uint
{
+ ///
+ /// Normal format.
+ ///
Normal = 0,
+ ///
+ /// SWF format.
+ ///
SWF = 1,
+ ///
+ /// Spine format.
+ ///
Spine = 2
}
+ ///
+ /// Different Separation mask types a sprite can have.
+ ///
public enum SepMaskType : uint
{
AxisAlignedRect = 0,
@@ -770,7 +846,7 @@ public void Unserialize(UndertaleReader reader)
}
[PropertyChanged.AddINotifyPropertyChangedInterface]
- public class UndertaleYYSWFGradientRecord : UndertaleObject
+ public class UndertaleYYSWFGradientRecord : UndertaleObject
{
public int Ratio { get; set; }
public byte Red { get; set; }
From faecb2085dd91da1c2904f576b81d56019841532 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Fri, 25 Mar 2022 15:14:43 +0100
Subject: [PATCH 04/18] Attempt to document timeline, gameobject and half of
room.
---
UndertaleModLib/Models/UndertaleGameObject.cs | 868 +++++++++++++++++-
UndertaleModLib/Models/UndertaleRoom.cs | 366 +++++++-
UndertaleModLib/Models/UndertaleTimeline.cs | 20 +
3 files changed, 1232 insertions(+), 22 deletions(-)
diff --git a/UndertaleModLib/Models/UndertaleGameObject.cs b/UndertaleModLib/Models/UndertaleGameObject.cs
index d0647d65e..d93d3b379 100644
--- a/UndertaleModLib/Models/UndertaleGameObject.cs
+++ b/UndertaleModLib/Models/UndertaleGameObject.cs
@@ -9,39 +9,141 @@
namespace UndertaleModLib.Models
{
+ //TODO: shouldn't this be inside of the UGameObject class?
+ ///
+ /// Collision shapes a can use.
+ ///
public enum CollisionShapeFlags : uint
{
+ ///
+ /// A circular collision shape.
+ ///
Circle = 0,
+ ///
+ /// A rectangular collision shape.
+ ///
Box = 1,
+ ///
+ /// A custom polygonal collision shape.
+ ///
Custom = 2,
}
+ ///
+ /// A game object in a data file.
+ ///
public class UndertaleGameObject : UndertaleNamedResource, INotifyPropertyChanged
{
public UndertaleResourceById _Sprite = new UndertaleResourceById();
public UndertaleResourceById _ParentId = new UndertaleResourceById();
public UndertaleResourceById _TextureMaskId = new UndertaleResourceById();
+ ///
+ /// The name of the game object.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The sprite this game object uses.
+ ///
public UndertaleSprite Sprite { get => _Sprite.Resource; set { _Sprite.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Sprite))); } }
+
+ ///
+ /// Whether the game object is visible.
+ ///
public bool Visible { get; set; } = true;
+
+ ///
+ /// Whether the game object is solid.
+ ///
public bool Solid { get; set; } = false;
+
+ ///
+ /// The depth level of the game object.
+ ///
public int Depth { get; set; } = 0;
+
+ ///
+ /// Whether the game object is persistent.
+ ///
public bool Persistent { get; set; } = false;
+
+ ///
+ /// The parent game object this is inheriting from.
+ ///
public UndertaleGameObject ParentId { get => _ParentId.Resource; set { _ParentId.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ParentId))); } }
+
+ ///
+ /// The texture mask this game object is using.
+ ///
public UndertaleSprite TextureMaskId { get => _TextureMaskId.Resource; set { _TextureMaskId.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TextureMaskId))); } }
+
+ #region Physics related properties
+ ///
+ /// Whether this object uses Game Maker physics.
+ ///
public bool UsesPhysics { get; set; } = false;
+
+ ///
+ /// Whether this game object should act as a sensor fixture.
+ ///
public bool IsSensor { get; set; } = false;
+
+ ///
+ /// The collision shape the game object should use.
+ ///
public CollisionShapeFlags CollisionShape { get; set; } = CollisionShapeFlags.Circle;
+
+ ///
+ /// The physics density of the game object.
+ ///
public float Density { get; set; } = 0.5f;
+
+ ///
+ /// The physics restitution of the game object.
+ ///
public float Restitution { get; set; } = 0.1f;
+
+ ///
+ /// The physics collision group this game object belongs to.
+ ///
public uint Group { get; set; } = 0;
+
+ ///
+ /// The physics linear damping this game object uses.
+ ///
public float LinearDamping { get; set; } = 0.1f;
+
+ ///
+ /// The physics angular damping this game object uses.
+ ///
public float AngularDamping { get; set; } = 0.1f;
+
+ ///
+ /// The physics friction this game object uses.
+ ///
public float Friction { get; set; } = 0.2f;
+
+ ///
+ /// Whether this game object should start awake in the physics simulation.
+ ///
public bool Awake { get; set; } = false;
+
+ ///
+ /// Whether this game object is kinematic.
+ ///
public bool Kinematic { get; set; } = false;
+
+ ///
+ /// The vertices used for a of type .
+ ///
public List PhysicsVertices { get; private set; } = new List();
+
+ #endregion
+
+ ///
+ /// All the events that this game object has.
+ ///
public UndertalePointerList> Events { get; private set; } = new UndertalePointerList>();
public event PropertyChangedEventHandler PropertyChanged;
@@ -133,6 +235,8 @@ public void Unserialize(UndertaleReader reader)
Events = reader.ReadUndertaleObject>>();
}
+ //TODO: what do all these eventhandlers do? can't find any references right now.
+
public UndertaleCode EventHandlerFor(EventType type, uint subtype, IList strg, IList codelist, IList localslist)
{
Event subtypeObj = Events[(int)type].Where((x) => x.EventSubtype == subtype).FirstOrDefault();
@@ -247,11 +351,23 @@ public override string ToString()
return Name.Content + " (" + GetType().Name + ")";
}
+ ///
+ /// Generic events that a uses.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class Event : UndertaleObject
{
- public uint EventSubtype { get; set; } // (the same as the ID at the end of name)
- public UndertalePointerList Actions { get; private set; } = new UndertalePointerList(); // seems to always have 1 entry, maybe the games using drag-and-drop code are different
+ ///
+ /// The subtype of this event.
+ ///
+ /// Game Maker suffixes the action names with this id.
+ public uint EventSubtype { get; set; }
+
+ ///
+ /// The available actions that will be performed for this event.
+ ///
+ /// This seems to always have 1 entry, it would need testing if maybe the games using drag-and-drop code are different
+ public UndertalePointerList Actions { get; private set; } = new UndertalePointerList();
public EventSubtypeKey EventSubtypeKey
{
@@ -302,12 +418,15 @@ public void Unserialize(UndertaleReader reader)
}
}
+ ///
+ /// An action in an event.
+ ///
public class EventAction : UndertaleObject, INotifyPropertyChanged
{
// All the unknown values seem to be provided for compatibility only - in older versions of GM:S they stored the drag and drop blocks,
// but newer versions compile them down to GML bytecode anyway
// Possible meaning of values: https://github.com/WarlockD/GMdsam/blob/26aefe3e90a7a7a1891cb83f468079546f32b4b7/GMdsam/GameMaker/ChunkTypes.cs#L466
-
+
// Note from the future: these aren't always these values...
public uint LibID { get; set; } // always 1
@@ -319,6 +438,10 @@ public class EventAction : UndertaleObject, INotifyPropertyChanged
public uint ExeType { get; set; } // always 2
public UndertaleString ActionName { get; set; } // always ""
private UndertaleResourceById _CodeId = new UndertaleModLib.UndertaleResourceById();
+
+ ///
+ /// The code entry that gets executed.
+ ///
public UndertaleCode CodeId { get => _CodeId.Resource; set { _CodeId.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CodeId))); } }
public uint ArgumentCount { get; set; } // always 1
public int Who { get; set; } // always -1
@@ -365,10 +488,20 @@ public void Unserialize(UndertaleReader reader)
}
}
+ ///
+ /// Class representing a physics vertex used for a of type .
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertalePhysicsVertex : UndertaleObject
{
+ ///
+ /// The x position of the vertex.
+ ///
public float X { get; set; }
+
+ ///
+ /// The y position of the vertex.
+ ///
public float Y { get; set; }
public void Serialize(UndertaleWriter writer)
@@ -385,156 +518,565 @@ public void Unserialize(UndertaleReader reader)
}
}
+ ///
+ /// The types an event can be.
+ ///
+ /// Note, that subtypes exist as well.
public enum EventType : uint
{
- Create = 0, // no subtypes, always 0
- Destroy = 1, // no subtypes, always 0
- Alarm = 2, // subtype is alarm id (0-11)
+ ///
+ /// A creation event type. Has no subtypes, it's always 0
+ ///
+ Create = 0,
+ ///
+ /// A destroy event type. Has no subtypes, it's always 0.
+ ///
+ Destroy = 1,
+ ///
+ /// An alarm event type. The subtype is 0-11, depending on the alarm id.
+ ///
+ Alarm = 2,
+ ///
+ /// A step event type. The subtype is .
+ ///
Step = 3, // subtype is EventSubtypeStep
- Collision = 4, // subtype is other game object ID
- Keyboard = 5, // subtype is key ID, see EventSubtypeKey
+ ///
+ /// A collision event type. The subtype is the other 's id.
+ ///
+ Collision = 4,
+ ///
+ /// A key down event type. The subtype is the key id, see .
+ ///
+ Keyboard = 5,
+ ///
+ /// A mouse event type. The subtype is .
+ ///
Mouse = 6, // subtype is EventSubtypeMouse
- Other = 7, // subtype is EventSubtypeOther
- Draw = 8, // subtype is EventSubtypeDraw
- KeyPress = 9, // subtype is key ID, see EventSubtypeKey
- KeyRelease = 10, // subtype is key ID, see EventSubtypeKey
+ ///
+ /// A miscellaneous event type. The subtype is .
+ ///
+ Other = 7,
+ ///
+ /// A draw event type. The subtype is .
+ ///
+ Draw = 8,
+ ///
+ /// A key pressed event type. The subtype is the key id, see .
+ ///
+ KeyPress = 9,
+ ///
+ /// A key released event type. The subtype is the key id, see .
+ ///
+ KeyRelease = 10,
+ //TODO
Trigger = 11, // no subtypes, always 0
- CleanUp = 12, // no subtypes, always 0
- Gesture = 13, // subtype is EventSubtypeGesture
+ ///
+ /// A cleanup event type. Has no subtypes, always 0.
+ ///
+ CleanUp = 12,
+ ///
+ /// A gesture event type. The subtype is .
+ ///
+ Gesture = 13,
+ ///
+ /// A pre-create event type. Unknown subtype. TODO?
+ ///
PreCreate = 14
}
+ ///
+ /// The subtypes for .
+ ///
public enum EventSubtypeStep : uint
{
+ ///
+ /// Normal step event.
+ ///
Step = 0,
+ ///
+ /// The begin step event.
+ ///
BeginStep = 1,
+ ///
+ /// The end step event.
+ ///
EndStep = 2,
}
+ ///
+ /// The subtypes for .
+ ///
public enum EventSubtypeDraw : uint
{
+ ///
+ /// The draw event.
+ ///
Draw = 0,
+ ///
+ /// The draw GUI event.
+ ///
DrawGUI = 64,
+ ///
+ /// The resize event.
+ ///
Resize = 65,
+ ///
+ /// The draw begin event.
+ ///
DrawBegin = 72,
+ ///
+ /// The draw end event.
+ ///
DrawEnd = 73,
+ ///
+ /// The draw GUI begin event.
+ ///
DrawGUIBegin = 74,
+ ///
+ /// The draw GUI end event.
+ ///
DrawGUIEnd = 75,
+ ///
+ /// The pre-draw event.
+ ///
PreDraw = 76,
+ ///
+ /// The post-draw event.
+ ///
PostDraw = 77,
}
+ ///
+ /// The subtypes for , and .
+ ///
public enum EventSubtypeKey : uint
{
// if doesn't match any of the below, then it's probably just chr(value)
+
+ ///
+ /// Keycode representing no key.
+ ///
vk_nokey = 0,
+ ///
+ /// Keycode representing that any key.
+ ///
vk_anykey = 1,
+ ///
+ /// Keycode representing Backspace.
+ ///
vk_backspace = 8,
+ ///
+ /// Keycode representing Tab.
+ ///
vk_tab = 9,
+ ///
+ /// Keycode representing Return.
+ ///
vk_return = 13,
+ ///
+ /// Keycode representing Enter.
+ ///
vk_enter = 13,
+ ///
+ /// Keycode representing any Shift key.
+ ///
vk_shift = 16,
+ ///
+ /// Keycode representing any Control key.
+ ///
vk_control = 17,
+ ///
+ /// Keycode representing any Alt key.
+ ///
vk_alt = 18,
+ ///
+ /// Keycode representing the Pause key.
+ ///
vk_pause = 19,
+ ///
+ /// Keycode representing the Escape key.
+ ///
vk_escape = 27,
+ ///
+ /// Keycode representing the Space key.
+ ///
vk_space = 32,
+ ///
+ /// Keycode representing PageUp.
+ ///
vk_pageup = 33,
+ ///
+ /// Keycode representing PageDown.
+ ///
vk_pagedown = 34,
+ ///
+ /// Keycode representing the End key.
+ ///
vk_end = 35,
+ ///
+ /// Keycode representing the Home key.
+ ///
vk_home = 36,
+ ///
+ /// Keycode representing the left arrow key.
+ ///
vk_left = 37,
+ ///
+ /// Keycode representing the up arrow key.
+ ///
vk_up = 38,
+ ///
+ /// Keycode representing the right arrow key.
+ ///
vk_right = 39,
+ ///
+ /// Keycode representing the down arrow key.
+ ///
vk_down = 40,
+ ///
+ /// Keycode representing the PrintScreen key.
+ ///
vk_printscreen = 44,
+ ///
+ /// Keycode representing the Insert key.
+ ///
vk_insert = 45,
+ ///
+ /// Keycode representing the Delete key.
+ ///
vk_delete = 46,
+ ///
+ /// Keycode representing the 0 key.
+ ///
Digit0 = 48,
+ ///
+ /// Keycode representing the 1 key.
+ ///
Digit1 = 49,
+ ///
+ /// Keycode representing the 2 key.
+ ///
Digit2 = 50,
+ ///
+ /// Keycode representing the 3 key.
+ ///
Digit3 = 51,
+ ///
+ /// Keycode representing the 4 key.
+ ///
Digit4 = 52,
+ ///
+ /// Keycode representing the 5 key.
+ ///
Digit5 = 53,
+ ///
+ /// Keycode representing the 6 key.
+ ///
Digit6 = 54,
+ ///
+ /// Keycode representing the 7 key.
+ ///
Digit7 = 55,
+ ///
+ /// Keycode representing the 8 key.
+ ///
Digit8 = 56,
+ ///
+ /// Keycode representing the 9 key.
+ ///
Digit9 = 57,
+ ///
+ /// Keycode representing the A key.
+ ///
A = 65,
+ ///
+ /// Keycode representing the B key.
+ ///
B = 66,
+ ///
+ /// Keycode representing the C key.
+ ///
C = 67,
+ ///
+ /// Keycode representing the D key.
+ ///
D = 68,
+ ///
+ /// Keycode representing the E key.
+ ///
E = 69,
+ ///
+ /// Keycode representing the F key.
+ ///
F = 70,
+ ///
+ /// Keycode representing the G key.
+ ///
G = 71,
+ ///
+ /// Keycode representing the H key.
+ ///
H = 72,
+ ///
+ /// Keycode representing the I key.
+ ///
I = 73,
+ ///
+ /// Keycode representing the J key.
+ ///
J = 74,
+ ///
+ /// Keycode representing the K key.
+ ///
K = 75,
+ ///
+ /// Keycode representing the L key.
+ ///
L = 76,
+ ///
+ /// Keycode representing the M key.
+ ///
M = 77,
+ ///
+ /// Keycode representing the N key.
+ ///
N = 78,
+ ///
+ /// Keycode representing the O key.
+ ///
O = 79,
+ ///
+ /// Keycode representing the P key.
+ ///
P = 80,
+ ///
+ /// Keycode representing the Q key.
+ ///
Q = 81,
+ ///
+ /// Keycode representing the R key.
+ ///
R = 82,
+ ///
+ /// Keycode representing the S key.
+ ///
S = 83,
+ ///
+ /// Keycode representing the T key.
+ ///
T = 84,
+ ///
+ /// Keycode representing the U key.
+ ///
U = 85,
+ ///
+ /// Keycode representing the V key.
+ ///
V = 86,
+ ///
+ /// Keycode representing the W key.
+ ///
W = 87,
+ ///
+ /// Keycode representing the X key.
+ ///
X = 88,
+ ///
+ /// Keycode representing the Y key.
+ ///
Y = 89,
+ ///
+ /// Keycode representing the Z key.
+ ///
Z = 90,
+ ///
+ /// Keycode representing the 0 key on the numeric keypad.
+ ///
vk_numpad0 = 96,
+ ///
+ /// Keycode representing the 1 key on the numeric keypad.
+ ///
vk_numpad1 = 97,
+ ///
+ /// Keycode representing the 2 key on the numeric keypad.
+ ///
vk_numpad2 = 98,
+ ///
+ /// Keycode representing the 3 key on the numeric keypad.
+ ///
vk_numpad3 = 99,
+ ///
+ /// Keycode representing the 4 key on the numeric keypad.
+ ///
vk_numpad4 = 100,
+ ///
+ /// Keycode representing the 5 key on the numeric keypad.
+ ///
vk_numpad5 = 101,
+ ///
+ /// Keycode representing the 6 key on the numeric keypad.
+ ///
vk_numpad6 = 102,
+ ///
+ /// Keycode representing the 7 key on the numeric keypad.
+ ///
vk_numpad7 = 103,
+ ///
+ /// Keycode representing the 8 key on the numeric keypad.
+ ///
vk_numpad8 = 104,
+ ///
+ /// Keycode representing the 9 key on the numeric keypad.
+ ///
vk_numpad9 = 105,
+ ///
+ /// Keycode representing the Multiply key on the numeric keypad.
+ ///
vk_multiply = 106,
+ ///
+ /// Keycode representing the Add key on the numeric keypad.
+ ///
vk_add = 107,
+ ///
+ /// Keycode representing the Subtract key on the numeric keypad.
+ ///
vk_subtract = 109,
+ ///
+ /// Keycode representing the Decimal Dot key on the numeric keypad.
+ ///
vk_decimal = 110,
+ ///
+ /// Keycode representing the Divide key on the numeric keypad.
+ ///
vk_divide = 111,
+ ///
+ /// Keycode representing the F1 key.
+ ///
vk_f1 = 112,
+ ///
+ /// Keycode representing the F2 key.
+ ///
vk_f2 = 113,
+ ///
+ /// Keycode representing the F3 key.
+ ///
vk_f3 = 114,
+ ///
+ /// Keycode representing the F4 key.
+ ///
vk_f4 = 115,
+ ///
+ /// Keycode representing the F5 key.
+ ///
vk_f5 = 116,
+ ///
+ /// Keycode representing the F6 key.
+ ///
vk_f6 = 117,
+ ///
+ /// Keycode representing the F7 key.
+ ///
vk_f7 = 118,
+ ///
+ /// Keycode representing the F8 key.
+ ///
vk_f8 = 119,
+ ///
+ /// Keycode representing the F9 key.
+ ///
vk_f9 = 120,
+ ///
+ /// Keycode representing the F10 key.
+ ///
vk_f10 = 121,
+ ///
+ /// Keycode representing the F11 key.
+ ///
vk_f11 = 122,
+ ///
+ /// Keycode representing the F12 key.
+ ///
vk_f12 = 123,
+ ///
+ /// Keycode representing the left Shift key.
+ ///
vk_lshift = 160,
+ ///
+ /// Keycode representing the right Shift key.
+ ///
vk_rshift = 161,
+ ///
+ /// Keycode representing the left Control key.
+ ///
vk_lcontrol = 162,
+ ///
+ /// Keycode representing the right Control key.
+ ///
vk_rcontrol = 163,
+ ///
+ /// Keycode representing the left Alt key.
+ ///
vk_lalt = 164,
+ ///
+ /// Keycode representing the right Alt key.
+ ///
vk_ralt = 165,
}
-
+
+ ///
+ /// The subtypes for .
+ ///
public enum EventSubtypeMouse : uint
{
+ ///
+ /// The left-mouse button down event.
+ ///
LeftButton = 0,
+ ///
+ /// The right-mouse button down event.
+ ///
RightButton = 1,
+ ///
+ /// The middle-mouse button down event.
+ ///
MiddleButton = 2,
+ ///
+ /// The no-mouse input event.
+ ///
NoButton = 3,
+ ///
+ /// The left-mouse button pressed event.
+ ///
LeftPressed = 4,
+ ///
+ /// The right-mouse button pressed event.
+ ///
RightPressed = 5,
+ ///
+ /// The middle-mouse button pressed event.
+ ///
MiddlePressed = 6,
+ ///
+ /// The left-mouse button released event.
+ ///
LeftReleased = 7,
+ ///
+ /// The right-mouse button released event.
+ ///
RightReleased = 8,
+ ///
+ /// The middle-mouse button released event.
+ ///
MiddleReleased = 9,
+ ///
+ /// The mouse enter event.
+ ///
MouseEnter = 10,
+ ///
+ /// The mouse leave event.
+ ///
MouseLeave = 11,
+ //TODO: are these even used?
Joystick1Left = 16,
Joystick1Right = 17,
Joystick1Up = 18,
@@ -559,109 +1101,403 @@ public enum EventSubtypeMouse : uint
Joystick2Button6 = 41,
Joystick2Button7 = 42,
Joystick2Button8 = 43,
+ ///
+ /// The global left-mouse button down event.
+ ///
GlobLeftButton = 50,
+ ///
+ /// The global right-mouse button down event.
+ ///
GlobRightButton = 51,
+ ///
+ /// The global middle-mouse button down event.
+ ///
GlobMiddleButton = 52,
+ ///
+ /// The global left-mouse button pressed event.
+ ///
GlobLeftPressed = 53,
+ ///
+ /// The global right-mouse button pressed event.
+ ///
GlobRightPressed = 54,
+ ///
+ /// The global middle-mouse button pressed event.
+ ///
GlobMiddlePressed = 55,
+ ///
+ /// The global left-mouse button released event.
+ ///
GlobLeftReleased = 56,
+ ///
+ /// The global right-mouse button released event.
+ ///
GlobRightReleased = 57,
+ ///
+ /// The global middle-mouse button released event.
+ ///
GlobMiddleReleased = 58,
+ ///
+ /// The mouse-wheel up event.
+ ///
MouseWheelUp = 60,
+ ///
+ /// The mouse-wheel down event.
+ ///
MouseWheelDown = 61,
}
-
+
+ ///
+ /// The subtypes for .
+ ///
public enum EventSubtypeOther : uint
{
+ ///
+ /// The outside room event.
+ ///
OutsideRoom = 0,
+ ///
+ /// The intersect boundary event.
+ ///
IntersectBoundary = 1,
+ ///
+ /// The game start event.
+ ///
GameStart = 2,
+ ///
+ /// The game end event.
+ ///
GameEnd = 3,
+ ///
+ /// The room start event.
+ ///
RoomStart = 4,
+ ///
+ /// The room end event.
+ ///
RoomEnd = 5,
+
+ //TODO: are the ones here used?
NoMoreLives = 6,
+ ///
+ /// The animation end event.
+ ///
AnimationEnd = 7,
+ ///
+ /// The path ended event.
+ ///
EndOfPath = 8,
+
NoMoreHealth = 9,
+
+ ///
+ /// The User 0 event.
+ ///
User0 = 10,
+ ///
+ /// The User 1 event.
+ ///
User1 = 11,
+ ///
+ /// The User 2 event.
+ ///
User2 = 12,
+ ///
+ /// The User 3 event.
+ ///
User3 = 13,
+ ///
+ /// The User 4 event.
+ ///
User4 = 14,
+ ///
+ /// The User 5 event.
+ ///
User5 = 15,
+ ///
+ /// The User 6 event.
+ ///
User6 = 16,
+ ///
+ /// The User 7 event.
+ ///
User7 = 17,
+ ///
+ /// The User 8 event.
+ ///
User8 = 18,
+ ///
+ /// The User 9 event.
+ ///
User9 = 19,
+ ///
+ /// The User 10 event.
+ ///
User10 = 20,
+ ///
+ /// The User 11 event.
+ ///
User11 = 21,
+ ///
+ /// The User 12 event.
+ ///
User12 = 22,
+ ///
+ /// The User 13 event.
+ ///
User13 = 23,
+ ///
+ /// The User 14 event.
+ ///
User14 = 24,
+ ///
+ /// The User 15 event.
+ ///
User15 = 25,
+ ///
+ /// The User 16 event.
+ ///
User16 = 26,
+ ///
+ /// The Outside View 0 event.
+ ///
OutsideView0 = 40,
+ ///
+ /// The Outside View 1 event.
+ ///
OutsideView1 = 41,
+ ///
+ /// The Outside View 2 event.
+ ///
OutsideView2 = 42,
+ ///
+ /// The Outside View 3 event.
+ ///
OutsideView3 = 43,
+ ///
+ /// The Outside View 4 event.
+ ///
OutsideView4 = 44,
+ ///
+ /// The Outside View 5 event.
+ ///
OutsideView5 = 45,
+ ///
+ /// The Outside View 6 event.
+ ///
OutsideView6 = 46,
+ ///
+ /// The Outside View 7 event.
+ ///
OutsideView7 = 47,
+ ///
+ /// The Intersect View 0 Boundary event.
+ ///
BoundaryView0 = 50,
+ ///
+ /// The Intersect View 1 Boundary event.
+ ///
BoundaryView1 = 51,
+ ///
+ /// The Intersect View 2 Boundary event.
+ ///
BoundaryView2 = 52,
+ ///
+ /// The Intersect View 3 Boundary event.
+ ///
BoundaryView3 = 53,
+ ///
+ /// The Intersect View 4 Boundary event.
+ ///
BoundaryView4 = 54,
+ ///
+ /// The Intersect View 5 Boundary event.
+ ///
BoundaryView5 = 55,
+ ///
+ /// The Intersect View 6 Boundary event.
+ ///
BoundaryView6 = 56,
+ ///
+ /// The Intersect View 7 Boundary event.
+ ///
BoundaryView7 = 57,
+ ///
+ /// The animation Update event for Skeletal Animation functions.
+ ///
AnimationUpdate = 58,
+ ///
+ /// The animation event for Skeletal Animation functions.
+ ///
AnimationEvent = 59,
+ #region Async events
+ ///
+ /// The async image loaded event.
+ ///
AsyncImageLoaded = 60,
+ ///
+ /// The async sound loaded event.
+ ///
AsyncSoundLoaded = 61,
+ ///
+ /// The async http event.
+ ///
AsyncHTTP = 62,
+ ///
+ /// The async dialog event.
+ ///
AsyncDialog = 63,
+ ///
+ /// The async in-app purchase event.
+ ///
AsyncIAP = 66,
+ ///
+ /// The async cloud event.
+ ///
AsyncCloud = 67,
+ ///
+ /// The async networking event.
+ ///
AsyncNetworking = 68,
+ ///
+ /// The async Steam event.
+ ///
AsyncSteam = 69,
+ ///
+ /// The async social event.
+ ///
AsyncSocial = 70,
+ ///
+ /// The async push notification event.
+ ///
AsyncPushNotification = 71,
+ ///
+ /// The async save/load event.
+ ///
AsyncSaveAndLoad = 72,
+ ///
+ /// The async audio recording event.
+ ///
AsyncAudioRecording = 73,
+ ///
+ /// The async audio playback event.
+ ///
AsyncAudioPlayback = 74,
+ ///
+ /// The async system event.
+ ///
AsyncSystem = 75,
+ #endregion
}
+ ///
+ /// The subtypes for .
+ ///
public enum EventSubtypeGesture : uint
{
+ ///
+ /// The tap event.
+ ///
Tap = 0,
+ ///
+ /// The double tap event.
+ ///
DoubleTap = 1,
+ ///
+ /// The drag start event.
+ ///
DragStart = 2,
+ ///
+ /// The dragging event.
+ ///
DragMove = 3,
+ ///
+ /// The drag end event.
+ ///
DragEnd = 4,
+ ///
+ /// The flick event.
+ ///
Flick = 5,
+ ///
+ /// The pinch start event.
+ ///
PinchStart = 6,
+ ///
+ /// The pinch in event.
+ ///
PinchIn = 7,
+ ///
+ /// The pinch out event.
+ ///
PinchOut = 8,
+ ///
+ /// The pinch end event.
+ ///
PinchEnd = 9,
+ ///
+ /// The rotate start event.
+ ///
RotateStart = 10,
+ ///
+ /// The rotating event.
+ ///
Rotating = 11,
+ ///
+ /// The rotate end event.
+ ///
RotateEnd = 12,
+ ///
+ /// The global tap event.
+ ///
GlobalTap = 64,
+ ///
+ /// The global double tap event.
+ ///
GlobalDoubleTap = 65,
+ ///
+ /// The global drag start event.
+ ///
GlobalDragStart = 66,
+ ///
+ /// The global dragging event.
+ ///
GlobalDragMove = 67,
+ ///
+ /// The global drag end event.
+ ///
GlobalDragEnd = 68,
+ ///
+ /// The global flick event.
+ ///
GlobalFlick = 69,
+ ///
+ /// The global pinch start event.
+ ///
GlobalPinchStart = 70,
+ ///
+ /// The global pinch in event.
+ ///
GlobalPinchIn = 71,
+ ///
+ /// The global pinch out event.
+ ///
GlobalPinchOut = 72,
+ ///
+ /// The global pinch end event.
+ ///
GlobalPinchEnd = 73,
+ ///
+ /// The global rotate start event.
+ ///
GlobalRotateStart = 74,
+ ///
+ /// The global rotating event.
+ ///
GlobalRotating = 75,
+ ///
+ /// The global rotate end event.
+ ///
GlobalRotateEnd = 76,
}
}
diff --git a/UndertaleModLib/Models/UndertaleRoom.cs b/UndertaleModLib/Models/UndertaleRoom.cs
index 645dac05f..e3fb17eca 100644
--- a/UndertaleModLib/Models/UndertaleRoom.cs
+++ b/UndertaleModLib/Models/UndertaleRoom.cs
@@ -12,47 +12,158 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// A room in a data file.
+ ///
public class UndertaleRoom : UndertaleNamedResource, INotifyPropertyChanged
{
+ ///
+ /// Certain flags a room can have.
+ ///
[Flags]
public enum RoomEntryFlags : uint
{
+ ///
+ /// Whether the room has Views enabled.
+ ///
EnableViews = 1,
+ ///
+ /// TODO no idea.
+ ///
ShowColor = 2,
+ ///
+ /// Whether the room should clear the display buffer.
+ ///
ClearDisplayBuffer = 4,
+ ///
+ /// Whether the room was made in Game Maker: Studio 2.
+ ///
IsGMS2 = 131072,
+ ///
+ /// Whether the room was made in Game Maker: Studio 2.3.
+ ///
IsGMS2_3 = 65536
}
+ ///
+ /// The name of the room.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The caption of the room. Legacy variable that's used in pre- Game Maker: Studio.
+ ///
public UndertaleString Caption { get; set; }
+
+ ///
+ /// The Width of the room.
+ ///
public uint Width { get; set; } = 320;
+
+ ///
+ /// The height of the room.
+ ///
public uint Height { get; set; } = 240;
+
+ ///
+ /// The speed of the current room in steps.
+ ///
+ //TODO: GMS1 only? IIRC gms2 deals with it differently.
public uint Speed { get; set; } = 30;
+
+ ///
+ /// Whether this room is persistant.
+ ///
public bool Persistent { get; set; } = false;
+
+ ///
+ /// The background color of this room.
+ ///
public uint BackgroundColor { get; set; } = 0;
+
+ ///
+ /// Whether the display buffer should be cleared with Window Color.
+ ///
public bool DrawBackgroundColor { get; set; } = true;
private UndertaleResourceById _CreationCodeId = new UndertaleResourceById();
+
+ ///
+ /// The creation code of this room.
+ ///
public UndertaleCode CreationCodeId { get => _CreationCodeId.Resource; set { _CreationCodeId.Resource = value; OnPropertyChanged(); } }
+
+ ///
+ /// The room flags this room has.
+ ///
public RoomEntryFlags Flags { get; set; } = RoomEntryFlags.EnableViews;
+
+ //TODO
public bool World { get; set; } = false;
public uint Top { get; set; } = 0;
public uint Left { get; set; } = 0;
public uint Right { get; set; } = 1024;
public uint Bottom { get; set; } = 768;
+
+ ///
+ /// The gravity towards x axis using room physics in m/s.
+ ///
public float GravityX { get; set; } = 0;
+
+ ///
+ /// The gravity towards y axis using room physics in m/s.
+ ///
public float GravityY { get; set; } = 10;
+
+ ///
+ /// The meters per pixel value for room physics.
+ ///
public float MetersPerPixel { get; set; } = 0.1f;
+
+ ///
+ /// The width of the room grid in pixels.
+ ///
public double GridWidth { get; set; } = 16d;
+
+ ///
+ /// The height of the room grid in pixels.
+ ///
public double GridHeight { get; set; } = 16d;
+
+ ///
+ /// The thickness of the room grid in pixels.
+ ///
public double GridThicknessPx { get; set; } = 1d;
private UndertalePointerList _layers = new();
+
+ ///
+ /// The list of backgrounds this room uses.
+ ///
public UndertalePointerList Backgrounds { get; private set; } = new UndertalePointerList();
+
+ ///
+ /// The list of views this room uses.
+ ///
public UndertalePointerList Views { get; private set; } = new UndertalePointerList();
+
+ ///
+ /// The list of game objects this room uses.
+ ///
public UndertalePointerListLenCheck GameObjects { get; private set; } = new UndertalePointerListLenCheck();
+
+ ///
+ /// The list of tiles this room uses.
+ ///
public UndertalePointerList Tiles { get; private set; } = new UndertalePointerList();
+
+ ///
+ /// The list of layers this room uses. Used in Game Maker Studio: 2 only, as and are empty there.
+ ///
public UndertalePointerList Layers { get => _layers; private set { _layers = value; UpdateBGColorLayer(); OnPropertyChanged(); } }
+
+ ///
+ /// The list of sequences this room uses.
+ ///
public UndertaleSimpleList> Sequences { get; private set; } = new UndertaleSimpleList>();
private Layer GetBGColorLayer()
@@ -64,6 +175,10 @@ private Layer GetBGColorLayer()
.FirstOrDefault();
}
public void UpdateBGColorLayer() => OnPropertyChanged("BGColorLayer");
+
+ ///
+ /// The layer containing the background color.
+ ///
public Layer BGColorLayer => GetBGColorLayer();
public event PropertyChangedEventHandler PropertyChanged;
@@ -135,7 +250,7 @@ public void Serialize(UndertaleWriter writer)
if (writer.undertaleData.GeneralInfo.Major >= 2)
{
writer.WriteUndertaleObject(Layers);
-
+
if (sequences)
writer.WriteUndertaleObject(Sequences);
}
@@ -194,7 +309,7 @@ public void Unserialize(UndertaleReader reader)
}
}
}
-
+
if (sequences)
reader.ReadUndertaleObject(Sequences);
}
@@ -231,7 +346,7 @@ public void SetupRoom(bool calculateGrid = true)
tileSizes[new(w, h)] = layer.TilesData.TilesX * layer.TilesData.TilesY;
}
}
-
+
}
else
tileList = Tiles;
@@ -265,35 +380,98 @@ public override string ToString()
return Name.Content + " (" + GetType().Name + ")";
}
+ ///
+ /// Interface for objects within rooms.
+ ///
public interface RoomObject
{
+ ///
+ /// X coordinate of the object.
+ ///
int X { get; }
+
+ ///
+ /// Y coordinate of the object.
+ ///
int Y { get; }
+
+ ///
+ /// Instance id of the object.
+ ///
uint InstanceID { get; }
}
+ ///
+ /// A background with properties as it's used in a room.
+ ///
public class Background : UndertaleObject, INotifyPropertyChanged
{
private UndertaleRoom _ParentRoom;
+
+ ///
+ /// The room parent this background belongs to.
+ ///
public UndertaleRoom ParentRoom { get => _ParentRoom; set { _ParentRoom = value; OnPropertyChanged(); UpdateStretch(); } }
+
+ //TODO:
public float CalcScaleX { get; set; } = 1;
public float CalcScaleY { get; set; } = 1;
+
+ ///
+ /// Whether this background is enabled.
+ ///
public bool Enabled { get; set; } = false;
+
+ ///
+ /// Whether this acts as a foreground.
+ ///
public bool Foreground { get; set; } = false;
private UndertaleResourceById _BackgroundDefinition = new UndertaleResourceById();
+
+ ///
+ /// The background asset this uses.
+ ///
public UndertaleBackground BackgroundDefinition { get => _BackgroundDefinition.Resource; set { _BackgroundDefinition.Resource = value; OnPropertyChanged(); } }
private int _X = 0;
- private int _Y = 0;
+ private int _Y = 0;
+
+ ///
+ /// The x coordinate of the background in the room.
+ ///
public int X { get => _X; set { _X = value; OnPropertyChanged(); UpdateStretch(); } }
+
+ ///
+ /// The y coordinate of the background in the room.
+ ///
public int Y { get => _Y; set { _Y = value; OnPropertyChanged(); UpdateStretch(); } }
public int TileX { get; set; } = 1;
public int TileY { get; set; } = 1;
+
+ ///
+ /// Horizontal speed of the background.
+ ///
public int SpeedX { get; set; } = 0;
+
+ ///
+ /// Vertical speed of the background.
+ ///
public int SpeedY { get; set; } = 0;
private bool _Stretch = false;
+
+ ///
+ /// Whether this background is stretched
+ ///
public bool Stretch { get => _Stretch; set { _Stretch = value; OnPropertyChanged(); UpdateStretch(); } }
+
+ ///
+ /// Whether this background is tiled horizontally.
+ ///
public bool TiledHorizontally { get => TileX > 0; set { TileX = value ? 1 : 0; OnPropertyChanged(); } }
+
+ ///
+ /// Whether this background is tiled vertically.
+ ///
public bool TiledVertically { get => TileY > 0; set { TileY = value ? 1 : 0; OnPropertyChanged(); } }
public event PropertyChangedEventHandler PropertyChanged;
@@ -338,23 +516,81 @@ public void Unserialize(UndertaleReader reader)
}
}
+ ///
+ /// A view with properties as it's used in a room.
+ ///
public class View : UndertaleObject, INotifyPropertyChanged
{
+ ///
+ /// Whether this view is enabled.
+ ///
public bool Enabled { get; set; } = false;
+
+ ///
+ /// The x coordinate of the view in the room.
+ ///
public int ViewX { get; set; }
+
+ ///
+ /// The y coordinate of the view in the room.
+ ///
public int ViewY { get; set; }
+
+ ///
+ /// The width of the view.
+ ///
public int ViewWidth { get; set; } = 640;
+
+ ///
+ /// The height of the view.
+ ///
public int ViewHeight { get; set; } = 480;
+
+ ///
+ /// The x coordinate of the viewport on the screen.
+ ///
public int PortX { get; set; }
+
+ ///
+ /// The y coordinate of the viewport on the screen.
+ ///
public int PortY { get; set; }
+
+ ///
+ /// The width of the viewport on the screen.
+ ///
public int PortWidth { get; set; } = 640;
+
+ ///
+ /// The height of the viewport on the screen.
+ ///
public int PortHeight { get; set; } = 480;
+
+ ///
+ /// The horizontal border of the view for view following.
+ ///
public uint BorderX { get; set; } = 32;
+
+ ///
+ /// The vertical border of the view for view following.
+ ///
public uint BorderY { get; set; } = 32;
+
+ ///
+ /// The horizontal movement speed of the view.
+ ///
public int SpeedX { get; set; } = -1;
+
+ ///
+ /// The vertical movement speed of the view.
+ ///
public int SpeedY { get; set; } = -1;
private UndertaleResourceById _ObjectId = new UndertaleResourceById();
+
+ ///
+ /// The object the view should follow.
+ ///
public UndertaleGameObject ObjectId { get => _ObjectId.Resource; set { _ObjectId.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ObjectId))); } }
public event PropertyChangedEventHandler PropertyChanged;
@@ -396,23 +632,71 @@ public void Unserialize(UndertaleReader reader)
}
}
+ ///
+ /// A game object with properties as it's used in a room.
+ ///
public class GameObject : UndertaleObjectLenCheck, RoomObject, INotifyPropertyChanged
{
private UndertaleResourceById _ObjectDefinition = new UndertaleResourceById();
private UndertaleResourceById _CreationCode = new UndertaleResourceById();
private UndertaleResourceById _PreCreateCode = new UndertaleResourceById();
+ ///
+ /// The x coordinate of this object.
+ ///
public int X { get; set; }
+
+ ///
+ /// The y coordinate of this object.
+ ///
public int Y { get; set; }
+
+ ///
+ /// The game object that is used.
+ ///
public UndertaleGameObject ObjectDefinition { get => _ObjectDefinition.Resource; set { _ObjectDefinition.Resource = value; OnPropertyChanged(); } }
+
+ ///
+ /// The instance id of this object.
+ ///
public uint InstanceID { get; set; }
+
+ ///
+ /// The creation code for this object.
+ ///
public UndertaleCode CreationCode { get => _CreationCode.Resource; set { _CreationCode.Resource = value; OnPropertyChanged(); } }
+
+ ///
+ /// The x scale that's applied for this object.
+ ///
public float ScaleX { get; set; } = 1;
+
+ ///
+ /// The y scale that's applied for this object.
+ ///
public float ScaleY { get; set; } = 1;
+
+ //TODO: no idea
public uint Color { get; set; } = 0xFFFFFFFF;
+
+ ///
+ /// The rotation of this object.
+ ///
public float Rotation { get; set; }
+
+ ///
+ /// The pre creation code of this object.
+ ///
public UndertaleCode PreCreateCode { get => _PreCreateCode.Resource; set { _PreCreateCode.Resource = value; OnPropertyChanged(); } }
+
+ ///
+ /// The image speed of this object. Game Maker: Studio 2 only.
+ ///
public float ImageSpeed { get; set; }
+
+ ///
+ /// The image index of this object. Game Maker: Studio 2 only.
+ ///
public int ImageIndex { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
@@ -421,7 +705,10 @@ protected void OnPropertyChanged([CallerMemberName] string name = null)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
- public float OppositeRotation => 360F - Rotation;
+ ///
+ /// The opposite angle of the current rotation.
+ ///
+ public float OppositeRotation => 360F - (Rotation % 360);
public int XOffset => ObjectDefinition.Sprite != null
? X - ObjectDefinition.Sprite.OriginX + (ObjectDefinition.Sprite.Textures.FirstOrDefault()?.Texture?.TargetX ?? 0)
: X;
@@ -481,25 +768,85 @@ public override string ToString()
}
}
+ ///
+ /// A tile with properties as it's used in a room.
+ ///
public class Tile : UndertaleObject, RoomObject, INotifyPropertyChanged
{
+ ///
+ /// Whether this tile is from an asset layer. Game Maker Studio: 2 exclusive.
+ ///
public bool _SpriteMode = false;
private UndertaleResourceById _BackgroundDefinition = new UndertaleResourceById();
private UndertaleResourceById _SpriteDefinition = new UndertaleResourceById();
+ ///
+ /// The x coordinate of the tile in the room.
+ ///
public int X { get; set; }
+
+ ///
+ /// The y coordinate of the tile in the room.
+ ///
public int Y { get; set; }
+
+ ///
+ /// From which tileset / background the tile stems from.
+ ///
public UndertaleBackground BackgroundDefinition { get => _BackgroundDefinition.Resource; set { _BackgroundDefinition.Resource = value; OnPropertyChanged(); OnPropertyChanged("ObjectDefinition"); } }
+
+ ///
+ /// From which sprite this tile stems from.
+ ///
public UndertaleSprite SpriteDefinition { get => _SpriteDefinition.Resource; set { _SpriteDefinition.Resource = value; OnPropertyChanged(); OnPropertyChanged("ObjectDefinition"); } }
+
+ ///
+ /// From which object this tile stems from.
+ /// Will return a if is disabled, a if it's enabled.
+ ///
public UndertaleNamedResource ObjectDefinition { get => _SpriteMode ? SpriteDefinition : BackgroundDefinition; set { if (_SpriteMode) SpriteDefinition = (UndertaleSprite)value; else BackgroundDefinition = (UndertaleBackground)value; } }
+
+ ///
+ /// The x coordinate of the tile in .
+ ///
public uint SourceX { get; set; }
+
+ ///
+ /// The y coordinate of the tile in .
+ ///
public uint SourceY { get; set; }
+
+ ///
+ /// The width of the tile.
+ ///
public uint Width { get; set; }
+
+ ///
+ /// The height of the tile.
+ ///
public uint Height { get; set; }
+
+ ///
+ /// The depth value of this tile.
+ ///
public int TileDepth { get; set; }
+
+ ///
+ /// The instance id of this tile.
+ ///
public uint InstanceID { get; set; }
+
+ ///
+ /// The x scale that's applied for this tile.
+ ///
public float ScaleX { get; set; } = 1;
+
+ ///
+ /// The y scale that's applied for this tile.
+ ///
public float ScaleY { get; set; } = 1;
+
+ //TODO?
public uint Color { get; set; } = 0xFFFFFFFF;
public UndertaleTexturePageItem Tpag => _SpriteMode ? SpriteDefinition?.Textures?.FirstOrDefault()?.Texture : BackgroundDefinition?.Texture; // TODO: what happens on sprites with multiple textures?
@@ -558,6 +905,10 @@ public override string ToString()
}
// For GMS2, Backgrounds and Tiles are empty and this is used instead
+ ///
+ /// The layer type for a specific layer. In Game Maker: Studio 2, ,
+ /// are empty and this is used instead.
+ ///
public enum LayerType
{
Background = 1,
@@ -567,6 +918,9 @@ public enum LayerType
Effect = 6
}
+ ///
+ /// A layer with properties as it's used in a room. Game Maker: Studio 2 only.
+ ///
public class Layer : UndertaleObject, INotifyPropertyChanged
{
public interface LayerData : UndertaleObject
@@ -652,7 +1006,7 @@ public void Serialize(UndertaleWriter writer)
throw new Exception("Unsupported layer type " + LayerType);
}
}
-
+
public void Unserialize(UndertaleReader reader)
{
LayerName = reader.ReadUndertaleString();
diff --git a/UndertaleModLib/Models/UndertaleTimeline.cs b/UndertaleModLib/Models/UndertaleTimeline.cs
index 368f7b27c..c18d7a04c 100644
--- a/UndertaleModLib/Models/UndertaleTimeline.cs
+++ b/UndertaleModLib/Models/UndertaleTimeline.cs
@@ -8,13 +8,26 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// A timeline in a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleTimeline : UndertaleNamedResource
{
+ ///
+ /// A specific moment in a timeline.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleTimelineMoment : UndertaleObject
{
+ ///
+ /// After how many steps this moment gets executed.
+ ///
public uint Step { get; set; }
+
+ ///
+ /// The actions that get executed at this moment.
+ ///
public UndertalePointerList Event { get; set; }
public UndertaleTimelineMoment()
@@ -42,7 +55,14 @@ public void Unserialize(UndertaleReader reader)
}
}
+ ///
+ /// The name of the timeline.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The moments this timeline has. Comparable to keyframes.
+ ///
public ObservableCollection Moments { get; set; } = new ObservableCollection();
public override string ToString()
From 5a792a4f822cf740872dcd992a2dc69fc15495ab Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Sat, 26 Mar 2022 13:29:44 +0100
Subject: [PATCH 05/18] Rename some scriptMethods, document more modules
- start documenting UndertaleCode
- document some gms2 stuff of UndertaleRoom.
- document texturepageItem
- document some missing IScriptInterface methods and rename some of them.
- document some missing UndertaleData properties and mehotds.
---
UndertaleModCli/Program.cs | 8 +-
UndertaleModLib/Compiler/BuiltinList.cs | 9 ++-
UndertaleModLib/Models/UndertaleCode.cs | 39 ++++++---
UndertaleModLib/Models/UndertaleRoom.cs | 21 +++++
.../Models/UndertaleTexturePageItem.cs | 81 ++++++++++++++++---
UndertaleModLib/Scripting/IScriptInterface.cs | 40 +++++++--
UndertaleModLib/UndertaleData.cs | 56 ++++++++++---
UndertaleModLib/UndertaleModLib.csproj | 1 +
UndertaleModTests/GameScriptTests.cs | 12 +--
UndertaleModTool/MainWindow.xaml.cs | 55 +++++++------
10 files changed, 240 insertions(+), 82 deletions(-)
diff --git a/UndertaleModCli/Program.cs b/UndertaleModCli/Program.cs
index e548cb9e4..a0a20c8ae 100644
--- a/UndertaleModCli/Program.cs
+++ b/UndertaleModCli/Program.cs
@@ -805,7 +805,7 @@ public void SyncBinding(string resourceType, bool enable)
{
//there is no UI with any data binding
}
- public void SyncBinding(bool enable = false)
+ public void DisableAllSyncBinding()
{
//there is no UI with any data binding
}
@@ -837,7 +837,7 @@ private void ProgressUpdater()
Thread.Sleep(100); //10 times per second
}
}
- public void StartUpdater()
+ public void StartProgressBarUpdater()
{
if (cts is not null)
Console.WriteLine("Warning - there is another progress updater task running (hangs) in the background.");
@@ -847,7 +847,7 @@ public void StartUpdater()
updater = Task.Run(ProgressUpdater);
}
- public async Task StopUpdater() //"async" because "Wait()" blocks UI thread
+ public async Task StopProgressBarUpdater() //"async" because "Wait()" blocks UI thread
{
if (cts is not null)
{
@@ -865,7 +865,7 @@ public async Task StopUpdater() //"async" because "Wait()" blocks UI thread
}
}
- public async Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool isSaving = false)
+ public async Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool clearGMLEditedBefore = false)
{
await Task.Delay(1); //dummy await
diff --git a/UndertaleModLib/Compiler/BuiltinList.cs b/UndertaleModLib/Compiler/BuiltinList.cs
index 20a19b79d..9b41b543e 100644
--- a/UndertaleModLib/Compiler/BuiltinList.cs
+++ b/UndertaleModLib/Compiler/BuiltinList.cs
@@ -105,9 +105,10 @@ public AccessorInfo(string lFunc, string lPreFunc, string lPostFunc, string rFun
}
}
- // This is a really long list of known constants and variables, taken from code analysis
- // This deserves to be in its own file for that reason...
- // This will likely need to be updated with every new GameMaker version with new features
+ ///
+ /// A really long list of known Game Maker: Studio constants and variables, taken from code analysis.
+ /// Will likely need to be updated on every new Game Maker version with new features.
+ ///
public class BuiltinList
{
public Dictionary Constants = null;
@@ -132,7 +133,7 @@ public BuiltinList(UndertaleData data)
{
Initialize(data);
}
-
+
public void Initialize(UndertaleData data)
{
// Functions
diff --git a/UndertaleModLib/Models/UndertaleCode.cs b/UndertaleModLib/Models/UndertaleCode.cs
index 9bdbeaad6..bbad10120 100644
--- a/UndertaleModLib/Models/UndertaleCode.cs
+++ b/UndertaleModLib/Models/UndertaleCode.cs
@@ -12,8 +12,15 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// A bytecode instruction.
+ ///
public class UndertaleInstruction : UndertaleObject
{
+ ///
+ /// Possible opcodes an instruction can use.
+ ///
+ //TODO: document all these. i ain't smart enough to understand these.
public enum Opcode : byte
{
Conv = 0x07, // Push((Types.Second)Pop) // DoubleTypeInstruction
@@ -51,6 +58,9 @@ public enum Opcode : byte
Break = 0xFF, // TODO: Several sub-opcodes in GMS 2.3
}
+ ///
+ /// Possible types an instruction can be.
+ ///
public enum InstructionType
{
SingleTypeInstruction,
@@ -63,31 +73,37 @@ public enum InstructionType
BreakInstruction
}
+ ///
+ /// Determines the instruction type of an opcode and returns it.
+ ///
+ /// The opcode to get the instruction type of.
+ /// The instruction type of the supplied opcode.
+ /// For unknown opcodes.
public static InstructionType GetInstructionType(Opcode op)
{
return op switch
{
- Opcode.Neg or Opcode.Not or Opcode.Dup or
- Opcode.Ret or Opcode.Exit or Opcode.Popz or
- Opcode.CallV
+ Opcode.Neg or Opcode.Not or Opcode.Dup or
+ Opcode.Ret or Opcode.Exit or Opcode.Popz or
+ Opcode.CallV
=> InstructionType.SingleTypeInstruction,
- Opcode.Conv or Opcode.Mul or Opcode.Div or
- Opcode.Rem or Opcode.Mod or Opcode.Add or
- Opcode.Sub or Opcode.And or Opcode.Or or
- Opcode.Xor or Opcode.Shl or Opcode.Shr
+ Opcode.Conv or Opcode.Mul or Opcode.Div or
+ Opcode.Rem or Opcode.Mod or Opcode.Add or
+ Opcode.Sub or Opcode.And or Opcode.Or or
+ Opcode.Xor or Opcode.Shl or Opcode.Shr
=> InstructionType.DoubleTypeInstruction,
Opcode.Cmp => InstructionType.ComparisonInstruction,
- Opcode.B or Opcode.Bt or Opcode.Bf or
- Opcode.PushEnv or Opcode.PopEnv
+ Opcode.B or Opcode.Bt or Opcode.Bf or
+ Opcode.PushEnv or Opcode.PopEnv
=> InstructionType.GotoInstruction,
Opcode.Pop => InstructionType.PopInstruction,
- Opcode.Push or Opcode.PushLoc or Opcode.PushGlb or
- Opcode.PushBltn or Opcode.PushI
+ Opcode.Push or Opcode.PushLoc or Opcode.PushGlb or
+ Opcode.PushBltn or Opcode.PushI
=> InstructionType.PushInstruction,
Opcode.Call => InstructionType.CallInstruction,
@@ -97,6 +113,7 @@ Opcode.PushBltn or Opcode.PushI
};
}
+
public enum DataType : byte
{
Double,
diff --git a/UndertaleModLib/Models/UndertaleRoom.cs b/UndertaleModLib/Models/UndertaleRoom.cs
index e3fb17eca..d677f9059 100644
--- a/UndertaleModLib/Models/UndertaleRoom.cs
+++ b/UndertaleModLib/Models/UndertaleRoom.cs
@@ -921,6 +921,7 @@ public enum LayerType
///
/// A layer with properties as it's used in a room. Game Maker: Studio 2 only.
///
+ //TODO: everything from here on is mostly gms2 related which i dont have much experience with
public class Layer : UndertaleObject, INotifyPropertyChanged
{
public interface LayerData : UndertaleObject
@@ -929,12 +930,32 @@ public interface LayerData : UndertaleObject
private UndertaleRoom _ParentRoom;
private int _layerDepth;
+
+ ///
+ /// The room this layer belongs to.
+ ///
public UndertaleRoom ParentRoom { get => _ParentRoom; set { _ParentRoom = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ParentRoom))); UpdateParentRoom(); } }
+ ///
+ /// The name of the layer.
+ ///
public UndertaleString LayerName { get; set; }
+
+ ///
+ /// The id of the layer.
+ ///
public uint LayerId { get; set; }
+
+ ///
+ /// The type of this layer.
+ ///
public LayerType LayerType { get; set; }
+
+ ///
+ /// The depth of this layer.
+ ///
public int LayerDepth { get => _layerDepth; set { _layerDepth = value; ParentRoom?.UpdateBGColorLayer(); } }
+
public float XOffset { get; set; }
public float YOffset { get; set; }
public float HSpeed { get; set; }
diff --git a/UndertaleModLib/Models/UndertaleTexturePageItem.cs b/UndertaleModLib/Models/UndertaleTexturePageItem.cs
index 6804b7455..f8b056b6f 100644
--- a/UndertaleModLib/Models/UndertaleTexturePageItem.cs
+++ b/UndertaleModLib/Models/UndertaleTexturePageItem.cs
@@ -5,26 +5,78 @@
namespace UndertaleModLib.Models
{
- /**
- * The way this works is:
- * It renders in a box of size BoundingWidth x BoundingHeight at some position.
- * TargetX/Y/W/H is relative to the bounding box, anything outside of that is just transparent.
- * SourceX/Y/W/H is part of TexturePage that is drawn over TargetX/Y/W/H
- */
+ ///
+ /// A texture page item in a data file.
+ ///
+ /// The way a texture page item works is:
+ /// It renders in a box of size x at some position.
+ /// , , and are relative to the bounding box,
+ /// anything outside of that is just transparent.
+ /// , , and are part of the texture page which
+ /// are drawn over , , , .
public class UndertaleTexturePageItem : UndertaleNamedResource, INotifyPropertyChanged
{
+ ///
+ /// The name of the texture page item.
+ ///
+ //TODO: is not used by game maker, should get repurposed
public UndertaleString Name { get; set; }
- public ushort SourceX { get; set; } // X/Y of item on the texture page
+
+ ///
+ /// The x coordinate of the item on the texture page.
+ ///
+ public ushort SourceX { get; set; }
+
+ ///
+ /// The y coordinate of the item on the texture page.
+ ///
public ushort SourceY { get; set; }
- public ushort SourceWidth { get; set; } // Width/height of item on the texture page
+
+ ///
+ /// The width of the item on the texture page.
+ ///
+ public ushort SourceWidth { get; set; }
+
+ ///
+ /// The height of the item on the texture page.
+ ///
public ushort SourceHeight { get; set; }
- public ushort TargetX { get; set; } // X/Y of where to place inside of bound width/height
+
+ ///
+ /// The x coordinate of the item in the bounding rectangle.
+ ///
+ public ushort TargetX { get; set; }
+
+ ///
+ /// The y coordinate of the item in the bounding rectangle.
+ ///
public ushort TargetY { get; set; }
- public ushort TargetWidth { get; set; } // Dimensions of where to scale/place inside of bound width/height
+
+ ///
+ /// The width of the item in the bounding rectangle.
+ ///
+ public ushort TargetWidth { get; set; }
+
+ ///
+ /// The height of the item in the bounding rectangle.
+ ///
public ushort TargetHeight { get; set; }
- public ushort BoundingWidth { get; set; } // Source sprite/asset dimensions
+
+ ///
+ /// The width of the bounding rectangle.
+ ///
+ public ushort BoundingWidth { get; set; }
+
+ ///
+ /// The height of the bounding rectangle.
+ ///
public ushort BoundingHeight { get; set; }
+
private UndertaleResourceById _TexturePage = new UndertaleResourceById();
+
+ ///
+ /// The texture page this item is referencing
+ ///
public UndertaleEmbeddedTexture TexturePage { get => _TexturePage.Resource; set { _TexturePage.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TexturePage))); } }
public event PropertyChangedEventHandler PropertyChanged;
@@ -73,10 +125,15 @@ public override string ToString()
return Name.Content + " (" + GetType().Name + ")";
}
+ ///
+ /// Replaces the current image of this texture page item to hold a new image.
+ ///
+ /// The new image that shall be applied to this texture page item.
+ /// Whether to dispose afterwards.
public void ReplaceTexture(Image replaceImage, bool disposeImage = true)
{
Image finalImage = TextureWorker.ResizeImage(replaceImage, SourceWidth, SourceHeight);
-
+
// Apply the image to the TexturePage.
lock (TexturePage.TextureData)
{
diff --git a/UndertaleModLib/Scripting/IScriptInterface.cs b/UndertaleModLib/Scripting/IScriptInterface.cs
index a083e49ff..005089219 100644
--- a/UndertaleModLib/Scripting/IScriptInterface.cs
+++ b/UndertaleModLib/Scripting/IScriptInterface.cs
@@ -75,7 +75,9 @@ public interface IScriptInterface
///
string ScriptErrorType { get; }
- //TODO: no idea what this is. is not used per se anywhere, GUI implements its own thing and uses that instead.
+ ///
+ /// Indicates whether the user has enabled the setting to use decompiled code cache.
+ ///
bool GMLCacheEnabled { get; }
//TODO: this has no use. Only GUI uses this, and nothing should ever need to access this value.
@@ -395,13 +397,39 @@ bool AreFilesIdentical(string file1, string file2)
///
void EnableUI();
- // TODO: ask vlad about these.
+ ///
+ /// Allows scripts to synchronize their assets with the lists from the UI.
+ ///
+ /// A comma separated list of asset list names. This is case sensitive.
+ /// Whether to enable or disable the synchronization.
+ //TODO: Having resourceType as a comma separated list just screams for error. Make it use some array of predefined assets it can use.
void SyncBinding(string resourceType, bool enable);
- void SyncBinding(bool enable = false);
- void StartUpdater();
- Task StopUpdater();
- Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool isSaving = false);
+ ///
+ /// Stops the synchronization of all previously enabled assets.
+ ///
+ void DisableAllSyncBinding();
+
+ ///
+ /// Starts the task that updates a progress bar in parallel.
+ ///
+ void StartProgressBarUpdater();
+
+ ///
+ /// Stops the task that updates a progress bar in parallel.
+ ///
+ /// A task that represents the stopped progress updater.
+ Task StopProgressBarUpdater();
+
+ ///
+ /// Generates a decompiled code cache to accelerate operations that need to access code often.
+ ///
+ /// The GlobalDecompileContext.
+ /// The dialog that should be shown. If then a new dialog will be automatically created and shown.
+ /// Whether to clear from .
+ /// Whether the decompiled GML cache was generated or not. if it was successful,
+ /// if it wasn't or is disabled.
+ Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool clearGMLEditedBefore = false);
///
/// Changes the currently selected in the GUI.
diff --git a/UndertaleModLib/UndertaleData.cs b/UndertaleModLib/UndertaleData.cs
index 5b9332b49..abe7f7e51 100644
--- a/UndertaleModLib/UndertaleData.cs
+++ b/UndertaleModLib/UndertaleData.cs
@@ -1,10 +1,7 @@
using System;
-using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using UndertaleModLib.Compiler;
using UndertaleModLib.Models;
@@ -15,7 +12,11 @@ namespace UndertaleModLib
///
public class UndertaleData
{
- // access resource list by its name
+ ///
+ /// Indexer to access the resource list by its name.
+ ///
+ /// The resource name to get.
+ /// if the data file does not contain a property with that name.
public object this[string resourceTypeName]
{
get
@@ -36,7 +37,12 @@ public object this[string resourceTypeName]
}
}
- // access resource list by its items type
+ ///
+ /// Indexer to access the resource list by its items type.
+ ///
+ /// The resource type to get.
+ /// if the type is not an .
+ /// if the data file does not contain a property of that type.
public object this[Type resourceType]
{
get
@@ -65,6 +71,9 @@ public object this[Type resourceType]
}
}
+ ///
+ /// The FORM chunk of the data file.
+ ///
public UndertaleChunkFORM FORM;
///
@@ -229,7 +238,7 @@ public object this[Type resourceType]
public IList Sequences => FORM.SEQN?.List;
///
- /// Whether this is an unsupported bytecode version
+ /// Whether this is an unsupported bytecode version.
///
public bool UnsupportedBytecodeVersion = false;
@@ -279,9 +288,19 @@ public object this[Type resourceType]
public bool GMS2022_1 = false;
- public ToolInfo ToolInfo = new ToolInfo();
+ ///
+ /// Some info for the editor to store data on.
+ ///
+ public readonly ToolInfo ToolInfo = new ToolInfo();
+
+ ///
+ /// Shows the current padding value. -1 indicates a pre 1.4.9999 padding, where the default is 16.
+ ///
public int PaddingAlignException = -1;
+ ///
+ /// A list of known Game Maker: Studio constants and variables.
+ ///
public BuiltinList BuiltinList;
///
@@ -379,7 +398,7 @@ internal int IndexOfByName(string line)
}
///
- /// Reports whether the data file was build by GameMaker Studio 2.
+ /// Reports whether the data file was build by Game Maker Studio 2.
///
/// if yes, if not.
public bool IsGameMaker2()
@@ -391,7 +410,7 @@ public bool IsGameMaker2()
// Old Versions: https://store.yoyogames.com/downloads/gm-studio/release-notes-studio-old.html
// https://web.archive.org/web/20150304025626/https://store.yoyogames.com/downloads/gm-studio/release-notes-studio.html
// Early Access: https://web.archive.org/web/20181002232646/http://store.yoyogames.com:80/downloads/gm-studio-ea/release-notes-studio.html
- public bool TestGMS1Version(uint stableBuild, uint betaBuild, bool allowGMS2 = false)
+ private bool TestGMS1Version(uint stableBuild, uint betaBuild, bool allowGMS2 = false)
{
return (allowGMS2 || !IsGameMaker2()) && (IsVersionAtLeast(1, 0, 0, stableBuild) || (IsVersionAtLeast(1, 0, 0, betaBuild) && !IsVersionAtLeast(1, 0, 0, 1000)));
}
@@ -421,6 +440,7 @@ public bool IsVersionAtLeast(uint major, uint minor, uint release, uint build)
return true; // The version is exactly what supplied.
}
+ //TODO: I have no idea what this does.
public int GetBuiltinSoundGroupID()
{
// It is known it works this way in 1.0.1266. The exact version which changed this is unknown.
@@ -429,7 +449,7 @@ public int GetBuiltinSoundGroupID()
}
///
- /// Reports whether the data file was compiled with YYD
+ /// Reports whether the data file was compiled with YYC.
///
/// if yes, if not.
public bool IsYYC()
@@ -437,6 +457,7 @@ public bool IsYYC()
return GeneralInfo != null && Code == null;
}
+ //TODO: This is a helper method for something I don't really understand.
public uint ExtensionFindLastId()
{
// The reason:
@@ -705,11 +726,24 @@ public static UndertaleExtensionFunction DefineExtensionFunction(this IList
+ /// An info handle for an editor to store data on.
+ ///
public class ToolInfo
{
- // Info handle for the actual editor to store data on
+ ///
+ /// Whether profile mode is enabled.
+ ///
public bool ProfileMode = false;
+
+ ///
+ /// The location of the profiles folder.
+ ///
public string AppDataProfiles = null;
+
+ ///
+ /// The MD5 hash of the current file.
+ ///
public string CurrentMD5 = "Unknown";
}
}
diff --git a/UndertaleModLib/UndertaleModLib.csproj b/UndertaleModLib/UndertaleModLib.csproj
index e376b1751..dced7e684 100644
--- a/UndertaleModLib/UndertaleModLib.csproj
+++ b/UndertaleModLib/UndertaleModLib.csproj
@@ -19,6 +19,7 @@
true
+
true
diff --git a/UndertaleModTests/GameScriptTests.cs b/UndertaleModTests/GameScriptTests.cs
index c6df1129c..359c2328a 100644
--- a/UndertaleModTests/GameScriptTests.cs
+++ b/UndertaleModTests/GameScriptTests.cs
@@ -224,26 +224,26 @@ public void SyncBinding(string resourceType, bool enable)
{
Console.WriteLine($"SyncBinding(): \"{resourceType}\", {enable}");
}
- public void SyncBinding(bool enable = false)
+ public void DisableAllSyncBinding()
{
- Console.WriteLine($"SyncBinding(): {enable}");
+ Console.WriteLine($"SyncBinding(): disabled");
}
- public void StartUpdater()
+ public void StartProgressBarUpdater()
{
Console.WriteLine("Starting progress bar updater...");
}
- public async Task StopUpdater()
+ public async Task StopProgressBarUpdater()
{
Console.WriteLine("Stopping progress bar updater...");
await Task.Delay(1); //dummy await
}
- public async Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool isSaving = false)
+ public async Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool clearGMLEditedBefore = false)
{
Console.WriteLine(string.Format("GenerateGMLCache(): *decompileContext*{0}, *dialog*{1}, {2}",
decompileContext is null ? " (null)" : "",
dialog is null ? " (null)" : "",
- isSaving.ToString().ToLower())
+ clearGMLEditedBefore.ToString().ToLower())
);
await Task.Delay(1); //dummy await
diff --git a/UndertaleModTool/MainWindow.xaml.cs b/UndertaleModTool/MainWindow.xaml.cs
index 6da0d6fc4..b09b8e6fd 100644
--- a/UndertaleModTool/MainWindow.xaml.cs
+++ b/UndertaleModTool/MainWindow.xaml.cs
@@ -1026,7 +1026,7 @@ await Task.Run(async () => {
if (updateCache)
{
await GenerateGMLCache(null, dialog, true);
- await StopUpdater();
+ await StopProgressBarUpdater();
}
string[] codeNames = Data.Code.Where(x => x.ParentEntry is null).Select(x => x.Name.Content).ToArray();
@@ -1060,7 +1060,7 @@ await Task.Run(async () => {
});
}
- public async Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool isSaving = false)
+ public async Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool clearGMLEditedBefore = false)
{
if (!SettingsWindow.UseGMLCache)
return false;
@@ -1104,7 +1104,7 @@ public async Task GenerateGMLCache(ThreadLocal dec
if (Data.GMLCache.IsEmpty)
{
SetProgressBar(null, "Generating decompiled code cache...", 0, Data.Code.Count);
- StartUpdater();
+ StartProgressBarUpdater();
await Task.Run(() => Parallel.ForEach(Data.Code, (code) =>
{
@@ -1152,7 +1152,7 @@ await Task.Run(() => Parallel.ForEach(Data.Code, (code) =>
if (codeToUpdate.Count > 0)
{
SetProgressBar(null, "Updating decompiled code cache...", 0, codeToUpdate.Count);
- StartUpdater();
+ StartProgressBarUpdater();
await Task.Run(() => Parallel.ForEach(codeToUpdate.Select(x => Data.Code.ByName(x)), (code) =>
{
@@ -1173,7 +1173,7 @@ await Task.Run(() => Parallel.ForEach(codeToUpdate.Select(x => Data.Code.ByName(
IncrementProgressParallel();
}));
- if (isSaving)
+ if (clearGMLEditedBefore)
Data.GMLEditedBefore.Clear();
else
Data.GMLEditedBefore = Data.GMLEditedBefore.Union(Data.GMLCacheChanged).ToList();
@@ -1182,7 +1182,7 @@ await Task.Run(() => Parallel.ForEach(codeToUpdate.Select(x => Data.Code.ByName(
Data.GMLCacheFailed = Data.GMLCacheFailed.Union(failedBag).ToList();
Data.GMLCacheWasSaved = false;
}
- else if (isSaving)
+ else if (clearGMLEditedBefore)
Data.GMLEditedBefore.Clear();
if (!existedDialog)
@@ -1190,7 +1190,7 @@ await Task.Run(() => Parallel.ForEach(codeToUpdate.Select(x => Data.Code.ByName(
if (createdDialog)
{
- await StopUpdater();
+ await StopProgressBarUpdater();
HideProgressBar();
}
}
@@ -1750,15 +1750,14 @@ public void SyncBinding(string resourceType, bool enable)
}
}
}
- public void SyncBinding(bool enable = false) //disable all sync. bindings
+ public void DisableAllSyncBinding() //disable all sync. bindings
{
- if (syncBindings.Count != 0)
- {
- foreach (string resType in syncBindings)
- BindingOperations.DisableCollectionSynchronization(Data[resType] as IEnumerable);
+ if (syncBindings.Count <= 0) return;
- syncBindings.Clear();
- }
+ foreach (string resType in syncBindings)
+ BindingOperations.DisableCollectionSynchronization(Data[resType] as IEnumerable);
+
+ syncBindings.Clear();
}
private void ProgressUpdater()
@@ -1788,7 +1787,7 @@ private void ProgressUpdater()
Thread.Sleep(100); //10 times per second
}
}
- public void StartUpdater()
+ public void StartProgressBarUpdater()
{
if (cts is not null)
ScriptWarning("Warning - there is another progress bar updater task running (hangs) in the background.\nRestart the application to prevent some unexpected behavior.");
@@ -1798,22 +1797,22 @@ public void StartUpdater()
updater = Task.Run(ProgressUpdater);
}
- public async Task StopUpdater() //async because "Wait()" blocks UI thread
+ public async Task StopProgressBarUpdater() //async because "Wait()" blocks UI thread
{
- if (cts is not null)
- {
- cts.Cancel();
+ if (cts is null) return;
- if (await Task.Run(() => !updater.Wait(2000))) //if ProgressUpdater isn't responding
- ScriptError("Stopping the progress bar updater task is failed.\nIt's highly recommended to restart the application.", "Script error", false);
- else
- {
- cts.Dispose();
- cts = null;
- }
+ cts.Cancel();
- updater.Dispose();
+ if (await Task.Run(() => !updater.Wait(2000))) //if ProgressUpdater isn't responding
+ ScriptError("Stopping the progress bar updater task is failed.\nIt's highly recommended to restart the application.",
+ "Script error", false);
+ else
+ {
+ cts.Dispose();
+ cts = null;
}
+
+ updater.Dispose();
}
public void OpenCodeFile(string name, CodeEditorMode editorDecompile)
@@ -1978,7 +1977,7 @@ private async Task RunScriptNow(string path)
if (!isScriptException)
excString = ProcessException(in exc, in scriptText);
- await StopUpdater();
+ await StopProgressBarUpdater();
Console.WriteLine(exc.ToString());
Dispatcher.Invoke(() => CommandBox.Text = exc.Message);
From 300a01bfab6da8f62a6661e2d9e8a48bf2b24122 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Sat, 26 Mar 2022 14:59:58 +0100
Subject: [PATCH 06/18] Add some remarks and fill out missing documentation
from before.
---
.../Models/UndertaleAnimationCurve.cs | 20 +++++++++
UndertaleModLib/Models/UndertaleBackground.cs | 32 ++++++++++++++-
UndertaleModLib/Models/UndertaleCode.cs | 41 ++++++++++++++++++-
UndertaleModLib/Models/UndertaleGameObject.cs | 6 +--
UndertaleModLib/UndertaleBaseTypes.cs | 2 +-
UndertaleModLib/UndertaleData.cs | 14 +++++--
6 files changed, 103 insertions(+), 12 deletions(-)
diff --git a/UndertaleModLib/Models/UndertaleAnimationCurve.cs b/UndertaleModLib/Models/UndertaleAnimationCurve.cs
index d49ef287e..ef905fcf4 100644
--- a/UndertaleModLib/Models/UndertaleAnimationCurve.cs
+++ b/UndertaleModLib/Models/UndertaleAnimationCurve.cs
@@ -7,6 +7,9 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// An animation curve entry in a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleAnimationCurve : UndertaleNamedResource
{
@@ -16,7 +19,14 @@ public enum GraphTypeEnum : uint
Unknown1 = 1
}
+ ///
+ /// The name of this animation curve.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The graph type of this animation curve.
+ ///
public GraphTypeEnum GraphType { get; set; }
public UndertaleSimpleList Channels { get; set; }
@@ -25,6 +35,11 @@ public void Serialize(UndertaleWriter writer)
Serialize(writer, true);
}
+ ///
+ /// Serializes the data file into a specified .
+ ///
+ /// Where to serialize to.
+ /// Whether to include in the serialization.
public void Serialize(UndertaleWriter writer, bool includeName)
{
if (includeName)
@@ -38,6 +53,11 @@ public void Unserialize(UndertaleReader reader)
Unserialize(reader, true);
}
+ ///
+ /// Deserializes from a specified to the current data file.
+ ///
+ ///
+ /// Whether to include in the deserialization.
public void Unserialize(UndertaleReader reader, bool includeName)
{
if (includeName)
diff --git a/UndertaleModLib/Models/UndertaleBackground.cs b/UndertaleModLib/Models/UndertaleBackground.cs
index 7efb52180..d2e24363b 100644
--- a/UndertaleModLib/Models/UndertaleBackground.cs
+++ b/UndertaleModLib/Models/UndertaleBackground.cs
@@ -9,15 +9,23 @@
namespace UndertaleModLib.Models
{
///
- /// A background (and tileset) entry in a data file.
+ /// A background or tileset entry in a data file.
///
+ /// For Game Maker Studio: 2, this will only ever be a tileset. For Game Maker Studio: 1, this is usually a background,
+ /// but is sometimes repurposed as use for a tileset as well.
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleBackground : UndertaleNamedResource
{
+ ///
+ /// A tile id, which can be used for referencing specific tiles in a tileset.
+ ///
public class TileID : UndertaleObject, INotifyPropertyChanged
{
private uint _ID;
+ ///
+ /// The id of a specific tile.
+ ///
public uint ID { get => _ID; set { _ID = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ID))); } }
public event PropertyChangedEventHandler PropertyChanged;
@@ -57,6 +65,8 @@ public void Unserialize(UndertaleReader reader)
/// The this background uses.
///
public UndertaleTexturePageItem Texture { get; set; }
+
+
public uint GMS2UnknownAlways2 { get; set; } = 2;
///
@@ -69,13 +79,31 @@ public void Unserialize(UndertaleReader reader)
///
public uint GMS2TileHeight { get; set; } = 32;
+ ///
+ /// The output border X of the tileset. Game Maker Studio 2 only.
+ ///
public uint GMS2OutputBorderX { get; set; } = 2;
+
+ ///
+ /// The output Border Y of the tileset. Game Maker Studio 2 only.
+ ///
public uint GMS2OutputBorderY { get; set; } = 2;
+
+ //TODO: no idea
public uint GMS2TileColumns { get; set; } = 32;
public uint GMS2ItemsPerTileCount { get; set; } = 1;
public uint GMS2TileCount { get; set; } = 1024;
public uint GMS2UnknownAlwaysZero { get; set; } = 0;
- public long GMS2FrameLength { get; set; } = 66666; // time for each frame (in microseconds seemingly)
+
+
+ ///
+ /// The time for each frame in microseconds.
+ ///
+ public long GMS2FrameLength { get; set; } = 66666;
+
+ ///
+ /// All tile id of this tileset. Game Maker Studio 2 only.
+ ///
public List GMS2TileIds { get; set; } = new List();
public void Serialize(UndertaleWriter writer)
diff --git a/UndertaleModLib/Models/UndertaleCode.cs b/UndertaleModLib/Models/UndertaleCode.cs
index bbad10120..3ec47c062 100644
--- a/UndertaleModLib/Models/UndertaleCode.cs
+++ b/UndertaleModLib/Models/UndertaleCode.cs
@@ -975,18 +975,41 @@ public static UndertaleInstruction.DataType FromOpcodeParam(string type)
}
}
+ ///
+ /// A code entry in a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleCode : UndertaleNamedResource, UndertaleObjectWithBlobs
{
+ ///
+ /// The name of the code entry.
+ ///
public UndertaleString Name { get; set; }
+
+
public uint Length { get; set; }
- public uint LocalsCount { get; set; } // Warning: Actually a ushort, left this way for compatibility
+
+
+ ///
+ /// The amount of local variables this code entry has.
+ /// Warning: This is actually a ushort internally, it's an uint here for compatibility.
+ ///
+ public uint LocalsCount { get; set; }
+
+ ///
+ /// The amount of arguments this code entry accepts.
+ ///
public ushort ArgumentsCount { get; set; }
+
+
public bool WeirdLocalsFlag { get; set; }
public uint Offset { get; set; }
+
+ ///
+ /// A list of bytecode instructions this code entry has.
+ ///
public List Instructions { get; } = new List();
public bool WeirdLocalFlag { get; set; }
-
public UndertaleCode ParentEntry { get; set; } = null;
public List ChildEntries { get; set; } = new List();
@@ -1151,18 +1174,32 @@ public IList FindReferencedLocalVars()
return FindReferencedVars().Where((x) => x.InstanceType == UndertaleInstruction.InstanceType.Local).ToList();
}
+ ///
+ /// Append instructions at the end of this code entry.
+ ///
+ /// The instructions to append.
public void Append(IList instructions)
{
Instructions.AddRange(instructions);
UpdateAddresses();
}
+ ///
+ /// Replaces all instructions currently existing in this code entry with another set of instructions.
+ ///
+ /// The new instructions for this code entry.
public void Replace(IList instructions)
{
Instructions.Clear();
Append(instructions);
}
+ ///
+ /// Append GML instructions at the end of this code entry.
+ ///
+ /// The GML code to append.
+ /// From which data file the gml code is coming from.
+ /// if the GML code does not compile or if there's an error writing the code to the entry in profile mode.
public void AppendGML(string gmlCode, UndertaleData data)
{
CompileContext context = Compiler.Compiler.CompileGMLText(gmlCode, data, this);
diff --git a/UndertaleModLib/Models/UndertaleGameObject.cs b/UndertaleModLib/Models/UndertaleGameObject.cs
index d93d3b379..13152c38e 100644
--- a/UndertaleModLib/Models/UndertaleGameObject.cs
+++ b/UndertaleModLib/Models/UndertaleGameObject.cs
@@ -11,7 +11,7 @@ namespace UndertaleModLib.Models
{
//TODO: shouldn't this be inside of the UGameObject class?
///
- /// Collision shapes a can use.
+ /// Collision shapes an can use.
///
public enum CollisionShapeFlags : uint
{
@@ -352,7 +352,7 @@ public override string ToString()
}
///
- /// Generic events that a uses.
+ /// Generic events that an uses.
///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class Event : UndertaleObject
@@ -519,7 +519,7 @@ public void Unserialize(UndertaleReader reader)
}
///
- /// The types an event can be.
+ /// The types an from an can be.
///
/// Note, that subtypes exist as well.
public enum EventType : uint
diff --git a/UndertaleModLib/UndertaleBaseTypes.cs b/UndertaleModLib/UndertaleBaseTypes.cs
index e11dcf82e..65d770f7d 100644
--- a/UndertaleModLib/UndertaleBaseTypes.cs
+++ b/UndertaleModLib/UndertaleBaseTypes.cs
@@ -18,7 +18,7 @@ public interface UndertaleObject
///
/// Deserializes from a specified to the current data file.
///
- ///
+ /// Where to deserialize from.
void Unserialize(UndertaleReader reader);
}
diff --git a/UndertaleModLib/UndertaleData.cs b/UndertaleModLib/UndertaleData.cs
index abe7f7e51..d6820209c 100644
--- a/UndertaleModLib/UndertaleData.cs
+++ b/UndertaleModLib/UndertaleData.cs
@@ -10,6 +10,11 @@ namespace UndertaleModLib
///
/// An object representing a Game Maker: Studio data file.
///
+ /// This is basically the heart of the data file, which is usually named data.win, data.unx,
+ /// data.ios or data.droid, depending for which OS the game was compiled for..
+ /// It includes all the data within it accessible by either the -Chunk attribute,
+ /// but also via already organized attributes such as or .
+ /// TODO: add more documentation about how a data file works at one point.
public class UndertaleData
{
///
@@ -216,7 +221,7 @@ public object this[Type resourceType]
///
public IList EmbeddedTextures => FORM.TXTR?.List;
-
+ //TODO: no idea what this is. Seems to sometimes not exist?
public IList TextureGroupInfo => FORM.TGIN?.List;
///
@@ -308,6 +313,8 @@ public object this[Type resourceType]
///
public Dictionary KnownSubFunctions;
+ //Profile mode related properties
+ //TODO: vlad, help with this pls
public ConcurrentDictionary GMLCache { get; set; }
public List GMLCacheFailed { get; set; }
public ConcurrentBag GMLCacheChanged { get; set; } = new();
@@ -315,13 +322,12 @@ public object this[Type resourceType]
public bool GMLCacheWasSaved { get; set; }
public bool GMLCacheIsReady { get; set; } = true;
-
///
/// Get a resource from the data file by name.
///
/// The name of the desired resource.
/// Whether to ignore casing while searching.
- ///
+ /// The .
public UndertaleNamedResource ByName(string name, bool ignoreCase = false)
{
// TODO: Check if those are all possible types
@@ -422,7 +428,7 @@ private bool TestGMS1Version(uint stableBuild, uint betaBuild, bool allowGMS2 =
/// The minor version.
/// The release version.
/// The build version.
- ///
+ /// Whether the version of the data file is the same or higher than a specified version.
public bool IsVersionAtLeast(uint major, uint minor, uint release, uint build)
{
if (GeneralInfo.Major != major)
From bf6b38476f1eb9308ef661631fd5011f0b7bf388 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Sat, 26 Mar 2022 19:58:49 +0100
Subject: [PATCH 07/18] Add more documentation to models and data
- document more in data
- finish timeline
- finish texturegroupinfo
- finish string
- finish sound
- finish script
- almost finish embeddedTexture
- finish embeddedAudio
- add a bit more in code
- slight tweaks to background and animationcurve.
---
.../Models/UndertaleAnimationCurve.cs | 2 +-
UndertaleModLib/Models/UndertaleBackground.cs | 2 +-
UndertaleModLib/Models/UndertaleCode.cs | 19 +++++-
.../Models/UndertaleEmbeddedAudio.cs | 10 ++++
.../Models/UndertaleEmbeddedTexture.cs | 24 ++++++++
UndertaleModLib/Models/UndertaleScript.cs | 10 ++--
UndertaleModLib/Models/UndertaleSound.cs | 21 ++++++-
UndertaleModLib/Models/UndertaleString.cs | 26 +++++++-
.../Models/UndertaleTextureGroupInfo.cs | 59 +++++++++++++++++++
UndertaleModLib/Models/UndertaleTimeline.cs | 12 +++-
UndertaleModLib/UndertaleBaseTypes.cs | 15 +++++
UndertaleModLib/UndertaleData.cs | 28 ++++++++-
12 files changed, 212 insertions(+), 16 deletions(-)
diff --git a/UndertaleModLib/Models/UndertaleAnimationCurve.cs b/UndertaleModLib/Models/UndertaleAnimationCurve.cs
index ef905fcf4..63028484c 100644
--- a/UndertaleModLib/Models/UndertaleAnimationCurve.cs
+++ b/UndertaleModLib/Models/UndertaleAnimationCurve.cs
@@ -56,7 +56,7 @@ public void Unserialize(UndertaleReader reader)
///
/// Deserializes from a specified to the current data file.
///
- ///
+ /// Where to deserialize from.
/// Whether to include in the deserialization.
public void Unserialize(UndertaleReader reader, bool includeName)
{
diff --git a/UndertaleModLib/Models/UndertaleBackground.cs b/UndertaleModLib/Models/UndertaleBackground.cs
index d2e24363b..df05051c4 100644
--- a/UndertaleModLib/Models/UndertaleBackground.cs
+++ b/UndertaleModLib/Models/UndertaleBackground.cs
@@ -17,7 +17,7 @@ namespace UndertaleModLib.Models
public class UndertaleBackground : UndertaleNamedResource
{
///
- /// A tile id, which can be used for referencing specific tiles in a tileset.
+ /// A tile id, which can be used for referencing specific tiles in a tileset. Game Maker Studio 2 only.
///
public class TileID : UndertaleObject, INotifyPropertyChanged
{
diff --git a/UndertaleModLib/Models/UndertaleCode.cs b/UndertaleModLib/Models/UndertaleCode.cs
index 3ec47c062..02ea9b921 100644
--- a/UndertaleModLib/Models/UndertaleCode.cs
+++ b/UndertaleModLib/Models/UndertaleCode.cs
@@ -1005,6 +1005,7 @@ public class UndertaleCode : UndertaleNamedResource, UndertaleObjectWithBlobs
public bool WeirdLocalsFlag { get; set; }
public uint Offset { get; set; }
+
///
/// A list of bytecode instructions this code entry has.
///
@@ -1157,6 +1158,10 @@ public UndertaleInstruction GetInstructionBeforeAddress(uint address)
return null;
}
+ ///
+ /// Finds and returns a list of all variables this code entry references.
+ ///
+ /// A list of all variables this code entry references.
public IList FindReferencedVars()
{
List vars = new List();
@@ -1169,6 +1174,10 @@ public IList FindReferencedVars()
return vars;
}
+ ///
+ /// Finds and returns a list of all local variables this code entry references.
+ ///
+ /// A list of all local variables this code entry references.
public IList FindReferencedLocalVars()
{
return FindReferencedVars().Where((x) => x.InstanceType == UndertaleInstruction.InstanceType.Local).ToList();
@@ -1198,8 +1207,8 @@ public void Replace(IList instructions)
/// Append GML instructions at the end of this code entry.
///
/// The GML code to append.
- /// From which data file the gml code is coming from.
- /// if the GML code does not compile or if there's an error writing the code to the entry in profile mode.
+ /// From which data file the GML code is coming from.
+ /// if the GML code does not compile or if there's an error writing the code to the profile entry.
public void AppendGML(string gmlCode, UndertaleData data)
{
CompileContext context = Compiler.Compiler.CompileGMLText(gmlCode, data, this);
@@ -1229,6 +1238,12 @@ public void AppendGML(string gmlCode, UndertaleData data)
}
}
+ ///
+ /// Replaces all instructions currently existing in this code entry with another set of GML instructions.
+ ///
+ /// The new GML code for this code entry.
+ /// From which data file the GML code is coming from.
+ /// If the GML code does not compile or if there's an error writing the code to the profile entry.
public void ReplaceGML(string gmlCode, UndertaleData data)
{
CompileContext context = Compiler.Compiler.CompileGMLText(gmlCode, data, this);
diff --git a/UndertaleModLib/Models/UndertaleEmbeddedAudio.cs b/UndertaleModLib/Models/UndertaleEmbeddedAudio.cs
index f7283348b..cafca30e5 100644
--- a/UndertaleModLib/Models/UndertaleEmbeddedAudio.cs
+++ b/UndertaleModLib/Models/UndertaleEmbeddedAudio.cs
@@ -9,10 +9,20 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// An embedded audio entry in a data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleEmbeddedAudio : UndertaleNamedResource, PaddedObject
{
+ ///
+ /// The name of the embedded audio entry.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// The audio data of the embedded audio entry.
+ ///
public byte[] Data { get; set; } = Array.Empty();
public void Serialize(UndertaleWriter writer)
diff --git a/UndertaleModLib/Models/UndertaleEmbeddedTexture.cs b/UndertaleModLib/Models/UndertaleEmbeddedTexture.cs
index f412c8964..3378e7f85 100644
--- a/UndertaleModLib/Models/UndertaleEmbeddedTexture.cs
+++ b/UndertaleModLib/Models/UndertaleEmbeddedTexture.cs
@@ -12,12 +12,30 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// An embedded texture entry in the data file.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleEmbeddedTexture : UndertaleNamedResource
{
+ ///
+ /// The name of the embedded texture entry.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// Whether or not this embedded texture is scaled.
+ ///
public uint Scaled { get; set; } = 0;
+
+ ///
+ /// The amount of generated mipmap levels.
+ ///
public uint GeneratedMips { get; set; }
+
+ ///
+ /// The texture data in the embedded image.
+ ///
public TexData TextureData { get; set; } = new TexData();
public void Serialize(UndertaleWriter writer)
@@ -63,10 +81,16 @@ public override string ToString()
return Name.Content + " (" + GetType().Name + ")";
}
+ ///
+ /// Texture data in an .
+ ///
public class TexData : UndertaleObject, INotifyPropertyChanged
{
private byte[] _TextureBlob;
+ ///
+ /// The image data of the texture.
+ ///
public byte[] TextureBlob { get => _TextureBlob; set { _TextureBlob = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TextureBlob))); } }
public event PropertyChangedEventHandler PropertyChanged;
diff --git a/UndertaleModLib/Models/UndertaleScript.cs b/UndertaleModLib/Models/UndertaleScript.cs
index 87882f03d..dfe32884d 100644
--- a/UndertaleModLib/Models/UndertaleScript.cs
+++ b/UndertaleModLib/Models/UndertaleScript.cs
@@ -24,15 +24,17 @@ public class UndertaleScript : UndertaleNamedResource, INotifyPropertyChanged
///
public UndertaleCode Code { get => _Code.Resource; set { _Code.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Code))); } }
-
- public bool Constructor { get; set; } = false;
+ ///
+ /// Whether or not this script is a constructor.
+ ///
+ public bool IsConstructor { get; set; } = false;
public event PropertyChangedEventHandler PropertyChanged;
public void Serialize(UndertaleWriter writer)
{
writer.WriteUndertaleString(Name);
- if (Constructor)
+ if (IsConstructor)
writer.Write((uint)_Code.SerializeById(writer) | 2147483648u);
else
writer.WriteUndertaleObject(_Code);
@@ -44,7 +46,7 @@ public void Unserialize(UndertaleReader reader)
int id = reader.ReadInt32();
if (id < -1)
{
- Constructor = true;
+ IsConstructor = true;
id = (int)((uint)id & 2147483647u);
}
_Code.UnserializeById(reader, id);
diff --git a/UndertaleModLib/Models/UndertaleSound.cs b/UndertaleModLib/Models/UndertaleSound.cs
index 1c9401576..f8cfbfccf 100644
--- a/UndertaleModLib/Models/UndertaleSound.cs
+++ b/UndertaleModLib/Models/UndertaleSound.cs
@@ -19,15 +19,22 @@ public class UndertaleSound : UndertaleNamedResource, INotifyPropertyChanged
public enum AudioEntryFlags : uint
{
///
- /// Whether the sound is embedded.
+ /// Whether the sound is embedded into the data file.
///
IsEmbedded = 0x1,
///
/// Whether the sound is compressed.
///
IsCompressed = 0x2,
-
+ ///
+ /// Whether the sound is compressed on load.
+ ///
IsDecompressedOnLoad = 0x3,
+ ///
+ /// Whether this sound uses the "new audio system".
+ ///
+ /// This is default for everything post Game Maker: Studio.
+ /// The legacy sound system was used in pre Game Maker 8
Regular = 0x64, // also means "Use New Audio System?" Set by default on GMS 2.
}
@@ -51,6 +58,11 @@ public enum AudioEntryFlags : uint
///
public UndertaleString File { get; set; }
+ ///
+ /// A pre- Game Maker: Studio way of having certain effects on a sound effect.
+ ///
+ /// The exact way this works is unknown. But following values are possible:
+ /// Chorus, Echo, Flanger, Reverb, Gargle, all possible to be combined with one another.
public uint Effects { get; set; } = 0;
///
@@ -82,7 +94,7 @@ public enum AudioEntryFlags : uint
public UndertaleEmbeddedAudio AudioFile { get => _AudioFile.Resource; set { _AudioFile.Resource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AudioFile))); } }
///
- /// The id of .
+ /// The id of .
///
public int AudioID { get => _AudioFile.CachedId; set { _AudioFile.CachedId = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AudioID))); } }
@@ -157,6 +169,9 @@ public override string ToString()
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleAudioGroup : UndertaleNamedResource
{
+ ///
+ /// The name of the audio group.
+ ///
public UndertaleString Name { get; set; }
public void Serialize(UndertaleWriter writer)
diff --git a/UndertaleModLib/Models/UndertaleString.cs b/UndertaleModLib/Models/UndertaleString.cs
index 5b8b13519..e19529e29 100644
--- a/UndertaleModLib/Models/UndertaleString.cs
+++ b/UndertaleModLib/Models/UndertaleString.cs
@@ -10,15 +10,28 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// A string entry a data file can have.
+ ///
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleString : UndertaleResource, ISearchable
{
+ ///
+ /// The contents of the string.
+ ///
public string Content { get; set; }
+ ///
+ /// Initializes a new empty instance of type .
+ ///
public UndertaleString()
{
}
+ ///
+ /// Initializes a new instance of type with a specified content.
+ ///
+ /// The content for the string.
public UndertaleString(string content)
{
this.Content = content;
@@ -39,6 +52,11 @@ public override string ToString()
return ToString(true);
}
+ ///
+ /// Returns a string that represents the current object.
+ ///
+ /// Whether the string is from a Game Maker: Studio 2 data file or not.
+ /// A string that represents the current object.
public string ToString(bool isGMS2)
{
if (Content == null)
@@ -82,8 +100,12 @@ public bool SearchMatches(string filter)
{
return Content?.ToLower().Contains(filter.ToLower()) ?? false;
}
-
- // Unescapes text for the assembler
+
+ ///
+ /// Unescapes text for the assembler.
+ ///
+ /// The text to unescape.
+ /// A string with \n, \r, " and \ being properly escaped.
public static string UnescapeText(string text)
{
return text.Replace("\\r", "\r").Replace("\\n", "\n").Replace("\\\"", "\"").Replace("\\\\", "\\");
diff --git a/UndertaleModLib/Models/UndertaleTextureGroupInfo.cs b/UndertaleModLib/Models/UndertaleTextureGroupInfo.cs
index e06be4bb4..4f8e37da6 100644
--- a/UndertaleModLib/Models/UndertaleTextureGroupInfo.cs
+++ b/UndertaleModLib/Models/UndertaleTextureGroupInfo.cs
@@ -8,14 +8,73 @@
namespace UndertaleModLib.Models
{
+ ///
+ /// A texture group info entry in a data file.
+ ///
+ /// This is a new chunk since Bytecode 17. It's probably related to performance improvements mentioned in the release notes for that runtime.
+ /// Here is the specification:
+ ///
+ /// TGIN structure - likely stands for Texture Group Info
+ /// Chunk introduced in 2.2.1 with new texture functions
+ /// ---
+ ///
+ /// Int32 - probably chunk format version number, always 1
+ ///
+ /// PointerList<T> structure. Each item represents a texture group:
+ /// 32-bit string pointer - Name
+ /// 32-bit pointer #1
+ /// 32-bit pointer #2
+ /// 32-bit pointer #3
+ /// 32-bit pointer #4
+ /// 32-bit pointer #5
+ ///
+ /// #1 leads here:
+ /// SimpleList<int> of texture page IDs the group has
+ ///
+ /// #2 leads here:
+ /// SimpleList<int> of sprite IDs the group has
+ ///
+ /// #3 leads here:
+ /// SimpleList<int> of Spine sprite IDs (normal sprite ID, just this has Spine sprites separated) the group has
+ ///
+ /// #4 leads here:
+ /// SimpleList<int> of font IDs the group has
+ ///
+ /// #5 leads here:
+ /// SimpleList<int> of tileset IDs the group has
+ ///
+ /// .
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class UndertaleTextureGroupInfo : UndertaleNamedResource
{
+ ///
+ /// The name of the texture group info entry.
+ ///
public UndertaleString Name { get; set; }
+
+ ///
+ /// A list of texture pages the group has.
+ ///
public UndertaleSimpleResourcesList TexturePages { get; set; }
+
+ ///
+ /// A list of sprites the group has.
+ ///
public UndertaleSimpleResourcesList Sprites { get; set; }
+
+ ///
+ /// A list of spine sprites the group has.
+ ///
public UndertaleSimpleResourcesList SpineSprites { get; set; }
+
+ ///
+ /// A list of fonts the group has.
+ ///
public UndertaleSimpleResourcesList Fonts { get; set; }
+
+ ///
+ /// A list of tilesets this group has.
+ ///
public UndertaleSimpleResourcesList Tilesets { get; set; }
public UndertaleTextureGroupInfo()
diff --git a/UndertaleModLib/Models/UndertaleTimeline.cs b/UndertaleModLib/Models/UndertaleTimeline.cs
index c18d7a04c..e6b4f96d4 100644
--- a/UndertaleModLib/Models/UndertaleTimeline.cs
+++ b/UndertaleModLib/Models/UndertaleTimeline.cs
@@ -30,6 +30,9 @@ public class UndertaleTimelineMoment : UndertaleObject
///
public UndertalePointerList Event { get; set; }
+ ///
+ /// Initializes a new empty instance of the class.
+ ///
public UndertaleTimelineMoment()
{
/*
@@ -38,10 +41,15 @@ public UndertaleTimelineMoment()
*/
}
- public UndertaleTimelineMoment(uint step, UndertalePointerList ev)
+ ///
+ /// Initializes a new instance of the with the specified step time and event action list.
+ ///
+ /// After how many steps the moment shall be executed.
+ /// A list of events that shall be executed.
+ public UndertaleTimelineMoment(uint step, UndertalePointerList events)
{
Step = step;
- Event = ev;
+ Event = events;
}
public void Serialize(UndertaleWriter writer)
diff --git a/UndertaleModLib/UndertaleBaseTypes.cs b/UndertaleModLib/UndertaleBaseTypes.cs
index 65d770f7d..7682e37ad 100644
--- a/UndertaleModLib/UndertaleBaseTypes.cs
+++ b/UndertaleModLib/UndertaleBaseTypes.cs
@@ -39,7 +39,16 @@ public interface UndertaleObjectWithBlobs
public interface PaddedObject // TODO: use this everywhere
{
+ ///
+ /// TODO!
+ ///
+ /// Where to serialize to.
void SerializePadding(UndertaleWriter writer);
+
+ ///
+ /// TODO!
+ ///
+ /// Where to deserialize from.
void UnserializePadding(UndertaleReader reader);
}
@@ -80,6 +89,12 @@ public interface UndertaleNamedResource : UndertaleResource
public interface ISearchable
{
+ ///
+ /// Returns a value indicating whether a specified substring occurs within this object.
+ ///
+ /// The string to seek. Case insensitive.
+ /// if occurs within this object, or if
+ /// is the empty string (""); otherwise, false.
bool SearchMatches(string filter);
}
}
diff --git a/UndertaleModLib/UndertaleData.cs b/UndertaleModLib/UndertaleData.cs
index d6820209c..0d7e8d208 100644
--- a/UndertaleModLib/UndertaleData.cs
+++ b/UndertaleModLib/UndertaleData.cs
@@ -314,12 +314,38 @@ public object this[Type resourceType]
public Dictionary KnownSubFunctions;
//Profile mode related properties
- //TODO: vlad, help with this pls
+
+ //TODO: Why are the functions that deal with the cache in a completely different place than the cache parameters? These have *no* place of being here.
+ ///
+ /// A of cached decompiled code,
+ /// with the code name as the Key and the decompiled code text as the value.
+ ///
public ConcurrentDictionary GMLCache { get; set; }
+
+ ///
+ /// A list of names of code entries which failed to compile or decompile.
+ ///
public List GMLCacheFailed { get; set; }
+
+ ///
+ /// A list of names of modified code entries.
+ ///
public ConcurrentBag GMLCacheChanged { get; set; } = new();
+
+ ///
+ /// A list of names of code entries that were edited before the "Use decompiled code cache" setting was enabled.
+ ///
public List GMLEditedBefore { get; set; }
+
+ ///
+ /// Whether the decompiled code cache has been saved to disk with no new cache changes happening since then.
+ ///
public bool GMLCacheWasSaved { get; set; }
+
+ ///
+ /// Whether the decompiled code cache is generated. This will be if it's currently generating and
+ /// otherwise.
+ ///
public bool GMLCacheIsReady { get; set; } = true;
///
From f0507183645033013736e8ea921224ee2e6c35b6 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Sat, 26 Mar 2022 21:33:55 +0100
Subject: [PATCH 08/18] Put c# version back to 9
---
UndertaleModTool/UndertaleModTool.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/UndertaleModTool/UndertaleModTool.csproj b/UndertaleModTool/UndertaleModTool.csproj
index 71284c929..b95e213e4 100644
--- a/UndertaleModTool/UndertaleModTool.csproj
+++ b/UndertaleModTool/UndertaleModTool.csproj
@@ -26,7 +26,7 @@
embedded
AnyCPU;x64
win-x64;win-x86
- 10
+ 9
UndertaleModTool.Program
From 573d9ac7373256db396a7b4764a12e2ccd3caada Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Sun, 27 Mar 2022 16:29:26 +0200
Subject: [PATCH 09/18] Fix broken scripts, document AUMIMessage
---
UndertaleModCli/Program.cs | 2 +-
UndertaleModLib/AumiIPC.cs | 40 ++++++++++++++++
UndertaleModLib/Scripting/IScriptInterface.cs | 10 ++--
UndertaleModTests/GameScriptTests.cs | 10 ++--
.../CommunityScripts/ExternalizeAllOGGs.csx | 48 +++++++++----------
.../CommunityScripts/UndertaleWithJSONs.csx | 14 +++---
.../DemoScripts/TestExportAllCode.csx | 6 +--
.../HelperScripts/ExportAllSoundsOld.csx | 12 ++---
UndertaleModTool/MainWindow.xaml.cs | 2 +-
.../Repackers/ApplyBasicGraphicsMod.csx | 8 ++--
.../Repackers/CopySpriteBgFont.csx | 10 ++--
.../Repackers/CopySpriteBgFontInternal.csx | 10 ++--
UndertaleModTool/Repackers/ImportASM.csx | 8 ++--
UndertaleModTool/Repackers/ImportASM_2_3.csx | 16 +++----
.../Repackers/ImportAllTilesets.csx | 6 +--
UndertaleModTool/Repackers/ImportGML.csx | 8 ++--
UndertaleModTool/Repackers/ImportGML_2_3.csx | 16 +++----
UndertaleModTool/Repackers/ImportMasks.csx | 8 ++--
.../Repackers/ImportSoundsBulk.csx | 14 +++---
.../Repackers/ReduceEmbeddedTexturePages.csx | 10 ++--
.../SampleScripts/FindAndReplace.csx | 12 ++---
UndertaleModTool/SampleScripts/Search.csx | 10 ++--
UndertaleModTool/SampleScripts/SearchASM.csx | 6 +--
.../SampleScripts/SearchLimited.csx | 6 +--
.../TechnicalScripts/ExportAllCode2_3.csx | 10 ++--
.../TechnicalScripts/ExportAllCodeSync.csx | 18 +++----
.../ExportAndConvert_2_3_ASM.csx | 26 +++++-----
.../ImportGraphics_Full_Repack.csx | 4 +-
.../Unpackers/DumpSpecificCode.csx | 16 +++----
UndertaleModTool/Unpackers/ExportASM.csx | 16 +++----
UndertaleModTool/Unpackers/ExportAllCode.csx | 10 ++--
.../Unpackers/ExportAllEmbeddedTextures.csx | 10 ++--
.../Unpackers/ExportAllRoomsToPng.csx | 8 ++--
.../Unpackers/ExportAllSounds.csx | 42 ++++++++--------
.../Unpackers/ExportAllSprites.csx | 10 ++--
.../Unpackers/ExportAllTextures.csx | 10 ++--
.../Unpackers/ExportAllTexturesGrouped.csx | 10 ++--
.../Unpackers/ExportAllTilesets.csx | 10 ++--
UndertaleModTool/Unpackers/ExportFontData.csx | 6 +--
UndertaleModTool/Unpackers/ExportMasks.csx | 8 ++--
40 files changed, 273 insertions(+), 233 deletions(-)
diff --git a/UndertaleModCli/Program.cs b/UndertaleModCli/Program.cs
index a0a20c8ae..543fd3dc3 100644
--- a/UndertaleModCli/Program.cs
+++ b/UndertaleModCli/Program.cs
@@ -805,7 +805,7 @@ public void SyncBinding(string resourceType, bool enable)
{
//there is no UI with any data binding
}
- public void DisableAllSyncBinding()
+ public void DisableAllSyncBindings()
{
//there is no UI with any data binding
}
diff --git a/UndertaleModLib/AumiIPC.cs b/UndertaleModLib/AumiIPC.cs
index 8555bf2b1..9a5ccc6b9 100644
--- a/UndertaleModLib/AumiIPC.cs
+++ b/UndertaleModLib/AumiIPC.cs
@@ -10,7 +10,39 @@ namespace UndertaleModLib
{
public struct IpcMessage_t
{
+ ///
+ /// A numerical value (1 to 4 for the latest AUMI implementation).
+ ///
+ ///
+ /// The following table describes and explains the numerical values:
+ ///
+ ///
+ /// number
+ /// Explanation
+ ///
+ /// -
+ /// 1
+ /// Test Communication - Always returns a string that's 128 characters long.
+ ///
+ /// -
+ /// 2
+ /// Get Function By Index - Returns information about a function at a specified index in the runner.
+ ///
+ /// -
+ /// 3
+ /// Get Function By Name - Returns information about a function with a specified name.
+ ///
+ /// -
+ /// 4
+ /// Execute Code - Executes precompiled bytecode in the global context.
+ ///
+ ///
+ ///
public short FuncID;
+
+ ///
+ /// A 512 byte buffer containing information which accompanies .
+ ///
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] Buffer;
@@ -30,7 +62,15 @@ public byte[] RawBytes()
public struct IpcReply_t
{
+ ///
+ /// A numerical value from 0 to n, where 0 means success.
+ ///
+ /// Anything other than 0 means failure, where the number specifies the actual reason.
public int AUMIResult; // Always contains a value.
+
+ ///
+ /// A 128 byte buffer, might not always be filled in.
+ ///
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] Buffer;
diff --git a/UndertaleModLib/Scripting/IScriptInterface.cs b/UndertaleModLib/Scripting/IScriptInterface.cs
index 005089219..256564dbc 100644
--- a/UndertaleModLib/Scripting/IScriptInterface.cs
+++ b/UndertaleModLib/Scripting/IScriptInterface.cs
@@ -136,11 +136,11 @@ void EnsureDataLoaded()
void ScriptOpenURL(string url);
///
- /// Used for communicating with AUMI (Archie's Undertale Modding Interface).
+ /// Used for communicating with AUMI (Archie's Undertale Modding Interface).
///
- /// TODO
- /// TODO
- /// TODO
+ /// The message to send.
+ /// The reply from AUMI.
+ /// if the message couldn't be sent. Otherwise, the function returns .
bool SendAUMIMessage(IpcMessage_t ipMessage, ref IpcReply_t outReply)
{
// By Archie
@@ -408,7 +408,7 @@ bool AreFilesIdentical(string file1, string file2)
///
/// Stops the synchronization of all previously enabled assets.
///
- void DisableAllSyncBinding();
+ void DisableAllSyncBindings();
///
/// Starts the task that updates a progress bar in parallel.
diff --git a/UndertaleModTests/GameScriptTests.cs b/UndertaleModTests/GameScriptTests.cs
index 359c2328a..6d8dbe004 100644
--- a/UndertaleModTests/GameScriptTests.cs
+++ b/UndertaleModTests/GameScriptTests.cs
@@ -129,15 +129,15 @@ public void AddProgress(int amount)
}
public void IncrementProgress()
{
- Console.WriteLine("IncProgress()");
+ Console.WriteLine("IncrementProgress()");
}
public void AddProgressParallel(int amount)
{
- Console.WriteLine($"AddProgressP(): {amount}");
+ Console.WriteLine($"AddProgressParallel(): {amount}");
}
public void IncrementProgressParallel()
{
- Console.WriteLine("IncProgressP()");
+ Console.WriteLine("IncrementProgressParallel()");
}
public int GetProgress()
{
@@ -224,9 +224,9 @@ public void SyncBinding(string resourceType, bool enable)
{
Console.WriteLine($"SyncBinding(): \"{resourceType}\", {enable}");
}
- public void DisableAllSyncBinding()
+ public void DisableAllSyncBindings()
{
- Console.WriteLine($"SyncBinding(): disabled");
+ Console.WriteLine($"DisableAllSyncBindings(): disabled");
}
public void StartProgressBarUpdater()
{
diff --git a/UndertaleModTool/CommunityScripts/ExternalizeAllOGGs.csx b/UndertaleModTool/CommunityScripts/ExternalizeAllOGGs.csx
index 51d6d5d92..0561bf088 100644
--- a/UndertaleModTool/CommunityScripts/ExternalizeAllOGGs.csx
+++ b/UndertaleModTool/CommunityScripts/ExternalizeAllOGGs.csx
@@ -17,7 +17,7 @@ bool usesAGRPs = (Data.AudioGroups.Count > 0);
if (Data.AudioGroups.Count > 1)
{
- bool warningCheck = ScriptQuestion(@"This game uses external audiogroup.dat files.
+ bool warningCheck = ScriptQuestion(@"This game uses external audiogroup.dat files.
In order to externalize the audio files it will clear all data from the external audiogroup.dat files.
It is recommended that you make a backup of your game files.
If you have already made a backup and wish to continue, select 'Yes'.
@@ -30,8 +30,8 @@ Otherwise, select 'No', and make a backup of the game before using this script.
//Overwrite Folder Check One
if (Directory.Exists(winFolder + "Exported_Sounds\\"))
{
- bool overwriteCheckOne = ScriptQuestion(@"An 'Exported_Sounds' folder already exists.
-Would you like to remove it? This may some time.
+ bool overwriteCheckOne = ScriptQuestion(@"An 'Exported_Sounds' folder already exists.
+Would you like to remove it? This may some time.
Note: If an error window stating that 'the directory is not empty' appears, please try again or delete the folder manually.
");
@@ -60,16 +60,16 @@ You will have to check the code for these functions and change it accordingly.
}
SetProgressBar(null, "Externalizing Sounds...", 0, Data.Sounds.Count);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("Strings", true);
await Task.Run(() => {
DumpSounds(); // This runs sync, because it has to load audio groups.
ExternalizeSounds(); // This runs sync, because it has to load audio groups.
});
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Externalization Complete.\nExternalized " + sounds.ToString() + " sounds.\n\nNOTE: You will need to convert any external WAV files into OGG files.\nThen replace the WAV file with the OGG file.\nOtherwise the sound will not play.\nA batch conversion tool such as 'LameXP' will help.\nCheck the #faq for more information or message Grossley#2869 on Discord.");
@@ -80,12 +80,12 @@ void ExternalizeSounds()
ExternalizeSound(sound);
}
-string GetFolder(string path)
+string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}
-void ExternalizeSound(UndertaleSound sound)
+void ExternalizeSound(UndertaleSound sound)
{
bool flagCompressed = sound.Flags.HasFlag(UndertaleSound.AudioEntryFlags.IsCompressed);
bool flagEmbedded = sound.Flags.HasFlag(UndertaleSound.AudioEntryFlags.IsEmbedded);
@@ -95,8 +95,8 @@ void ExternalizeSound(UndertaleSound sound)
string searchName = sound.Name.Content;
string searchFilePath = winFolder + "Exported_Sounds\\";
// If it's not an external file already, setup the sound entry such that it is external.
- if (flagCompressed == true || flagEmbedded == true)
- {
+ if (flagCompressed == true || flagEmbedded == true)
+ {
// 4.
string[] files = Directory.GetFiles(searchFilePath, searchName + ".*", SearchOption.AllDirectories);
var path_result = files[0];
@@ -117,7 +117,7 @@ void ExternalizeSound(UndertaleSound sound)
//Array.Resize(audioGroupDat.EmbeddedAudio[_audioid].Data, 1);
audioGroupDat.EmbeddedAudio[_audioid].Data = new byte[1];
audioGroupDat.EmbeddedAudio[_audioid].Data[0] = 0;
-
+
var audioGroupWriteStream = (new FileStream(winFolder + "audiogroup" + _groupid.ToString() + ".dat", FileMode.Create));
UndertaleIO.Write(audioGroupWriteStream, audioGroupDat); // Write it to the disk
audioGroupWriteStream.Dispose();
@@ -137,9 +137,9 @@ void ExternalizeSound(UndertaleSound sound)
sound.AudioGroup = Data.AudioGroups[Data.GetBuiltinSoundGroupID()];
}
// if it doesn't then we shouldn't care, it's always null.
-
+
sounds++;
- IncProgress();
+ IncrementProgress();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -147,7 +147,7 @@ void ExternalizeSound(UndertaleSound sound)
byte[] EMPTY_WAV_FILE_BYTES = System.Convert.FromBase64String("UklGRiQAAABXQVZFZm10IBAAAAABAAIAQB8AAAB9AAAEABAAZGF0YQAAAAA=");
string DEFAULT_AUDIOGROUP_NAME = "audiogroup_default";
-void MakeFolder(String folderName)
+void MakeFolder(String folderName)
{
if (!Directory.Exists(winFolder + folderName + "/"))
Directory.CreateDirectory(winFolder + folderName + "/");
@@ -155,25 +155,25 @@ void MakeFolder(String folderName)
Dictionary> loadedAudioGroups;
-IList GetAudioGroupData(UndertaleSound sound)
+IList GetAudioGroupData(UndertaleSound sound)
{
if (loadedAudioGroups == null)
loadedAudioGroups = new Dictionary>();
-
+
string audioGroupName = sound.AudioGroup != null ? sound.AudioGroup.Name.Content : DEFAULT_AUDIOGROUP_NAME;
if (loadedAudioGroups.ContainsKey(audioGroupName))
return loadedAudioGroups[audioGroupName];
-
+
string groupFilePath = winFolder + "audiogroup" + sound.GroupID + ".dat";
if (!File.Exists(groupFilePath))
return null; // Doesn't exist.
-
- try
+
+ try
{
UndertaleData data = null;
using (var stream = new FileStream(groupFilePath, FileMode.Open, FileAccess.Read))
data = UndertaleIO.Read(stream, warning => ScriptMessage("A warning occured while trying to load " + audioGroupName + ":\n" + warning));
-
+
loadedAudioGroups[audioGroupName] = data.EmbeddedAudio;
return data.EmbeddedAudio;
} catch (Exception e)
@@ -183,12 +183,12 @@ IList GetAudioGroupData(UndertaleSound sound)
}
}
-byte[] GetSoundData(UndertaleSound sound)
+byte[] GetSoundData(UndertaleSound sound)
{
if (sound.AudioFile != null)
return sound.AudioFile.Data;
-
- if (sound.GroupID > Data.GetBuiltinSoundGroupID())
+
+ if (sound.GroupID > Data.GetBuiltinSoundGroupID())
{
IList audioGroup = GetAudioGroupData(sound);
if (audioGroup != null)
@@ -197,7 +197,7 @@ byte[] GetSoundData(UndertaleSound sound)
return EMPTY_WAV_FILE_BYTES;
}
-void DumpSounds()
+void DumpSounds()
{
foreach (UndertaleSound sound in Data.Sounds)
DumpSound(sound);
diff --git a/UndertaleModTool/CommunityScripts/UndertaleWithJSONs.csx b/UndertaleModTool/CommunityScripts/UndertaleWithJSONs.csx
index 68b87e542..d47ecd06b 100644
--- a/UndertaleModTool/CommunityScripts/UndertaleWithJSONs.csx
+++ b/UndertaleModTool/CommunityScripts/UndertaleWithJSONs.csx
@@ -25,7 +25,7 @@ else if (Data?.GeneralInfo?.DisplayName?.Content.ToLower() == "deltarune chapter
string langFolder = GetFolder(FilePath) + "lang" + Path.DirectorySeparatorChar;
ThreadLocal DECOMPILE_CONTEXT = new ThreadLocal(() => new GlobalDecompileContext(Data, false));
-if (Directory.Exists(langFolder))
+if (Directory.Exists(langFolder))
{
ScriptError("The lang files already exist.", "Error");
return;
@@ -55,7 +55,7 @@ await Task.Run(() => {
void IncProgressLocal()
{
if (GetProgress() < maxCount)
- IncProgress();
+ IncrementProgress();
}
string GetFolder(string path) {
@@ -137,11 +137,11 @@ ScriptMessage("Complete.");
void DumpJSON(string language)
{
var lang_file = Data.Code.ByName("gml_Script_textdata_" + language);
- try
+ try
{
File.WriteAllText(Path.Combine(langFolder, "lang_" + language + ".json"), (lang_file != null ? Decompiler.Decompile(lang_file, DECOMPILE_CONTEXT.Value) : ""));
- }
- catch (Exception e)
+ }
+ catch (Exception e)
{
throw new ScriptException("gml_Script_textdata_" + language + " has an error that prevents creation of JSONs.");
}
@@ -177,11 +177,11 @@ void MakeJSON(string language)
pattern = @""" \+ '""'";
replacement = @"\""""";
input = Regex.Replace(input, pattern, replacement);
-
+
pattern = @"'""'";
replacement = @"\""";
input = Regex.Replace(input, pattern, replacement);
-
+
input = input.Replace(@"\"",", @"\"""",");
pattern = @"ds_map_add\(global\.text_data_.., ("".*""), ("".*"")\)";
diff --git a/UndertaleModTool/DemoScripts/TestExportAllCode.csx b/UndertaleModTool/DemoScripts/TestExportAllCode.csx
index c468930a4..3c745df9c 100644
--- a/UndertaleModTool/DemoScripts/TestExportAllCode.csx
+++ b/UndertaleModTool/DemoScripts/TestExportAllCode.csx
@@ -24,7 +24,7 @@ bool isErrorCodeEntry = false;
ScriptMessage("If UndertaleModTool crashes during code export, or another serious error of that nature occurs, this script will record it. Please reload the game into the tool in the event the tool crashes and re-run this script until it completes successfully without crashing. A full record of code entries with fatal decompilation problems (if they exist) will be recorded by the end in \"Errored_Code_Entries.txt\".");
SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
-StartUpdater();
+StartProgressBarUpdater();
if (File.Exists(path_error))
{
@@ -132,7 +132,7 @@ await Task.Run(() => {
}
}
- IncProgress();
+ IncrementProgress();
}
});
if (write)
@@ -147,7 +147,7 @@ if (write)
}
}
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + codeFolder);
if (File.Exists(path_error2))
diff --git a/UndertaleModTool/HelperScripts/ExportAllSoundsOld.csx b/UndertaleModTool/HelperScripts/ExportAllSoundsOld.csx
index 95560b842..1d79f1534 100644
--- a/UndertaleModTool/HelperScripts/ExportAllSoundsOld.csx
+++ b/UndertaleModTool/HelperScripts/ExportAllSoundsOld.csx
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
EnsureDataLoaded();
string sndFolder = GetFolder(FilePath) + "Export_Sounds" + Path.DirectorySeparatorChar;
-if (Directory.Exists(sndFolder))
+if (Directory.Exists(sndFolder))
{
ScriptError("A sound export already exists. Please remove it.", "Error");
return;
@@ -16,11 +16,11 @@ if (Directory.Exists(sndFolder))
Directory.CreateDirectory(sndFolder);
SetProgressBar(null, "Sounds", 0, Data.Sounds.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpSounds();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + sndFolder);
@@ -31,15 +31,15 @@ string GetFolder(string path)
}
-async Task DumpSounds()
+async Task DumpSounds()
{
await Task.Run(() => Parallel.ForEach(Data.Sounds, DumpSound));
}
-void DumpSound(UndertaleSound sound)
+void DumpSound(UndertaleSound sound)
{
if (sound.AudioFile != null && !File.Exists(sndFolder + sound.File.Content))
File.WriteAllBytes(sndFolder + sound.File.Content, sound.AudioFile.Data);
- IncProgressP();
+ IncrementProgress();
}
diff --git a/UndertaleModTool/MainWindow.xaml.cs b/UndertaleModTool/MainWindow.xaml.cs
index b09b8e6fd..b00e55924 100644
--- a/UndertaleModTool/MainWindow.xaml.cs
+++ b/UndertaleModTool/MainWindow.xaml.cs
@@ -1750,7 +1750,7 @@ public void SyncBinding(string resourceType, bool enable)
}
}
}
- public void DisableAllSyncBinding() //disable all sync. bindings
+ public void DisableAllSyncBindings() //disable all sync. bindings
{
if (syncBindings.Count <= 0) return;
diff --git a/UndertaleModTool/Repackers/ApplyBasicGraphicsMod.csx b/UndertaleModTool/Repackers/ApplyBasicGraphicsMod.csx
index e090aec49..f0f43cace 100644
--- a/UndertaleModTool/Repackers/ApplyBasicGraphicsMod.csx
+++ b/UndertaleModTool/Repackers/ApplyBasicGraphicsMod.csx
@@ -44,7 +44,7 @@ foreach (string file in dirFiles)
if ((Data.Sprites.ByName(spriteName).Width != (uint)img.Width) || (Data.Sprites.ByName(spriteName).Height != (uint)img.Height))
throw new ScriptException(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
{
@@ -79,12 +79,12 @@ foreach (string file in dirFiles)
}
SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartUpdater();
+StartProgressBarUpdater();
await Task.Run(() => {
foreach (string file in dirFiles)
{
- IncProgress();
+ IncrementProgress();
string fileName = Path.GetFileName(file);
if (!fileName.EndsWith(".png") || !fileName.Contains("_"))
@@ -142,6 +142,6 @@ await Task.Run(() => {
}
});
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Import Complete!");
\ No newline at end of file
diff --git a/UndertaleModTool/Repackers/CopySpriteBgFont.csx b/UndertaleModTool/Repackers/CopySpriteBgFont.csx
index e15dc44f9..609443808 100644
--- a/UndertaleModTool/Repackers/CopySpriteBgFont.csx
+++ b/UndertaleModTool/Repackers/CopySpriteBgFont.csx
@@ -51,7 +51,7 @@ bool[] SpriteSheetsUsed = new bool[(DataEmbeddedTexturesCount + DonorDataEmbedde
int lastTextPage = Data.EmbeddedTextures.Count - 1;
SetProgressBar(null, "Textures Exported", 0, DonorData.TexturePageItems.Count);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("EmbeddedTextures, Strings, Backgrounds, Sprites, Fonts, TexturePageItems", true);
await Task.Run(() => {
@@ -265,9 +265,9 @@ await Task.Run(() => {
TexturePageItemsUsedUpdate();
RemoveUnusedTexturePageItems();
});
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
copiedAssetsCount = (copiedFontsCount + copiedBackgroundsCount + copiedSpritesCount);
ScriptMessage(copiedAssetsCount.ToString() + " assets were copied (" + copiedSpritesCount.ToString() + " Sprites, " + copiedBackgroundsCount.ToString() + " Backgrounds, and " + copiedFontsCount.ToString() + " Fonts)");
@@ -330,7 +330,7 @@ void DumpFont(UndertaleFont font)
tex_Name.Add(font.Name.Content);
tex_Type.Add("fnt");
- IncProgress();
+ IncrementProgress();
}
void DumpBackground(UndertaleBackground background)
{
@@ -342,7 +342,7 @@ void DumpBackground(UndertaleBackground background)
tex_Name.Add(background.Name.Content);
tex_Type.Add("bg");
- IncProgress();
+ IncrementProgress();
}
void NullHandler()
{
diff --git a/UndertaleModTool/Repackers/CopySpriteBgFontInternal.csx b/UndertaleModTool/Repackers/CopySpriteBgFontInternal.csx
index 7e6236875..c22c7400b 100644
--- a/UndertaleModTool/Repackers/CopySpriteBgFontInternal.csx
+++ b/UndertaleModTool/Repackers/CopySpriteBgFontInternal.csx
@@ -41,7 +41,7 @@ bool[] SpriteSheetsUsed = new bool[(DataEmbeddedTexturesCount + DataEmbeddedText
int lastTextPage = Data.EmbeddedTextures.Count - 1;
SetProgressBar(null, "Textures Exported", 0, Data.TexturePageItems.Count);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("EmbeddedTextures, Strings, Backgrounds, Sprites, Fonts, TexturePageItems", true);
await Task.Run(() => {
@@ -245,9 +245,9 @@ await Task.Run(() => {
TexturePageItemsUsedUpdate();
RemoveUnusedTexturePageItems();
});
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
copiedAssetsCount = (copiedFontsCount + copiedBackgroundsCount + copiedSpritesCount);
ScriptMessage(copiedAssetsCount.ToString() + " assets were copied (" + copiedSpritesCount.ToString() + " Sprites, " + copiedBackgroundsCount.ToString() + " Backgrounds, and " + copiedFontsCount.ToString() + " Fonts)");
@@ -305,7 +305,7 @@ void DumpFont(UndertaleFont font)
tex_Frame.Add(0);
tex_Name.Add(font.Name.Content + "_Copy");
tex_Type.Add("fnt");
- IncProgress();
+ IncrementProgress();
}
void DumpBackground(UndertaleBackground background)
{
@@ -316,7 +316,7 @@ void DumpBackground(UndertaleBackground background)
tex_Frame.Add(0);
tex_Name.Add(background.Name.Content + "_Copy");
tex_Type.Add("bg");
- IncProgress();
+ IncrementProgress();
}
void NullHandler()
{
diff --git a/UndertaleModTool/Repackers/ImportASM.csx b/UndertaleModTool/Repackers/ImportASM.csx
index 5306f11d4..8752dfe5d 100644
--- a/UndertaleModTool/Repackers/ImportASM.csx
+++ b/UndertaleModTool/Repackers/ImportASM.csx
@@ -35,7 +35,7 @@ bool stopOnError = ScriptQuestion("Stop importing on error?");
SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
await Task.Run(() => {
@@ -43,11 +43,11 @@ await Task.Run(() => {
{
ImportASMFile(file, doParse, true, false, stopOnError);
- IncProgress();
+ IncrementProgress();
}
});
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("All files successfully imported.");
\ No newline at end of file
diff --git a/UndertaleModTool/Repackers/ImportASM_2_3.csx b/UndertaleModTool/Repackers/ImportASM_2_3.csx
index eea12b0bc..2a88377f9 100644
--- a/UndertaleModTool/Repackers/ImportASM_2_3.csx
+++ b/UndertaleModTool/Repackers/ImportASM_2_3.csx
@@ -19,7 +19,7 @@ else
ScriptError("Use the regular ImportASM please!", "Incompatible");
}
-enum EventTypes
+enum EventTypes
{
Create,
Destroy,
@@ -46,9 +46,9 @@ List CodeList = new List();
if (File.Exists(importFolder + "/LookUpTable.txt"))
{
- int counter = 0;
- string line;
- System.IO.StreamReader file = new System.IO.StreamReader(importFolder + "/" + "LookUpTable.txt");
+ int counter = 0;
+ string line;
+ System.IO.StreamReader file = new System.IO.StreamReader(importFolder + "/" + "LookUpTable.txt");
while((line = file.ReadLine()) != null)
{
if (counter > 0)
@@ -72,13 +72,13 @@ bool skipGlobalScripts = true;
bool skipGlobalScriptsPrompted = false;
SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
await Task.Run(() => {
foreach (string file in dirFiles)
{
- IncProgress();
+ IncrementProgress();
string fileName = Path.GetFileName(file);
if (!(fileName.EndsWith(".asm")))
@@ -248,8 +248,8 @@ await Task.Run(() => {
}
}
});
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("All files successfully imported.");
\ No newline at end of file
diff --git a/UndertaleModTool/Repackers/ImportAllTilesets.csx b/UndertaleModTool/Repackers/ImportAllTilesets.csx
index 3421ecffb..be811e675 100644
--- a/UndertaleModTool/Repackers/ImportAllTilesets.csx
+++ b/UndertaleModTool/Repackers/ImportAllTilesets.csx
@@ -28,11 +28,11 @@ if (!Directory.Exists(winFolder + "Export_Tilesets\\"))
}
SetProgressBar(null, "Tilesets", 0, Data.Backgrounds.Count);
-StartUpdater();
+StartProgressBarUpdater();
await ImportTilesets();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Import Complete.");
@@ -58,5 +58,5 @@ void ImportTileset(UndertaleBackground tileset)
ScriptMessage($"Failed to import file {tileset.Name} (index - {Data.Backgrounds.IndexOf(tileset)}) due to: " + ex.Message);
}
- IncProgressP();
+ IncrementProgress();
}
diff --git a/UndertaleModTool/Repackers/ImportGML.csx b/UndertaleModTool/Repackers/ImportGML.csx
index 5a30cb17b..72c1c30b0 100644
--- a/UndertaleModTool/Repackers/ImportGML.csx
+++ b/UndertaleModTool/Repackers/ImportGML.csx
@@ -27,19 +27,19 @@ bool doParse = ScriptQuestion("Do you want to automatically attempt to link impo
bool stopOnError = ScriptQuestion("Stop importing on error?");
SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
await Task.Run(() => {
foreach (string file in dirFiles)
{
- IncProgress();
+ IncrementProgress();
ImportGMLFile(file, doParse, false, stopOnError);
}
});
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("All files successfully imported.");
diff --git a/UndertaleModTool/Repackers/ImportGML_2_3.csx b/UndertaleModTool/Repackers/ImportGML_2_3.csx
index 3df02228d..4c0b3ddbf 100644
--- a/UndertaleModTool/Repackers/ImportGML_2_3.csx
+++ b/UndertaleModTool/Repackers/ImportGML_2_3.csx
@@ -19,7 +19,7 @@ else
ScriptError("Use the regular ImportGML please!", "Incompatible");
}
-enum EventTypes
+enum EventTypes
{
Create,
Destroy,
@@ -46,9 +46,9 @@ List CodeList = new List();
if (File.Exists(importFolder + "/LookUpTable.txt"))
{
- int counter = 0;
- string line;
- System.IO.StreamReader file = new System.IO.StreamReader(importFolder + "/" + "LookUpTable.txt");
+ int counter = 0;
+ string line;
+ System.IO.StreamReader file = new System.IO.StreamReader(importFolder + "/" + "LookUpTable.txt");
while((line = file.ReadLine()) != null)
{
if (counter > 0)
@@ -72,13 +72,13 @@ bool skipGlobalScripts = true;
bool skipGlobalScriptsPrompted = false;
SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
await Task.Run(() => {
foreach (string file in dirFiles)
{
- IncProgress();
+ IncrementProgress();
string fileName = Path.GetFileName(file);
if (!(fileName.EndsWith(".gml")))
@@ -258,8 +258,8 @@ await Task.Run(() => {
}
}
});
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("All files successfully imported.");
\ No newline at end of file
diff --git a/UndertaleModTool/Repackers/ImportMasks.csx b/UndertaleModTool/Repackers/ImportMasks.csx
index 05c3cf09a..c7ffed861 100644
--- a/UndertaleModTool/Repackers/ImportMasks.csx
+++ b/UndertaleModTool/Repackers/ImportMasks.csx
@@ -22,7 +22,7 @@ if (importFolder == null)
string[] dirFiles = Directory.GetFiles(importFolder);
//Stop the script if there's missing sprite entries or w/e.
-foreach (string file in dirFiles)
+foreach (string file in dirFiles)
{
string FileNameWithExtension = Path.GetFileName(file);
if (!FileNameWithExtension.EndsWith(".png"))
@@ -82,12 +82,12 @@ foreach (string file in dirFiles)
}
SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartUpdater();
+StartProgressBarUpdater();
await Task.Run(() => {
foreach (string file in dirFiles)
{
- IncProgress();
+ IncrementProgress();
string FileNameWithExtension = Path.GetFileName(file);
if (!FileNameWithExtension.EndsWith(".png"))
@@ -114,6 +114,6 @@ await Task.Run(() => {
}
});
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Import Complete!");
diff --git a/UndertaleModTool/Repackers/ImportSoundsBulk.csx b/UndertaleModTool/Repackers/ImportSoundsBulk.csx
index 65d574e7e..31e4bde4e 100644
--- a/UndertaleModTool/Repackers/ImportSoundsBulk.csx
+++ b/UndertaleModTool/Repackers/ImportSoundsBulk.csx
@@ -17,7 +17,7 @@ EnsureDataLoaded();
int maxCount = 1;
-string GetFolder(string path)
+string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}
@@ -53,7 +53,7 @@ if (!emergencyCancel)
bool replaceSoundPropertiesCheck = ScriptQuestion("WARNING!:\nIf a sound already exists in the game, it will be replaced instead of added. Would you like to replace the sound properties as well?");
-bool autoSpecifyEverySound = ScriptQuestion(@"Would you like to automatically specify the characteristics of each sound?
+bool autoSpecifyEverySound = ScriptQuestion(@"Would you like to automatically specify the characteristics of each sound?
If you select no you will have to manually specify all sounds.");
manuallySpecifyEverySound = (autoSpecifyEverySound ? false : true);
@@ -74,7 +74,7 @@ if (manuallySpecifyEverySound == false)
maxCount = dirFiles.Length;
SetProgressBar(null, "Importing sounds", 0, maxCount);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("AudioGroups, EmbeddedAudio, Sounds, Strings", true);
await Task.Run(() => {
@@ -197,7 +197,7 @@ await Task.Run(() => {
}
}
}
- if (audioGroupID == 0) //If the audiogroup is zero then
+ if (audioGroupID == 0) //If the audiogroup is zero then
needAGRP = false;
UndertaleEmbeddedAudio soundData = null;
@@ -307,14 +307,14 @@ await Task.Run(() => {
}
}
});
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
ScriptMessage("Sound added successfully!\nEnjoy your meowing day!");
void IncProgressLocal()
{
if (GetProgress() < maxCount)
- IncProgress();
+ IncrementProgress();
}
diff --git a/UndertaleModTool/Repackers/ReduceEmbeddedTexturePages.csx b/UndertaleModTool/Repackers/ReduceEmbeddedTexturePages.csx
index c11287ade..e5743db30 100644
--- a/UndertaleModTool/Repackers/ReduceEmbeddedTexturePages.csx
+++ b/UndertaleModTool/Repackers/ReduceEmbeddedTexturePages.csx
@@ -35,14 +35,14 @@ Dictionary assetTypeDict = new Dictionary();
Directory.CreateDirectory(exportedTexturesFolder);
SetProgressBar(null, "Existing Textures Exported", 0, Data.TexturePageItems.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpSprites();
await DumpFonts();
await DumpBackgrounds();
worker.Cleanup();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
async Task DumpSprites()
@@ -73,7 +73,7 @@ void DumpSprite(UndertaleSprite sprite)
}
}
- AddProgressP(sprite.Textures.Count);
+ AddProgressParallel(sprite.Textures.Count);
}
void DumpFont(UndertaleFont font)
@@ -85,7 +85,7 @@ void DumpFont(UndertaleFont font)
assetCoordinateDict.Add(font.Name.Content, new int[] { tex.TargetX, tex.TargetY, tex.SourceWidth, tex.SourceHeight, tex.TargetWidth, tex.TargetHeight, tex.BoundingWidth, tex.BoundingHeight });
assetTypeDict.Add(font.Name.Content, "fnt");
- IncProgressP();
+ IncrementProgressParallel();
}
}
@@ -97,7 +97,7 @@ void DumpBackground(UndertaleBackground background)
worker.ExportAsPNG(tex, exportedTexturesFolder + background.Name.Content + ".png");
assetCoordinateDict.Add(background.Name.Content, new int[] { tex.TargetX, tex.TargetY, tex.SourceWidth, tex.SourceHeight, tex.TargetWidth, tex.TargetHeight, tex.BoundingWidth, tex.BoundingHeight });
assetTypeDict.Add(background.Name.Content, "bg");
- IncProgressP();
+ IncrementProgressParallel();
}
}
diff --git a/UndertaleModTool/SampleScripts/FindAndReplace.csx b/UndertaleModTool/SampleScripts/FindAndReplace.csx
index c4c297639..7e1cf2e69 100644
--- a/UndertaleModTool/SampleScripts/FindAndReplace.csx
+++ b/UndertaleModTool/SampleScripts/FindAndReplace.csx
@@ -22,25 +22,25 @@ if (!ScriptQuestion("This will make changes across all of the code! Are you sure
{
return;
}
-bool case_sensitive = ScriptQuestion("Case sensitive?");
-bool multiline = ScriptQuestion("Multi-line search?");
+bool case_sensitive = ScriptQuestion("Case sensitive?");
+bool multiline = ScriptQuestion("Multi-line search?");
bool isRegex = ScriptQuestion("Is regex search?");
String keyword = SimpleTextInput("Enter search terms", "Search box below", "", multiline);
String replacement = SimpleTextInput("Enter replacement term", "Search box below", "", multiline);
SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("Strings, Variables, Functions", true);
await Task.Run(() => {
foreach (UndertaleCode code in Data.Code)
{
ReplaceTextInGML(code.Name.Content, keyword, replacement, case_sensitive, isRegex);
- IncProgress();
+ IncrementProgress();
}
});
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Completed");
\ No newline at end of file
diff --git a/UndertaleModTool/SampleScripts/Search.csx b/UndertaleModTool/SampleScripts/Search.csx
index 5d6d050e8..3ad4595f1 100644
--- a/UndertaleModTool/SampleScripts/Search.csx
+++ b/UndertaleModTool/SampleScripts/Search.csx
@@ -44,14 +44,14 @@ if (regex_check)
}
bool cacheGenerated = await GenerateGMLCache(DECOMPILE_CONTEXT);
-await StopUpdater();
+await StopProgressBarUpdater();
SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpCode();
-await StopUpdater();
+await StopProgressBarUpdater();
await Task.Run(SortResults);
@@ -132,7 +132,7 @@ void DumpCode(UndertaleCode code)
failedList.Add(code.Name.Content);
}
- IncProgressP();
+ IncrementProgressParallel();
}
void ScanCode(KeyValuePair code)
{
@@ -165,5 +165,5 @@ void ScanCode(KeyValuePair code)
failedList.Add(code.Key);
}
- IncProgressP();
+ IncrementProgressParallel();
}
diff --git a/UndertaleModTool/SampleScripts/SearchASM.csx b/UndertaleModTool/SampleScripts/SearchASM.csx
index 4d66b0963..748cba132 100644
--- a/UndertaleModTool/SampleScripts/SearchASM.csx
+++ b/UndertaleModTool/SampleScripts/SearchASM.csx
@@ -41,11 +41,11 @@ if (regex_check)
}
SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpCode();
-await StopUpdater();
+await StopProgressBarUpdater();
await Task.Run(SortResults);
@@ -114,5 +114,5 @@ void DumpCode(UndertaleCode code)
}
}
- IncProgressP();
+ IncrementProgressParallel();
}
diff --git a/UndertaleModTool/SampleScripts/SearchLimited.csx b/UndertaleModTool/SampleScripts/SearchLimited.csx
index 23395effa..f7267ed2b 100644
--- a/UndertaleModTool/SampleScripts/SearchLimited.csx
+++ b/UndertaleModTool/SampleScripts/SearchLimited.csx
@@ -105,7 +105,7 @@ for (var j = 0; j < gameObjectCandidates.Count; j++)
}
SetProgressBar(null, "Code Entries", 0, codeToDump.Count);
-StartUpdater();
+StartProgressBarUpdater();
await Task.Run(() => {
for (var j = 0; j < codeToDump.Count; j++)
@@ -114,7 +114,7 @@ await Task.Run(() => {
}
});
-await StopUpdater();
+await StopProgressBarUpdater();
UpdateProgressStatus("Generating result list...");
await ClickableTextOutput("Search results.", keyword, result_count, resultsDict, true, failedList);
@@ -166,5 +166,5 @@ void DumpCode(UndertaleCode code)
failedList.Add(code.Name.Content);
}
- IncProgress();
+ IncrementProgress();
}
\ No newline at end of file
diff --git a/UndertaleModTool/TechnicalScripts/ExportAllCode2_3.csx b/UndertaleModTool/TechnicalScripts/ExportAllCode2_3.csx
index 65a810f77..9eb11c631 100644
--- a/UndertaleModTool/TechnicalScripts/ExportAllCode2_3.csx
+++ b/UndertaleModTool/TechnicalScripts/ExportAllCode2_3.csx
@@ -20,7 +20,7 @@ else
string codeFolder = GetFolder(FilePath) + "Export_Code" + Path.DirectorySeparatorChar;
ThreadLocal DECOMPILE_CONTEXT = new ThreadLocal(() => new GlobalDecompileContext(Data, false));
-if (Directory.Exists(codeFolder))
+if (Directory.Exists(codeFolder))
{
ScriptError("A code export already exists. Please remove it.", "Error");
return;
@@ -29,12 +29,12 @@ if (Directory.Exists(codeFolder))
Directory.CreateDirectory(codeFolder);
SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
-StartUpdater();
+StartProgressBarUpdater();
int failed = 0;
await Task.Run(DumpCode);
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + codeFolder + " " + failed.ToString() + " failed");
@@ -63,7 +63,7 @@ void DumpCode()
{
File.WriteAllText(path, (code != null ? Decompiler.Decompile(code, DECOMPILE_CONTEXT.Value) : ""));
}
- catch (Exception e)
+ catch (Exception e)
{
if (!(Directory.Exists(codeFolder + "/Failed/")))
{
@@ -74,6 +74,6 @@ void DumpCode()
failed += 1;
}
- IncProgress();
+ IncrementProgress();
}
}
diff --git a/UndertaleModTool/TechnicalScripts/ExportAllCodeSync.csx b/UndertaleModTool/TechnicalScripts/ExportAllCodeSync.csx
index f09e32c49..ceb7d7125 100644
--- a/UndertaleModTool/TechnicalScripts/ExportAllCodeSync.csx
+++ b/UndertaleModTool/TechnicalScripts/ExportAllCodeSync.csx
@@ -9,7 +9,7 @@ EnsureDataLoaded();
string codeFolder = GetFolder(FilePath) + "Export_Code" + Path.DirectorySeparatorChar;
ThreadLocal DECOMPILE_CONTEXT = new ThreadLocal(() => new GlobalDecompileContext(Data, false));
-if (Directory.Exists(codeFolder))
+if (Directory.Exists(codeFolder))
{
codeFolder = GetFolder(FilePath) + "Export_Code_2" + Path.DirectorySeparatorChar;
}
@@ -17,12 +17,12 @@ if (Directory.Exists(codeFolder))
Directory.CreateDirectory(codeFolder);
SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
-StartUpdater();
+StartProgressBarUpdater();
int failed = 0;
await Task.Run(DumpCode);
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + codeFolder + " " + failed.ToString() + " failed");
@@ -32,18 +32,18 @@ string GetFolder(string path)
}
-void DumpCode()
+void DumpCode()
{
foreach(UndertaleCode code in Data.Code)
{
string path = Path.Combine(codeFolder, code.Name.Content + ".gml");
if (code.ParentEntry == null)
{
- try
+ try
{
File.WriteAllText(path, (code != null ? Decompiler.Decompile(code, DECOMPILE_CONTEXT.Value) : ""));
}
- catch (Exception e)
+ catch (Exception e)
{
if (!(Directory.Exists(codeFolder + "/Failed/")))
{
@@ -60,12 +60,12 @@ void DumpCode()
{
Directory.CreateDirectory(codeFolder + "/Duplicates/");
}
- try
+ try
{
path = Path.Combine(codeFolder + "/Duplicates/", code.Name.Content + ".gml");
File.WriteAllText(path, (code != null ? Decompiler.Decompile(code, DECOMPILE_CONTEXT.Value) : ""));
}
- catch (Exception e)
+ catch (Exception e)
{
if (!(Directory.Exists(codeFolder + "/Duplicates/Failed/")))
{
@@ -77,7 +77,7 @@ void DumpCode()
}
}
- IncProgress();
+ IncrementProgress();
}
}
diff --git a/UndertaleModTool/TechnicalScripts/ExportAndConvert_2_3_ASM.csx b/UndertaleModTool/TechnicalScripts/ExportAndConvert_2_3_ASM.csx
index 1421a0301..5f5d1e46b 100644
--- a/UndertaleModTool/TechnicalScripts/ExportAndConvert_2_3_ASM.csx
+++ b/UndertaleModTool/TechnicalScripts/ExportAndConvert_2_3_ASM.csx
@@ -15,7 +15,7 @@ if (Data.ToolInfo.ProfileMode)
string codeFolder = GetFolder(FilePath) + "Export_Assembly2" + Path.DirectorySeparatorChar;
ThreadLocal DECOMPILE_CONTEXT = new ThreadLocal(() => new GlobalDecompileContext(Data, false));
-if (Directory.Exists(codeFolder))
+if (Directory.Exists(codeFolder))
{
codeFolder = GetFolder(FilePath) + "Export_Assembly2_2" + Path.DirectorySeparatorChar;
}
@@ -23,17 +23,17 @@ if (Directory.Exists(codeFolder))
Directory.CreateDirectory(codeFolder);
SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
-StartUpdater();
+StartProgressBarUpdater();
SyncBinding("Strings, CodeLocals, Variables, Functions", true);
await Task.Run(DumpCode);
-SyncBinding(false);
+DisableAllSyncBindings();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Conversion Complete.\n\nLocation: " + codeFolder);
-string GetFolder(string path)
+string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}
@@ -50,7 +50,7 @@ string ReplaceFirst(string text, string search, string replace)
void DumpCode()
{
- foreach (UndertaleCode code_orig in Data.Code)
+ foreach (UndertaleCode code_orig in Data.Code)
{
code_orig.Offset = 0;
if (Data.CodeLocals.ByName(code_orig.Name.Content) == null)
@@ -91,7 +91,7 @@ void DumpCode()
if (code_orig.ParentEntry == null)
{
string x = "";
- try
+ try
{
string disasm_code = code_orig.Disassemble(Data.Variables, Data.CodeLocals.For(code_orig));
//ScriptMessage(code_orig.Name.Content);
@@ -110,7 +110,7 @@ void DumpCode()
//Console.WriteLine(toBeSearched2);
ix = toBeSearched2.IndexOf(":" + code);
x = "";
- if (ix != -1)
+ if (ix != -1)
{
code = toBeSearched2.Substring(ix, toBeSearched2.Length - (ix));
//Console.WriteLine(code);
@@ -126,7 +126,7 @@ void DumpCode()
code_output = code_orig.Disassemble(Data.Variables, Data.CodeLocals.For(code_orig));
File.WriteAllText(str_path_to_use, code_output);
}
- catch (Exception e)
+ catch (Exception e)
{
ScriptMessage("Error " + code_orig.Name.Content + ": " + e.ToString());
SetUMTConsoleText(x);
@@ -134,7 +134,7 @@ void DumpCode()
return;
}
- IncProgress();
+ IncrementProgress();
}
else
{
@@ -142,7 +142,7 @@ void DumpCode()
{
Directory.CreateDirectory(Path.Combine(codeFolder, "Duplicates"));
}
- try
+ try
{
string str_path_to_use = Path.Combine(codeFolder, "Duplicates", code_orig.Name.Content + ".asm");
string code_output = "";
@@ -150,13 +150,13 @@ void DumpCode()
code_output = code_orig.Disassemble(Data.Variables, Data.CodeLocals.For(code_orig));
File.WriteAllText(str_path_to_use, code_output);
}
- catch (Exception e)
+ catch (Exception e)
{
string str_path_to_use = Path.Combine(codeFolder, "Duplicates", code_orig.Name.Content + ".asm");
File.WriteAllText(str_path_to_use, "/*\nDISASSEMBLY FAILED!\n\n" + e.ToString() + "\n*/"); // Please don't
}
- IncProgress();
+ IncrementProgress();
}
}
}
diff --git a/UndertaleModTool/TechnicalScripts/ImportGraphics_Full_Repack.csx b/UndertaleModTool/TechnicalScripts/ImportGraphics_Full_Repack.csx
index 7ce561fca..ffec8ea5d 100644
--- a/UndertaleModTool/TechnicalScripts/ImportGraphics_Full_Repack.csx
+++ b/UndertaleModTool/TechnicalScripts/ImportGraphics_Full_Repack.csx
@@ -100,14 +100,14 @@ Dictionary assetTypeDict = new Dictionary();
Directory.CreateDirectory(exportedTexturesFolder);
SetProgressBar(null, "Existing Textures Exported", 0, Data.TexturePageItems.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpSprites();
await DumpFonts();
await DumpBackgrounds();
worker.Cleanup();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
async Task DumpSprites()
diff --git a/UndertaleModTool/Unpackers/DumpSpecificCode.csx b/UndertaleModTool/Unpackers/DumpSpecificCode.csx
index 7f386867a..e8e41d698 100644
--- a/UndertaleModTool/Unpackers/DumpSpecificCode.csx
+++ b/UndertaleModTool/Unpackers/DumpSpecificCode.csx
@@ -95,7 +95,7 @@ for (var j = 0; j < gameObjectCandidates.Count; j++)
}
SetProgressBar(null, "Code Entries", 0, codeToDump.Count);
-StartUpdater();
+StartProgressBarUpdater();
await Task.Run(() => {
for (var j = 0; j < codeToDump.Count; j++)
@@ -104,18 +104,18 @@ await Task.Run(() => {
}
});
-await StopUpdater();
+await StopProgressBarUpdater();
-void DumpCode(UndertaleCode code)
+void DumpCode(UndertaleCode code)
{
string path = Path.Combine(codeFolder, code.Name.Content + ".gml");
if (code.ParentEntry == null)
{
- try
+ try
{
File.WriteAllText(path, (code != null ? Decompiler.Decompile(code, DECOMPILE_CONTEXT.Value) : ""));
}
- catch (Exception e)
+ catch (Exception e)
{
if (!(Directory.Exists(Path.Combine(codeFolder, "Failed"))))
{
@@ -132,12 +132,12 @@ void DumpCode(UndertaleCode code)
{
Directory.CreateDirectory(Path.Combine(codeFolder, "Duplicates"));
}
- try
+ try
{
path = Path.Combine(codeFolder, "Duplicates", code.Name.Content + ".gml");
File.WriteAllText(path, (code != null ? Decompiler.Decompile(code, DECOMPILE_CONTEXT.Value).Replace("@@This@@()", "self/*@@This@@()*/") : ""));
}
- catch (Exception e)
+ catch (Exception e)
{
if (!(Directory.Exists(Path.Combine(codeFolder, "Duplicates", "Failed"))))
{
@@ -148,5 +148,5 @@ void DumpCode(UndertaleCode code)
failed += 1;
}
}
- IncProgress();
+ IncrementProgress();
}
diff --git a/UndertaleModTool/Unpackers/ExportASM.csx b/UndertaleModTool/Unpackers/ExportASM.csx
index 5251b1846..13b022ca4 100644
--- a/UndertaleModTool/Unpackers/ExportASM.csx
+++ b/UndertaleModTool/Unpackers/ExportASM.csx
@@ -8,7 +8,7 @@ EnsureDataLoaded();
string codeFolder = GetFolder(FilePath) + "Export_Assembly" + Path.DirectorySeparatorChar;
ThreadLocal DECOMPILE_CONTEXT = new ThreadLocal(() => new GlobalDecompileContext(Data, false));
-if (Directory.Exists(codeFolder))
+if (Directory.Exists(codeFolder))
{
ScriptError("An assembly export already exists. Please remove it.", "Error");
return;
@@ -17,16 +17,16 @@ if (Directory.Exists(codeFolder))
Directory.CreateDirectory(codeFolder);
SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpCode();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + codeFolder);
-string GetFolder(string path)
+string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}
@@ -37,17 +37,17 @@ async Task DumpCode()
await Task.Run(() => Parallel.ForEach(Data.Code, DumpCode));
}
-void DumpCode(UndertaleCode code)
+void DumpCode(UndertaleCode code)
{
string path = Path.Combine(codeFolder, code.Name.Content + ".asm");
- try
+ try
{
File.WriteAllText(path, (code != null ? code.Disassemble(Data.Variables, Data.CodeLocals.For(code)) : ""));
}
- catch (Exception e)
+ catch (Exception e)
{
File.WriteAllText(path, "/*\nDISASSEMBLY FAILED!\n\n" + e.ToString() + "\n*/"); // Please don't
}
- IncProgressP();
+ IncrementProgressParallel();
}
\ No newline at end of file
diff --git a/UndertaleModTool/Unpackers/ExportAllCode.csx b/UndertaleModTool/Unpackers/ExportAllCode.csx
index e1e6c737b..248688a96 100644
--- a/UndertaleModTool/Unpackers/ExportAllCode.csx
+++ b/UndertaleModTool/Unpackers/ExportAllCode.csx
@@ -37,15 +37,15 @@ bool cacheGenerated = false;
if (exportFromCache)
{
cacheGenerated = await GenerateGMLCache(DECOMPILE_CONTEXT);
- await StopUpdater();
+ await StopProgressBarUpdater();
}
SetProgressBar(null, "Code Entries", 0, exportFromCache ? Data.GMLCache.Count + Data.GMLCacheFailed.Count : toDump.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpCode();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + codeFolder);
@@ -94,7 +94,7 @@ void DumpCode(UndertaleCode code)
}
}
- IncProgressP();
+ IncrementProgressParallel();
}
void DumpCachedCode(KeyValuePair code)
{
@@ -102,5 +102,5 @@ void DumpCachedCode(KeyValuePair code)
File.WriteAllText(path, code.Value);
- IncProgressP();
+ IncrementProgressParallel();
}
\ No newline at end of file
diff --git a/UndertaleModTool/Unpackers/ExportAllEmbeddedTextures.csx b/UndertaleModTool/Unpackers/ExportAllEmbeddedTextures.csx
index 2f940c788..d679d762f 100644
--- a/UndertaleModTool/Unpackers/ExportAllEmbeddedTextures.csx
+++ b/UndertaleModTool/Unpackers/ExportAllEmbeddedTextures.csx
@@ -15,7 +15,7 @@ if (!CanOverwrite())
MakeFolder("EmbeddedTextures");
SetProgressBar(null, "Embedded textures", 0, Data.EmbeddedTextures.Count);
-StartUpdater();
+StartProgressBarUpdater();
await Task.Run(() => {
for (var i = 0; i < Data.EmbeddedTextures.Count; i++)
@@ -29,23 +29,23 @@ await Task.Run(() => {
ScriptMessage("Failed to export file: " + ex.Message);
}
- IncProgress();
+ IncrementProgress();
}
});
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + EmbFolder);
/* Helper functions below.
*/
-string GetFolder(string path)
+string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}
-void MakeFolder(String folderName)
+void MakeFolder(String folderName)
{
string MakeFolderPath = Path.Combine(winFolder, folderName);
if (!Directory.Exists(MakeFolderPath))
diff --git a/UndertaleModTool/Unpackers/ExportAllRoomsToPng.csx b/UndertaleModTool/Unpackers/ExportAllRoomsToPng.csx
index 0337c8365..8f3153e3a 100644
--- a/UndertaleModTool/Unpackers/ExportAllRoomsToPng.csx
+++ b/UndertaleModTool/Unpackers/ExportAllRoomsToPng.csx
@@ -45,12 +45,12 @@ DirectoryInfo dir = new DirectoryInfo(exportedTexturesFolder);
TextureWorker worker = new TextureWorker();
SetProgressBar(null, "Rooms Exported", 0, roomCount);
-StartUpdater();
+StartProgressBarUpdater();
await DumpRooms();
worker.Cleanup();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; // force full garbage collection
@@ -67,7 +67,7 @@ async Task DumpRooms()
UndertaleRoom room = Data.Rooms[i];
- mainWindow.Selected = room;
+ mainWindow.Selected = room;
if (roomRenderer is null)
{
@@ -102,5 +102,5 @@ void DumpRoom(string roomName, bool last)
}
}
- IncProgress();
+ IncrementProgress();
}
\ No newline at end of file
diff --git a/UndertaleModTool/Unpackers/ExportAllSounds.csx b/UndertaleModTool/Unpackers/ExportAllSounds.csx
index dcf38f396..effc85ca3 100644
--- a/UndertaleModTool/Unpackers/ExportAllSounds.csx
+++ b/UndertaleModTool/Unpackers/ExportAllSounds.csx
@@ -16,8 +16,8 @@ bool usesAGRP = (Data.AudioGroups.Count > 0);
//Overwrite Folder Check One
if (Directory.Exists(winFolder + "Exported_Sounds\\"))
{
- bool overwriteCheckOne = ScriptQuestion(@"A 'Exported_Sounds' folder already exists.
-Would you like to remove it? This may some time.
+ bool overwriteCheckOne = ScriptQuestion(@"A 'Exported_Sounds' folder already exists.
+Would you like to remove it? This may some time.
Note: If an error window stating that 'the directory is not empty' appears, please try again or delete the folder manually.
");
@@ -33,9 +33,9 @@ Note: If an error window stating that 'the directory is not empty' appears, plea
var externalOGG_Copy = 0;
// EXTERNAL OGG CHECK
-bool externalOGGs = ScriptQuestion(@"This script exports embedded sounds.
+bool externalOGGs = ScriptQuestion(@"This script exports embedded sounds.
However, it can also export the external OGGs to a separate folder.
-If you would like to export both, select 'YES'.
+If you would like to export both, select 'YES'.
If you just want the embedded sounds, select 'NO'.
");
@@ -47,8 +47,8 @@ if (!externalOGGs)
// Overwrite Folder Check Two
if (Directory.Exists(winFolder + "External_Sounds\\") && externalOGG_Copy == 1)
{
- bool overwriteCheckTwo = ScriptQuestion(@"A 'External_Sounds' folder already exists.
-Would you like to remove it? This may some time.
+ bool overwriteCheckTwo = ScriptQuestion(@"A 'External_Sounds' folder already exists.
+Would you like to remove it? This may some time.
Note: If an error window stating that 'the directory is not empty' appears, please try again or delete the folder manually.
");
@@ -78,11 +78,11 @@ string DEFAULT_AUDIOGROUP_NAME = "audiogroup_default";
maxCount = Data.Sounds.Count;
SetProgressBar(null, "Sound", 0, maxCount);
-StartUpdater();
+StartProgressBarUpdater();
await Task.Run(DumpSounds); // This runs sync, because it has to load audio groups.
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
if (Directory.Exists(winFolder + "External_Sounds\\"))
ScriptMessage("Sounds exported to " + winFolder + " in the 'Exported_Sounds' and 'External_Sounds' folders.");
@@ -92,7 +92,7 @@ else
void IncProgressLocal()
{
if (GetProgress() < maxCount)
- IncProgress();
+ IncrementProgress();
}
void MakeFolder(String folderName)
@@ -107,40 +107,40 @@ string GetFolder(string path)
}
Dictionary> loadedAudioGroups;
-IList GetAudioGroupData(UndertaleSound sound)
+IList GetAudioGroupData(UndertaleSound sound)
{
if (loadedAudioGroups == null)
loadedAudioGroups = new Dictionary>();
-
+
string audioGroupName = sound.AudioGroup != null ? sound.AudioGroup.Name.Content : DEFAULT_AUDIOGROUP_NAME;
if (loadedAudioGroups.ContainsKey(audioGroupName))
return loadedAudioGroups[audioGroupName];
-
+
string groupFilePath = winFolder + "audiogroup" + sound.GroupID + ".dat";
if (!File.Exists(groupFilePath))
return null; // Doesn't exist.
-
- try
+
+ try
{
UndertaleData data = null;
using (var stream = new FileStream(groupFilePath, FileMode.Open, FileAccess.Read))
data = UndertaleIO.Read(stream, warning => ScriptMessage("A warning occured while trying to load " + audioGroupName + ":\n" + warning));
-
+
loadedAudioGroups[audioGroupName] = data.EmbeddedAudio;
return data.EmbeddedAudio;
- } catch (Exception e)
+ } catch (Exception e)
{
ScriptMessage("An error occured while trying to load " + audioGroupName + ":\n" + e.Message);
return null;
}
}
-byte[] GetSoundData(UndertaleSound sound)
+byte[] GetSoundData(UndertaleSound sound)
{
if (sound.AudioFile != null)
return sound.AudioFile.Data;
-
- if (sound.GroupID > Data.GetBuiltinSoundGroupID())
+
+ if (sound.GroupID > Data.GetBuiltinSoundGroupID())
{
IList audioGroup = GetAudioGroupData(sound);
if (audioGroup != null)
@@ -149,7 +149,7 @@ byte[] GetSoundData(UndertaleSound sound)
return EMPTY_WAV_FILE_BYTES;
}
-void DumpSounds()
+void DumpSounds()
{
//MakeFolder("Exported_Sounds");
foreach (UndertaleSound sound in Data.Sounds)
@@ -182,7 +182,7 @@ void DumpSound(UndertaleSound sound)
audioExt = ".ogg";
else if (flagCompressed && flagEmbedded) // 3.
audioExt = ".ogg";
- else if (!flagCompressed && !flagEmbedded)
+ else if (!flagCompressed && !flagEmbedded)
{
process = false;
audioExt = ".ogg";
diff --git a/UndertaleModTool/Unpackers/ExportAllSprites.csx b/UndertaleModTool/Unpackers/ExportAllSprites.csx
index 8d93115f4..c0d6675d9 100644
--- a/UndertaleModTool/Unpackers/ExportAllSprites.csx
+++ b/UndertaleModTool/Unpackers/ExportAllSprites.csx
@@ -21,17 +21,17 @@ if (Directory.Exists(texFolder))
Directory.CreateDirectory(texFolder);
SetProgressBar(null, "Sprites", 0, Data.Sprites.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpSprites();
worker.Cleanup();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + texFolder);
-string GetFolder(string path)
+string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}
@@ -41,11 +41,11 @@ async Task DumpSprites()
await Task.Run(() => Parallel.ForEach(Data.Sprites, DumpSprite));
}
-void DumpSprite(UndertaleSprite sprite)
+void DumpSprite(UndertaleSprite sprite)
{
for (int i = 0; i < sprite.Textures.Count; i++)
if (sprite.Textures[i]?.Texture != null)
worker.ExportAsPNG(sprite.Textures[i].Texture, texFolder + sprite.Name.Content + "_" + i + ".png", null, padded); // Include padding to make sprites look neat!
- IncProgressP();
+ IncrementProgressParallel();
}
\ No newline at end of file
diff --git a/UndertaleModTool/Unpackers/ExportAllTextures.csx b/UndertaleModTool/Unpackers/ExportAllTextures.csx
index 1f0c3cec0..af20edaa6 100644
--- a/UndertaleModTool/Unpackers/ExportAllTextures.csx
+++ b/UndertaleModTool/Unpackers/ExportAllTextures.csx
@@ -30,14 +30,14 @@ Directory.CreateDirectory(bgrFolder);
TextureWorker worker = new TextureWorker();
SetProgressBar(null, "Textures Exported", 0, Data.TexturePageItems.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpSprites();
await DumpFonts();
await DumpBackgrounds();
worker.Cleanup();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + texFolder);
@@ -68,7 +68,7 @@ void DumpSprite(UndertaleSprite sprite)
}
}
- AddProgressP(sprite.Textures.Count);
+ AddProgressParallel(sprite.Textures.Count);
}
void DumpFont(UndertaleFont font)
@@ -78,7 +78,7 @@ void DumpFont(UndertaleFont font)
UndertaleTexturePageItem tex = font.Texture;
worker.ExportAsPNG(tex, Path.Combine(fntFolder, font.Name.Content + "_0.png"));
- IncProgressP();
+ IncrementProgressParallel();
}
}
@@ -89,7 +89,7 @@ void DumpBackground(UndertaleBackground background)
UndertaleTexturePageItem tex = background.Texture;
worker.ExportAsPNG(tex, Path.Combine(bgrFolder, background.Name.Content + "_0.png"));
- IncProgressP();
+ IncrementProgressParallel();
}
}
diff --git a/UndertaleModTool/Unpackers/ExportAllTexturesGrouped.csx b/UndertaleModTool/Unpackers/ExportAllTexturesGrouped.csx
index 8e22dd9d5..f7ebdf570 100644
--- a/UndertaleModTool/Unpackers/ExportAllTexturesGrouped.csx
+++ b/UndertaleModTool/Unpackers/ExportAllTexturesGrouped.csx
@@ -30,14 +30,14 @@ Directory.CreateDirectory(bgrFolder);
TextureWorker worker = new TextureWorker();
SetProgressBar(null, "Textures Exported", 0, Data.TexturePageItems.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpSprites();
await DumpFonts();
await DumpBackgrounds();
worker.Cleanup();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + texFolder);
@@ -69,7 +69,7 @@ void DumpSprite(UndertaleSprite sprite)
}
}
- AddProgressP(sprite.Textures.Count);
+ AddProgressParallel(sprite.Textures.Count);
}
void DumpFont(UndertaleFont font)
@@ -80,7 +80,7 @@ void DumpFont(UndertaleFont font)
string fntFolder2 = Path.Combine(fntFolder, font.Name.Content);
Directory.CreateDirectory(fntFolder2);
worker.ExportAsPNG(tex, Path.Combine(fntFolder2, font.Name.Content + "_0.png"));
- IncProgressP();
+ IncrementProgressParallel();
}
}
@@ -92,7 +92,7 @@ void DumpBackground(UndertaleBackground background)
string bgrFolder2 = Path.Combine(bgrFolder, background.Name.Content);
Directory.CreateDirectory(bgrFolder2);
worker.ExportAsPNG(tex, Path.Combine(bgrFolder2, background.Name.Content + "_0.png"));
- IncProgressP();
+ IncrementProgressParallel();
}
}
diff --git a/UndertaleModTool/Unpackers/ExportAllTilesets.csx b/UndertaleModTool/Unpackers/ExportAllTilesets.csx
index f7849ccc2..1eab5498e 100644
--- a/UndertaleModTool/Unpackers/ExportAllTilesets.csx
+++ b/UndertaleModTool/Unpackers/ExportAllTilesets.csx
@@ -18,17 +18,17 @@ if (Directory.Exists(texFolder))
Directory.CreateDirectory(texFolder);
SetProgressBar(null, "Tilesets", 0, Data.Backgrounds.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpTilesets();
worker.Cleanup();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + texFolder);
-string GetFolder(string path)
+string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}
@@ -39,10 +39,10 @@ async Task DumpTilesets()
await Task.Run(() => Parallel.ForEach(Data.Backgrounds, DumpTileset));
}
-void DumpTileset(UndertaleBackground tileset)
+void DumpTileset(UndertaleBackground tileset)
{
if (tileset.Texture != null)
worker.ExportAsPNG(tileset.Texture, texFolder + tileset.Name.Content + ".png");
- IncProgressP();
+ IncrementProgressParallel();
}
\ No newline at end of file
diff --git a/UndertaleModTool/Unpackers/ExportFontData.csx b/UndertaleModTool/Unpackers/ExportFontData.csx
index 484cbdbbd..4dfc5f7e0 100644
--- a/UndertaleModTool/Unpackers/ExportFontData.csx
+++ b/UndertaleModTool/Unpackers/ExportFontData.csx
@@ -21,12 +21,12 @@ if (ShowInputDialog() == System.Windows.Forms.DialogResult.Cancel)
string[] arrayString = input.ToArray();
SetProgressBar(null, "Fonts", 0, Data.Fonts.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpFonts();
worker.Cleanup();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + fntFolder);
@@ -57,7 +57,7 @@ void DumpFont(UndertaleFont font)
}
}
- IncProgressP();
+ IncrementProgressParallel();
}
private DialogResult ShowInputDialog()
diff --git a/UndertaleModTool/Unpackers/ExportMasks.csx b/UndertaleModTool/Unpackers/ExportMasks.csx
index 499c0e317..58b7911ca 100644
--- a/UndertaleModTool/Unpackers/ExportMasks.csx
+++ b/UndertaleModTool/Unpackers/ExportMasks.csx
@@ -22,17 +22,17 @@ if (Directory.Exists(texFolder))
Directory.CreateDirectory(texFolder);
SetProgressBar(null, "Sprites", 0, Data.Sprites.Count);
-StartUpdater();
+StartProgressBarUpdater();
await DumpSprites();
worker.Cleanup();
-await StopUpdater();
+await StopProgressBarUpdater();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + texFolder);
-string GetFolder(string path)
+string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}
@@ -52,5 +52,5 @@ void DumpSprite(UndertaleSprite sprite)
}
}
- IncProgressP();
+ IncrementProgressParallel();
}
From d91f694931b36b767eef0376881feb7780bfb873 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Sun, 27 Mar 2022 21:34:00 +0200
Subject: [PATCH 10/18] Fix some todo documentation
---
.../Models/UndertaleAnimationCurve.cs | 2 +
UndertaleModLib/Models/UndertaleBackground.cs | 22 ++++-
.../Models/UndertaleEmbeddedTexture.cs | 8 ++
UndertaleModLib/Models/UndertaleFont.cs | 26 +++++-
UndertaleModLib/Models/UndertaleGameObject.cs | 91 +++++++++++++++++--
UndertaleModLib/Models/UndertaleRoom.cs | 4 +-
UndertaleModLib/Scripting/IScriptInterface.cs | 8 +-
UndertaleModLib/UndertaleData.cs | 30 ++++--
8 files changed, 168 insertions(+), 23 deletions(-)
diff --git a/UndertaleModLib/Models/UndertaleAnimationCurve.cs b/UndertaleModLib/Models/UndertaleAnimationCurve.cs
index 63028484c..55a61de53 100644
--- a/UndertaleModLib/Models/UndertaleAnimationCurve.cs
+++ b/UndertaleModLib/Models/UndertaleAnimationCurve.cs
@@ -28,6 +28,8 @@ public enum GraphTypeEnum : uint
/// The graph type of this animation curve.
///
public GraphTypeEnum GraphType { get; set; }
+
+
public UndertaleSimpleList Channels { get; set; }
public void Serialize(UndertaleWriter writer)
diff --git a/UndertaleModLib/Models/UndertaleBackground.cs b/UndertaleModLib/Models/UndertaleBackground.cs
index df05051c4..02a3eb6ad 100644
--- a/UndertaleModLib/Models/UndertaleBackground.cs
+++ b/UndertaleModLib/Models/UndertaleBackground.cs
@@ -67,6 +67,9 @@ public void Unserialize(UndertaleReader reader)
public UndertaleTexturePageItem Texture { get; set; }
+ ///
+ /// TODO: Functionality currently unknown.
+ ///
public uint GMS2UnknownAlways2 { get; set; } = 2;
///
@@ -89,12 +92,25 @@ public void Unserialize(UndertaleReader reader)
///
public uint GMS2OutputBorderY { get; set; } = 2;
- //TODO: no idea
+ ///
+ /// The amount of columns this tileset has.
+ ///
public uint GMS2TileColumns { get; set; } = 32;
+
+ ///
+ /// The number of frames of the tileset animation.
+ ///
public uint GMS2ItemsPerTileCount { get; set; } = 1;
+
+ ///
+ /// The amount of tiles this tileset has.
+ ///
public uint GMS2TileCount { get; set; } = 1024;
- public uint GMS2UnknownAlwaysZero { get; set; } = 0;
+ ///
+ /// TODO: Functionality currently unknown.
+ ///
+ public uint GMS2UnknownAlwaysZero { get; set; } = 0;
///
/// The time for each frame in microseconds.
@@ -102,7 +118,7 @@ public void Unserialize(UndertaleReader reader)
public long GMS2FrameLength { get; set; } = 66666;
///
- /// All tile id of this tileset. Game Maker Studio 2 only.
+ /// All tile ids of this tileset. Game Maker Studio 2 only.
///
public List GMS2TileIds { get; set; } = new List();
diff --git a/UndertaleModLib/Models/UndertaleEmbeddedTexture.cs b/UndertaleModLib/Models/UndertaleEmbeddedTexture.cs
index 3378e7f85..cd55cff22 100644
--- a/UndertaleModLib/Models/UndertaleEmbeddedTexture.cs
+++ b/UndertaleModLib/Models/UndertaleEmbeddedTexture.cs
@@ -54,6 +54,10 @@ public void Unserialize(UndertaleReader reader)
TextureData = reader.ReadUndertaleObjectPointer();
}
+ ///
+ /// TODO!
+ ///
+ /// Where to serialize to.
public void SerializeBlob(UndertaleWriter writer)
{
// padding
@@ -63,6 +67,10 @@ public void SerializeBlob(UndertaleWriter writer)
writer.WriteUndertaleObject(TextureData);
}
+ ///
+ /// TODO!
+ ///
+ /// Where to deserialize from.
public void UnserializeBlob(UndertaleReader reader)
{
while (reader.Position % 0x80 != 0)
diff --git a/UndertaleModLib/Models/UndertaleFont.cs b/UndertaleModLib/Models/UndertaleFont.cs
index 7e9db0978..036e07374 100644
--- a/UndertaleModLib/Models/UndertaleFont.cs
+++ b/UndertaleModLib/Models/UndertaleFont.cs
@@ -29,7 +29,7 @@ public class UndertaleFont : UndertaleNamedResource
public bool EmSizeIsFloat { get; set; }
///
- /// The font size in Ems
+ /// The font size in Ems. In Game Maker: Studio 2.3 and above, this is a float instead.
///
public uint EmSize { get; set; }
@@ -43,12 +43,26 @@ public class UndertaleFont : UndertaleNamedResource
///
public bool Italic { get; set; }
-
+ ///
+ /// The start of the character range for this font.
+ ///
public ushort RangeStart { get; set; }
+
+ ///
+ /// TODO: Currently unknown value.
+ ///
public byte Charset { get; set; }
+
+ ///
+ /// The level of anti-aliasing that is applied. 0 for none, Game Maker: Studio 2 has 1 for on, while
+ /// Game Maker Studio: 1 and earlier have values 1-3 for different anti-aliasing levels.
+ ///
public byte AntiAliasing { get; set; }
- public uint RangeEnd { get; set; }
+ ///
+ /// The end of the character range for this font.
+ ///
+ public uint RangeEnd { get; set; }
///
/// The object that contains the texture for this font.
@@ -70,7 +84,9 @@ public class UndertaleFont : UndertaleNamedResource
///
public UndertalePointerList Glyphs { get; private set; } = new UndertalePointerList();
-
+ ///
+ /// TODO: currently unknown, needs investigation. Exists since bytecode 17, but seems to be only get checked since 2022.2+.
+ ///
public int AscenderOffset { get; set; }
@@ -106,8 +122,10 @@ public class Glyph : UndertaleObject
public ushort SourceHeight { get; set; }
+ //TODO: From here on out is some kerning related stuff I don't know.
public short Shift { get; set; }
public short Offset { get; set; }
+
public UndertaleSimpleListShort Kerning { get; set; } = new UndertaleSimpleListShort();
public void Serialize(UndertaleWriter writer)
diff --git a/UndertaleModLib/Models/UndertaleGameObject.cs b/UndertaleModLib/Models/UndertaleGameObject.cs
index 13152c38e..f9f983a2e 100644
--- a/UndertaleModLib/Models/UndertaleGameObject.cs
+++ b/UndertaleModLib/Models/UndertaleGameObject.cs
@@ -568,7 +568,9 @@ public enum EventType : uint
/// A key released event type. The subtype is the key id, see .
///
KeyRelease = 10,
- //TODO
+ ///
+ /// A trigger event type. Only used in Pre- Game Maker: Studio.
+ ///
Trigger = 11, // no subtypes, always 0
///
/// A cleanup event type. Has no subtypes, always 0.
@@ -1076,30 +1078,101 @@ public enum EventSubtypeMouse : uint
/// The mouse leave event.
///
MouseLeave = 11,
- //TODO: are these even used?
+ ///
+ /// The Joystick1 left event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Left = 16,
+ ///
+ /// The Joystick1 right event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Right = 17,
+ ///
+ /// The Joystick1 up event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Up = 18,
+ ///
+ /// The Joystick1 down event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Down = 19,
+ ///
+ /// The Joystick1 button1 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Button1 = 21,
+ ///
+ /// The Joystick1 button2 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Button2 = 22,
+ ///
+ /// The Joystick1 button3 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Button3 = 23,
+ ///
+ /// The Joystick1 button4 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Button4 = 24,
+ ///
+ /// The Joystick1 button5 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Button5 = 25,
+ ///
+ /// The Joystick1 button6 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Button6 = 26,
+ ///
+ /// The Joystick1 button7 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Button7 = 27,
+ ///
+ /// The Joystick1 button8 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick1Button8 = 28,
+ ///
+ /// The Joystick2 left event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Left = 31,
+ ///
+ /// The Joystick2 right event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Right = 32,
+ ///
+ /// The Joystick2 up event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Up = 33,
+ ///
+ /// The Joystick2 down event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Down = 34,
+ ///
+ /// The Joystick2 button1 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Button1 = 36,
+ ///
+ /// The Joystick2 button2 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Button2 = 37,
+ ///
+ /// The Joystick2 button3 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Button3 = 38,
+ ///
+ /// The Joystick2 button4 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Button4 = 39,
+ ///
+ /// The Joystick2 button5 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Button5 = 40,
+ ///
+ /// The Joystick2 button6 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Button6 = 41,
+ ///
+ /// The Joystick2 button7 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Button7 = 42,
+ ///
+ /// The Joystick2 button8 event. Is only used in Pre-Game Maker: Studio.
+ ///
Joystick2Button8 = 43,
///
/// The global left-mouse button down event.
@@ -1176,8 +1249,9 @@ public enum EventSubtypeOther : uint
/// The room end event.
///
RoomEnd = 5,
-
- //TODO: are the ones here used?
+ ///
+ /// THe "No More Lives" event. Only used in Game Maker Studio: 1 and earlier.
+ ///
NoMoreLives = 6,
///
/// The animation end event.
@@ -1187,9 +1261,11 @@ public enum EventSubtypeOther : uint
/// The path ended event.
///
EndOfPath = 8,
-
+ ///
+ /// The "No More Health" event. Only used in Game Maker Studio: 1 and earlier.
+ ///
NoMoreHealth = 9,
-
+ #region User events
///
/// The User 0 event.
///
@@ -1258,6 +1334,8 @@ public enum EventSubtypeOther : uint
/// The User 16 event.
///
User16 = 26,
+ #endregion
+ #region View events
///
/// The Outside View 0 event.
///
@@ -1322,6 +1400,7 @@ public enum EventSubtypeOther : uint
/// The Intersect View 7 Boundary event.
///
BoundaryView7 = 57,
+ #endregion
///
/// The animation Update event for Skeletal Animation functions.
///
diff --git a/UndertaleModLib/Models/UndertaleRoom.cs b/UndertaleModLib/Models/UndertaleRoom.cs
index d677f9059..bd648362e 100644
--- a/UndertaleModLib/Models/UndertaleRoom.cs
+++ b/UndertaleModLib/Models/UndertaleRoom.cs
@@ -28,7 +28,7 @@ public enum RoomEntryFlags : uint
///
EnableViews = 1,
///
- /// TODO no idea.
+ /// TODO not exactly sure, probably similar to ?
///
ShowColor = 2,
///
@@ -67,8 +67,8 @@ public enum RoomEntryFlags : uint
///
/// The speed of the current room in steps.
+ /// TODO: GMS1 only? IIRC gms2 deals with it differently.
///
- //TODO: GMS1 only? IIRC gms2 deals with it differently.
public uint Speed { get; set; } = 30;
///
diff --git a/UndertaleModLib/Scripting/IScriptInterface.cs b/UndertaleModLib/Scripting/IScriptInterface.cs
index 256564dbc..a72d4f902 100644
--- a/UndertaleModLib/Scripting/IScriptInterface.cs
+++ b/UndertaleModLib/Scripting/IScriptInterface.cs
@@ -111,7 +111,11 @@ void EnsureDataLoaded()
/// The message to show.
void ScriptMessage(string message);
- //TODO: currently mostly used with GUI
+ //TODO: currently should get repurposed/renamed?
+ ///
+ /// Sets the message of the variable holding text from the console. Currently only used in GUI.
+ ///
+ /// The message to set it to.
void SetUMTConsoleText(string message);
///
@@ -126,7 +130,7 @@ void EnsureDataLoaded()
///
/// The error message to show.
/// A short-descriptive title.
- /// TODO
+ /// Whether to call with .
void ScriptError(string error, string title = "Error", bool SetConsoleText = true);
///
diff --git a/UndertaleModLib/UndertaleData.cs b/UndertaleModLib/UndertaleData.cs
index 0d7e8d208..190a2c3b4 100644
--- a/UndertaleModLib/UndertaleData.cs
+++ b/UndertaleModLib/UndertaleData.cs
@@ -184,15 +184,27 @@ public object this[Type resourceType]
public IList Variables => FORM.VARI?.List;
///
- /// TODO: no idea what these are.
+ /// TODO: Unknown value, need more research.
///
public uint VarCount1 { get => FORM.VARI.VarCount1; set => FORM.VARI.VarCount1 = value; }
+
+ ///
+ /// TODO: Unknown value, need more research.
+ ///
public uint VarCount2 { get => FORM.VARI.VarCount2; set => FORM.VARI.VarCount2 = value; }
+
+ ///
+ /// TODO: Unknown value, need more research.
+ ///
public bool DifferentVarCounts { get => FORM.VARI.DifferentVarCounts; set => FORM.VARI.DifferentVarCounts = value; }
[Obsolete]
public uint InstanceVarCount { get => VarCount1; set => VarCount1 = value; }
[Obsolete]
public uint InstanceVarCountAgain { get => VarCount2; set => VarCount2 = value; }
+
+ ///
+ /// TODO: Unknown value, need more research.
+ ///
public uint MaxLocalVarCount { get => FORM.VARI.MaxLocalVarCount; set => FORM.VARI.MaxLocalVarCount = value; }
///
@@ -221,7 +233,9 @@ public object this[Type resourceType]
///
public IList EmbeddedTextures => FORM.TXTR?.List;
- //TODO: no idea what this is. Seems to sometimes not exist?
+ ///
+ /// The texture group infos of the data file.
+ ///
public IList TextureGroupInfo => FORM.TGIN?.List;
///
@@ -229,7 +243,6 @@ public object this[Type resourceType]
///
public IList EmbeddedAudio => FORM.AUDO?.List;
- //TODO?
public UndertaleTags Tags => FORM.TAGS?.Object;
///
@@ -292,7 +305,6 @@ public object this[Type resourceType]
///
public bool GMS2022_1 = false;
-
///
/// Some info for the editor to store data on.
///
@@ -472,7 +484,10 @@ public bool IsVersionAtLeast(uint major, uint minor, uint release, uint build)
return true; // The version is exactly what supplied.
}
- //TODO: I have no idea what this does.
+ ///
+ /// TODO: needs to be documented on what this does.
+ ///
+ /// TODO
public int GetBuiltinSoundGroupID()
{
// It is known it works this way in 1.0.1266. The exact version which changed this is unknown.
@@ -489,7 +504,10 @@ public bool IsYYC()
return GeneralInfo != null && Code == null;
}
- //TODO: This is a helper method for something I don't really understand.
+ ///
+ /// TODO: Undocumented helper method.
+ ///
+ /// TODO
public uint ExtensionFindLastId()
{
// The reason:
From 1668187e5db50178f68510b3e7ca55ce09c1e9e3 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Mon, 28 Mar 2022 11:23:01 +0200
Subject: [PATCH 11/18] Fix AUMI Doc
---
UndertaleModLib/AumiIPC.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/UndertaleModLib/AumiIPC.cs b/UndertaleModLib/AumiIPC.cs
index 9a5ccc6b9..0cff656f3 100644
--- a/UndertaleModLib/AumiIPC.cs
+++ b/UndertaleModLib/AumiIPC.cs
@@ -37,7 +37,7 @@ public struct IpcMessage_t
/// Execute Code - Executes precompiled bytecode in the global context.
///
///
- ///
+ ///
public short FuncID;
///
From 6cf1cf3ff8564c470e0d3c6d9bac4343efeae683 Mon Sep 17 00:00:00 2001
From: Miepee <38186597+Miepee@users.noreply.github.com>
Date: Mon, 28 Mar 2022 11:41:02 +0200
Subject: [PATCH 12/18] Fix scripts not running because of
RemovePromptChooseDirectory
---
.../Repackers/ApplyBasicGraphicsMod.csx | 292 ++--
.../Repackers/CopySpriteBgFont.csx | 968 ++++++------
.../Repackers/CopySpriteBgFontInternal.csx | 844 +++++-----
UndertaleModTool/Repackers/ImportASM.csx | 104 +-
UndertaleModTool/Repackers/ImportASM_2_3.csx | 508 +++---
.../Repackers/ImportAllStrings.csx | 198 +--
.../Repackers/ImportAllTilesets.csx | 124 +-
UndertaleModTool/Repackers/ImportFontData.csx | 912 +++++------
UndertaleModTool/Repackers/ImportGML.csx | 90 +-
UndertaleModTool/Repackers/ImportGML_2_3.csx | 528 +++----
UndertaleModTool/Repackers/ImportGraphics.csx | 1240 +++++++--------
UndertaleModTool/Repackers/ImportMasks.csx | 238 +--
.../Repackers/ImportShaderData.csx | 611 +++----
.../Repackers/ImportSoundsBulk.csx | 640 ++++----
.../Repackers/ReduceEmbeddedTexturePages.csx | 1090 ++++++-------
.../TechnicalScripts/ExportAllCode2_3.csx | 158 +-
.../TechnicalScripts/ExportAllCodeSync.csx | 166 +-
.../ExportAndConvert_2_3_ASM.csx | 326 ++--
.../TechnicalScripts/FindUnknownFunctions.csx | 240 +--
.../TechnicalScripts/FindUnusedStrings.csx | 1292 +++++++--------
.../ImportGraphics_Full_Repack.csx | 1400 ++++++++---------
.../Unpackers/DumpSpecificCode.csx | 304 ++--
UndertaleModTool/Unpackers/ExportASM.csx | 104 +-
UndertaleModTool/Unpackers/ExportAllCode.csx | 210 +--
.../Unpackers/ExportAllEmbeddedTextures.csx | 138 +-
.../Unpackers/ExportAllRoomsToPng.csx | 210 +--
.../Unpackers/ExportAllSounds.csx | 414 ++---
.../Unpackers/ExportAllSprites.csx | 100 +-
.../Unpackers/ExportAllStrings.csx | 74 +-
.../Unpackers/ExportAllTextures.csx | 198 +--
.../Unpackers/ExportAllTexturesGrouped.csx | 204 +--
.../Unpackers/ExportAllTilesets.csx | 94 +-
UndertaleModTool/Unpackers/ExportFontData.csx | 272 ++--
UndertaleModTool/Unpackers/ExportMasks.csx | 112 +-
.../Unpackers/ExportShaderData.csx | 106 +-
UndertaleModTool/Unpackers/MergeImages.csx | 120 +-
36 files changed, 7315 insertions(+), 7314 deletions(-)
diff --git a/UndertaleModTool/Repackers/ApplyBasicGraphicsMod.csx b/UndertaleModTool/Repackers/ApplyBasicGraphicsMod.csx
index f0f43cace..f5d314c95 100644
--- a/UndertaleModTool/Repackers/ApplyBasicGraphicsMod.csx
+++ b/UndertaleModTool/Repackers/ApplyBasicGraphicsMod.csx
@@ -1,147 +1,147 @@
-using System;
-using System.IO;
-using System.Drawing;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using UndertaleModLib.Util;
-
-EnsureDataLoaded();
-
-// At this point, this just imports the sprites.
-string importFolder = PromptChooseDirectory("Import From Where");
-if (importFolder == null)
- throw new ScriptException("The import folder was not set.");
-
-string[] dirFiles = Directory.GetFiles(importFolder);
-
-//Stop the script if there's missing sprite entries or w/e.
-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 ScriptException("Getting the sprite name of " + FileNameWithExtension + " failed.");
- }
- if (Data.Sprites.ByName(spriteName) == null) // Reject non-existing sprites
- {
- throw new ScriptException(FileNameWithExtension + " could not be imported as the sprite " + spriteName + " does not exist.");
- }
- using (Image img = Image.FromFile(file))
- {
- if ((Data.Sprites.ByName(spriteName).Width != (uint)img.Width) || (Data.Sprites.ByName(spriteName).Height != (uint)img.Height))
- throw new ScriptException(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 ScriptException("The index of " + FileNameWithExtension + " could not be determined.");
- }
- int frame = 0;
- try
- {
- frame = Int32.Parse(stripped.Substring(lastUnderscore + 1));
- }
- catch
- {
- throw new ScriptException(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 ScriptException(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 ScriptException(spriteName + " is missing one or more indexes. The detected missing index is: " + prevFrameName);
-}
-
-SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartProgressBarUpdater();
-
-await Task.Run(() => {
- foreach (string file in dirFiles)
- {
- IncrementProgress();
-
- string fileName = Path.GetFileName(file);
- if (!fileName.EndsWith(".png") || !fileName.Contains("_"))
- continue; // Not an image.
-
- 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);
-
- if (frame < sprite.Textures.Count)
- {
- try
- {
- Bitmap bmp;
- using (var ms = new MemoryStream(TextureWorker.ReadTextureBlob(file)))
- {
- bmp = new Bitmap(ms);
- }
- bmp.SetResolution(96.0F, 96.0F);
- var width = (uint)bmp.Width;
- var height = (uint)bmp.Height;
- var CheckWidth = (uint)(sprite.Textures[frame].Texture.TargetWidth);
- var CheckHeight = (uint)(sprite.Textures[frame].Texture.TargetHeight);
- if ((width != CheckWidth) || (height != CheckHeight))
- {
- string error = "Incorrect dimensions of " + stripped + ". Sprite blurring is very likely in game. Aborting!";
- ScriptError(error, "Unexpected texture dimensions");
- SetUMTConsoleText(error);
- SetFinishedMessage(false);
- return;
- }
- sprite.Textures[frame].Texture.ReplaceTexture(bmp);
- }
- catch
- {
- string error = file + " encountered an unknown error during import. Contact the Underminers discord with as much information as possible, the file, and this error message. Aborting!";
- ScriptError(error, "Sprite Error");
- SetUMTConsoleText(error);
- SetFinishedMessage(false);
- return;
- }
- }
- else
- {
- string error = fileName + ": Index out of range. Index " + frame.ToString() + " exceeds maximum index (" + ((sprite.Textures.Count) - 1).ToString() + ") of " + spriteName + ". Aborting!";
- ScriptError(error, "Sprite Error");
- SetUMTConsoleText(error);
- SetFinishedMessage(false);
- return;
- }
- }
-});
-
-await StopProgressBarUpdater();
-HideProgressBar();
+using System;
+using System.IO;
+using System.Drawing;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using UndertaleModLib.Util;
+
+EnsureDataLoaded();
+
+// At this point, this just imports the sprites.
+string importFolder = PromptChooseDirectory();
+if (importFolder == null)
+ throw new ScriptException("The import folder was not set.");
+
+string[] dirFiles = Directory.GetFiles(importFolder);
+
+//Stop the script if there's missing sprite entries or w/e.
+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 ScriptException("Getting the sprite name of " + FileNameWithExtension + " failed.");
+ }
+ if (Data.Sprites.ByName(spriteName) == null) // Reject non-existing sprites
+ {
+ throw new ScriptException(FileNameWithExtension + " could not be imported as the sprite " + spriteName + " does not exist.");
+ }
+ using (Image img = Image.FromFile(file))
+ {
+ if ((Data.Sprites.ByName(spriteName).Width != (uint)img.Width) || (Data.Sprites.ByName(spriteName).Height != (uint)img.Height))
+ throw new ScriptException(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 ScriptException("The index of " + FileNameWithExtension + " could not be determined.");
+ }
+ int frame = 0;
+ try
+ {
+ frame = Int32.Parse(stripped.Substring(lastUnderscore + 1));
+ }
+ catch
+ {
+ throw new ScriptException(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 ScriptException(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 ScriptException(spriteName + " is missing one or more indexes. The detected missing index is: " + prevFrameName);
+}
+
+SetProgressBar(null, "Files", 0, dirFiles.Length);
+StartProgressBarUpdater();
+
+await Task.Run(() => {
+ foreach (string file in dirFiles)
+ {
+ IncrementProgress();
+
+ string fileName = Path.GetFileName(file);
+ if (!fileName.EndsWith(".png") || !fileName.Contains("_"))
+ continue; // Not an image.
+
+ 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);
+
+ if (frame < sprite.Textures.Count)
+ {
+ try
+ {
+ Bitmap bmp;
+ using (var ms = new MemoryStream(TextureWorker.ReadTextureBlob(file)))
+ {
+ bmp = new Bitmap(ms);
+ }
+ bmp.SetResolution(96.0F, 96.0F);
+ var width = (uint)bmp.Width;
+ var height = (uint)bmp.Height;
+ var CheckWidth = (uint)(sprite.Textures[frame].Texture.TargetWidth);
+ var CheckHeight = (uint)(sprite.Textures[frame].Texture.TargetHeight);
+ if ((width != CheckWidth) || (height != CheckHeight))
+ {
+ string error = "Incorrect dimensions of " + stripped + ". Sprite blurring is very likely in game. Aborting!";
+ ScriptError(error, "Unexpected texture dimensions");
+ SetUMTConsoleText(error);
+ SetFinishedMessage(false);
+ return;
+ }
+ sprite.Textures[frame].Texture.ReplaceTexture(bmp);
+ }
+ catch
+ {
+ string error = file + " encountered an unknown error during import. Contact the Underminers discord with as much information as possible, the file, and this error message. Aborting!";
+ ScriptError(error, "Sprite Error");
+ SetUMTConsoleText(error);
+ SetFinishedMessage(false);
+ return;
+ }
+ }
+ else
+ {
+ string error = fileName + ": Index out of range. Index " + frame.ToString() + " exceeds maximum index (" + ((sprite.Textures.Count) - 1).ToString() + ") of " + spriteName + ". Aborting!";
+ ScriptError(error, "Sprite Error");
+ SetUMTConsoleText(error);
+ SetFinishedMessage(false);
+ return;
+ }
+ }
+});
+
+await StopProgressBarUpdater();
+HideProgressBar();
ScriptMessage("Import Complete!");
\ No newline at end of file
diff --git a/UndertaleModTool/Repackers/CopySpriteBgFont.csx b/UndertaleModTool/Repackers/CopySpriteBgFont.csx
index 609443808..cc539de4c 100644
--- a/UndertaleModTool/Repackers/CopySpriteBgFont.csx
+++ b/UndertaleModTool/Repackers/CopySpriteBgFont.csx
@@ -1,484 +1,484 @@
-//Adapted from original script by Grossley
-using System.Text;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using UndertaleModLib.Util;
-
-EnsureDataLoaded();
-
-// Initialization Start
-
-var DataEmbeddedTexturesCount = Data.EmbeddedTextures.Count;
-List tex_TargetX = new List();
-List tex_TargetY = new List();
-List tex_SourceX = new List();
-List tex_SourceY = new List();
-List tex_SourceWidth = new List();
-List tex_SourceHeight = new List();
-List tex_TargetWidth = new List();
-List tex_TargetHeight = new List();
-List tex_BoundingWidth = new List();
-List tex_BoundingHeight = new List();
-List tex_Frame = new List();
-List tex_EmbeddedTextureID = new List();
-List tex_Name = new List();
-List tex_Type = new List();
-List tex_IsNull = new List();
-List TexturePageItemsUsed = new List();
-
-// Initialization End
-
-ScriptMessage("Select the file to copy from");
-
-UndertaleData DonorData;
-string DonorDataPath = PromptLoadFile(null, null);
-if (DonorDataPath == null)
- throw new ScriptException("The donor data path was not set.");
-
-using (var stream = new FileStream(DonorDataPath, FileMode.Open, FileAccess.Read))
- DonorData = UndertaleIO.Read(stream, warning => ScriptMessage("A warning occured while trying to load " + DonorDataPath + ":\n" + warning));
-var DonorDataEmbeddedTexturesCount = DonorData.EmbeddedTextures.Count;
-int copiedSpritesCount = 0;
-int copiedBackgroundsCount = 0;
-int copiedFontsCount = 0;
-int copiedAssetsCount = 0;
-List splitStringsList = GetSplitStringsList("sprite(s)/background(s)/font");
-bool[] SpriteSheetsCopyNeeded = new bool[DonorDataEmbeddedTexturesCount];
-bool[] SpriteSheetsUsed = new bool[(DataEmbeddedTexturesCount + DonorDataEmbeddedTexturesCount)];
-
-int lastTextPage = Data.EmbeddedTextures.Count - 1;
-
-SetProgressBar(null, "Textures Exported", 0, DonorData.TexturePageItems.Count);
-StartProgressBarUpdater();
-
-SyncBinding("EmbeddedTextures, Strings, Backgrounds, Sprites, Fonts, TexturePageItems", true);
-await Task.Run(() => {
- for (int i = 0; i < SpriteSheetsCopyNeeded.Length; i++)
- {
- SpriteSheetsCopyNeeded[i] = false;
- }
- for (int i = 0; i < SpriteSheetsUsed.Length; i++)
- {
- SpriteSheetsUsed[i] = false;
- }
- for (var i = 0; i < DonorDataEmbeddedTexturesCount; i++)
- {
- UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
- texture.Name = new UndertaleString("Texture " + ++lastTextPage);
- texture.TextureData.TextureBlob = DonorData.EmbeddedTextures[i].TextureData.TextureBlob;
- Data.EmbeddedTextures.Add(texture);
- }
- for (var j = 0; j < splitStringsList.Count; j++)
- {
- foreach (UndertaleBackground bg in DonorData.Backgrounds)
- {
- if (splitStringsList[j].ToLower() == bg.Name.Content.ToLower())
- {
- UndertaleBackground nativeBG = Data.Backgrounds.ByName(bg.Name.Content);
- UndertaleBackground donorBG = DonorData.Backgrounds.ByName(bg.Name.Content);
- if (nativeBG == null)
- {
- nativeBG = new UndertaleBackground();
- nativeBG.Name = Data.Strings.MakeString(bg.Name.Content);
- Data.Backgrounds.Add(nativeBG);
- }
- nativeBG.Transparent = donorBG.Transparent;
- nativeBG.Smooth = donorBG.Smooth;
- nativeBG.Preload = donorBG.Preload;
- nativeBG.GMS2UnknownAlways2 = donorBG.GMS2UnknownAlways2;
- nativeBG.GMS2TileWidth = donorBG.GMS2TileWidth;
- nativeBG.GMS2TileHeight = donorBG.GMS2TileHeight;
- nativeBG.GMS2OutputBorderX = donorBG.GMS2OutputBorderX;
- nativeBG.GMS2OutputBorderY = donorBG.GMS2OutputBorderY;
- nativeBG.GMS2TileColumns = donorBG.GMS2TileColumns;
- nativeBG.GMS2ItemsPerTileCount = donorBG.GMS2ItemsPerTileCount;
- nativeBG.GMS2TileCount = donorBG.GMS2TileCount;
- nativeBG.GMS2UnknownAlwaysZero = donorBG.GMS2UnknownAlwaysZero;
- nativeBG.GMS2FrameLength = donorBG.GMS2FrameLength;
- nativeBG.GMS2TileIds = donorBG.GMS2TileIds;
- DumpBackground(donorBG);
- copiedBackgroundsCount += 1;
- }
- }
- foreach (UndertaleSprite sprite in DonorData.Sprites)
- {
- if (splitStringsList[j].ToLower() == sprite.Name.Content.ToLower())
- {
- UndertaleSprite nativeSPR = Data.Sprites.ByName(sprite.Name.Content);
- UndertaleSprite donorSPR = DonorData.Sprites.ByName(sprite.Name.Content);
- if (nativeSPR != null)
- {
- nativeSPR.CollisionMasks.Clear();
- }
- else
- {
- nativeSPR = new UndertaleSprite();
- nativeSPR.Name = Data.Strings.MakeString(sprite.Name.Content);
- Data.Sprites.Add(nativeSPR);
- }
- for (var i = 0; i < donorSPR.CollisionMasks.Count; i++)
- nativeSPR.CollisionMasks.Add(new UndertaleSprite.MaskEntry(donorSPR.CollisionMasks[i].Data));
- nativeSPR.Width = donorSPR.Width;
- nativeSPR.Height = donorSPR.Height;
- nativeSPR.MarginLeft = donorSPR.MarginLeft;
- nativeSPR.MarginRight = donorSPR.MarginRight;
- nativeSPR.MarginBottom = donorSPR.MarginBottom;
- nativeSPR.MarginTop = donorSPR.MarginTop;
- nativeSPR.Transparent = donorSPR.Transparent;
- nativeSPR.Smooth = donorSPR.Smooth;
- nativeSPR.Preload = donorSPR.Preload;
- nativeSPR.BBoxMode = donorSPR.BBoxMode;
- nativeSPR.OriginX = donorSPR.OriginX;
- nativeSPR.OriginY = donorSPR.OriginY;
-
- // Special sprite types (always used in GMS2)
- nativeSPR.SVersion = donorSPR.SVersion;
- nativeSPR.GMS2PlaybackSpeed = donorSPR.GMS2PlaybackSpeed;
- nativeSPR.IsSpecialType = donorSPR.IsSpecialType;
- nativeSPR.SpineVersion = donorSPR.SpineVersion;
- nativeSPR.SpineJSON = donorSPR.SpineJSON;
- nativeSPR.SpineAtlas = donorSPR.SpineAtlas;
- nativeSPR.SWFVersion = donorSPR.SWFVersion;
-
- //Possibly will break
- nativeSPR.SepMasks = donorSPR.SepMasks;
- nativeSPR.SSpriteType = donorSPR.SSpriteType;
- nativeSPR.GMS2PlaybackSpeedType = donorSPR.GMS2PlaybackSpeedType;
- nativeSPR.SpineTextures = donorSPR.SpineTextures;
- nativeSPR.YYSWF = donorSPR.YYSWF;
- nativeSPR.V2Sequence = donorSPR.V2Sequence;
- nativeSPR.V3NineSlice = donorSPR.V3NineSlice;
-
- DumpSprite(donorSPR);
- copiedSpritesCount += 1;
- }
- }
- foreach (UndertaleFont fnt in DonorData.Fonts)
- {
- if (splitStringsList[j].ToLower() == fnt.Name.Content.ToLower())
- {
- UndertaleFont nativeFNT = Data.Fonts.ByName(fnt.Name.Content);
- UndertaleFont donorFNT = DonorData.Fonts.ByName(fnt.Name.Content);
- if (nativeFNT == null)
- {
- nativeFNT = new UndertaleFont();
- nativeFNT.Name = Data.Strings.MakeString(fnt.Name.Content);
- Data.Fonts.Add(nativeFNT);
- }
- nativeFNT.Glyphs.Clear();
- nativeFNT.RangeStart = donorFNT.RangeStart;
- nativeFNT.DisplayName = Data.Strings.MakeString(donorFNT.DisplayName.Content);
- nativeFNT.EmSize = donorFNT.EmSize;
- nativeFNT.Bold = donorFNT.Bold;
- nativeFNT.Italic = donorFNT.Italic;
- nativeFNT.Charset = donorFNT.Charset;
- nativeFNT.AntiAliasing = donorFNT.AntiAliasing;
- nativeFNT.ScaleX = donorFNT.ScaleX;
- nativeFNT.ScaleY = donorFNT.ScaleY;
- foreach (UndertaleFont.Glyph glyph in donorFNT.Glyphs)
- {
- UndertaleFont.Glyph glyph_new = new UndertaleFont.Glyph();
- glyph_new.Character = glyph.Character;
- glyph_new.SourceX = glyph.SourceX;
- glyph_new.SourceY = glyph.SourceY;
- glyph_new.SourceWidth = glyph.SourceWidth;
- glyph_new.SourceHeight = glyph.SourceHeight;
- glyph_new.Shift = glyph.Shift;
- glyph_new.Offset = glyph.Offset;
- nativeFNT.Glyphs.Add(glyph_new);
- }
- nativeFNT.RangeEnd = donorFNT.RangeEnd;
- DumpFont(donorFNT);
- copiedFontsCount += 1;
- }
- }
- }
- for (var i = 0; i < tex_IsNull.Count; i++)
- {
- if (tex_IsNull[i] == false)
- {
- UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
- texturePageItem.TargetX = (ushort)tex_TargetX[i];
- texturePageItem.TargetY = (ushort)tex_TargetY[i];
- texturePageItem.TargetWidth = (ushort)tex_TargetWidth[i];
- texturePageItem.TargetHeight = (ushort)tex_TargetHeight[i];
- texturePageItem.SourceX = (ushort)tex_SourceX[i];
- texturePageItem.SourceY = (ushort)tex_SourceY[i];
- texturePageItem.SourceWidth = (ushort)tex_SourceWidth[i];
- texturePageItem.SourceHeight = (ushort)tex_SourceHeight[i];
- texturePageItem.BoundingWidth = (ushort)tex_BoundingWidth[i];
- texturePageItem.BoundingHeight = (ushort)tex_BoundingHeight[i];
- texturePageItem.TexturePage = Data.EmbeddedTextures[(DataEmbeddedTexturesCount + tex_EmbeddedTextureID[i])];
- Data.TexturePageItems.Add(texturePageItem);
- texturePageItem.Name = new UndertaleString("PageItem " + Data.TexturePageItems.IndexOf(texturePageItem).ToString());
- if (tex_Type[i].Equals("bg"))
- {
- UndertaleBackground background = Data.Backgrounds.ByName(tex_Name[i]);
- background.Texture = texturePageItem;
- }
- else if (tex_Type[i].Equals("fnt"))
- {
- UndertaleFont font = Data.Fonts.ByName(tex_Name[i]);
- font.Texture = texturePageItem;
- }
- else
- {
- int frame = tex_Frame[i];
- UndertaleSprite sprite = Data.Sprites.ByName(tex_Name[i]);
- UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
- texentry.Texture = texturePageItem;
- if (frame > sprite.Textures.Count - 1)
- {
- while (frame > sprite.Textures.Count - 1)
- {
- sprite.Textures.Add(texentry);
- }
- }
- else
- {
- sprite.Textures[frame] = texentry;
- }
- }
- }
- else
- {
- if (tex_Type[i] == "spr")
- {
- UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
- texentry.Texture = null;
- Data.Sprites.ByName(tex_Name[i]).Textures.Add(texentry);
- }
- if (tex_Type[i] == "bg")
- {
- Data.Backgrounds.ByName(tex_Name[i]).Texture = null;
- }
- if (tex_Type[i] == "fnt")
- {
- Data.Fonts.ByName(tex_Name[i]).Texture = null;
- }
- }
- }
- SpriteSheetsUsedUpdate();
- RemoveUnusedSpriteSheets();
- TexturePageItemsUsedUpdate();
- RemoveUnusedTexturePageItems();
-});
-DisableAllSyncBindings();
-
-await StopProgressBarUpdater();
-HideProgressBar();
-copiedAssetsCount = (copiedFontsCount + copiedBackgroundsCount + copiedSpritesCount);
-ScriptMessage(copiedAssetsCount.ToString() + " assets were copied (" + copiedSpritesCount.ToString() + " Sprites, " + copiedBackgroundsCount.ToString() + " Backgrounds, and " + copiedFontsCount.ToString() + " Fonts)");
-
-
-
-
-// Functions
-
-void RemoveUnusedTexturePageItems()
-{
- for (int i = (TexturePageItemsUsed.Count - 1); i > -1; i--)
- {
- if (TexturePageItemsUsed[i] == false)
- {
- Data.TexturePageItems.Remove(Data.TexturePageItems[i]);
- }
- }
- foreach (UndertaleTexturePageItem texture in Data.TexturePageItems)
- {
- texture.Name = new UndertaleString("PageItem " + Data.TexturePageItems.IndexOf(texture).ToString());
- }
-}
-void RemoveUnusedSpriteSheets()
-{
- for (int i = (SpriteSheetsUsed.Length - 1); i > -1; i--)
- {
- if (SpriteSheetsUsed[i] == false)
- {
- Data.EmbeddedTextures.Remove(Data.EmbeddedTextures[i]);
- }
- }
- foreach (UndertaleEmbeddedTexture texture in Data.EmbeddedTextures)
- {
- texture.Name = new UndertaleString("Texture " + Data.EmbeddedTextures.IndexOf(texture).ToString());
- }
-}
-void DumpSprite(UndertaleSprite sprite)
-{
- for (int i = 0; i < sprite.Textures.Count; i++)
- {
- if (sprite.Textures[i]?.Texture != null)
- NotNullHandler(sprite.Textures[i].Texture);
- else
- NullHandler();
- tex_Frame.Add(i);
- tex_Name.Add(sprite.Name.Content);
- tex_Type.Add("spr");
- }
-
- AddProgress(sprite.Textures.Count);
-}
-void DumpFont(UndertaleFont font)
-{
- if (font.Texture != null)
- NotNullHandler(font.Texture);
- else
- NullHandler();
- tex_Frame.Add(0);
- tex_Name.Add(font.Name.Content);
- tex_Type.Add("fnt");
-
- IncrementProgress();
-}
-void DumpBackground(UndertaleBackground background)
-{
- if (background.Texture != null)
- NotNullHandler(background.Texture);
- else
- NullHandler();
- tex_Frame.Add(0);
- tex_Name.Add(background.Name.Content);
- tex_Type.Add("bg");
-
- IncrementProgress();
-}
-void NullHandler()
-{
- tex_TargetX.Add(-16000);
- tex_TargetY.Add(-16000);
- tex_SourceWidth.Add(-16000);
- tex_SourceHeight.Add(-16000);
- tex_SourceX.Add(-16000);
- tex_SourceY.Add(-16000);
- tex_TargetWidth.Add(-16000);
- tex_TargetHeight.Add(-16000);
- tex_BoundingWidth.Add(-16000);
- tex_BoundingHeight.Add(-16000);
- tex_EmbeddedTextureID.Add(-16000);
- tex_IsNull.Add(true);
-}
-void NotNullHandler(UndertaleTexturePageItem tex)
-{
- tex_TargetX.Add(tex.TargetX);
- tex_TargetY.Add(tex.TargetY);
- tex_SourceWidth.Add(tex.SourceWidth);
- tex_SourceHeight.Add(tex.SourceHeight);
- tex_SourceX.Add(tex.SourceX);
- tex_SourceY.Add(tex.SourceY);
- tex_TargetWidth.Add(tex.TargetWidth);
- tex_TargetHeight.Add(tex.TargetHeight);
- tex_BoundingWidth.Add(tex.BoundingWidth);
- tex_BoundingHeight.Add(tex.BoundingHeight);
- tex_EmbeddedTextureID.Add(DonorData.EmbeddedTextures.IndexOf(tex.TexturePage));
- tex_IsNull.Add(false);
-}
-void TexturePageItemsUsedUpdate()
-{
- foreach (UndertaleTexturePageItem texture in Data.TexturePageItems)
- {
- TexturePageItemsUsed.Add(false);
- }
- foreach(UndertaleSprite sprite in Data.Sprites)
- {
- for (int i = 0; i < sprite.Textures.Count; i++)
- {
- if (sprite.Textures[i]?.Texture != null)
- {
- TexturePageItemsUsed[Data.TexturePageItems.IndexOf(sprite.Textures[i]?.Texture)] = true;
- }
- }
- }
- foreach (UndertaleBackground bg in Data.Backgrounds)
- {
- if (bg.Texture != null)
- {
- TexturePageItemsUsed[Data.TexturePageItems.IndexOf(bg.Texture)] = true;
- }
- }
- foreach (UndertaleFont fnt in Data.Fonts)
- {
- if (fnt.Texture != null)
- {
- TexturePageItemsUsed[Data.TexturePageItems.IndexOf(fnt.Texture)] = true;
- }
- }
-}
-void SpriteSheetsUsedUpdate()
-{
- foreach(UndertaleSprite sprite in Data.Sprites)
- {
- for (int i = 0; i < sprite.Textures.Count; i++)
- {
- if (sprite.Textures[i]?.Texture != null)
- {
- SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(sprite.Textures[i]?.Texture.TexturePage)] = true;
- }
- }
- }
- foreach (UndertaleBackground bg in Data.Backgrounds)
- {
- if (bg.Texture != null)
- {
- SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(bg.Texture.TexturePage)] = true;
- }
- }
- foreach (UndertaleFont fnt in Data.Fonts)
- {
- if (fnt.Texture != null)
- {
- SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(fnt.Texture.TexturePage)] = true;
- }
- }
-}
-//Unused
-/*
-void UpdateSpriteSheetsCopyNeeded()
-{
- for (var j = 0; j < sprCandidates.Count; j++)
- {
- UndertaleSprite sprite = Data.Sprites.ByName(sprCandidates[j]);
- for (int i = 0; i < sprite.Textures.Count; i++)
- {
- if (sprite.Textures[i]?.Texture != null)
- {
- SpriteSheetsCopyNeeded[Data.EmbeddedTextures.IndexOf(sprite.Textures[i]?.Texture.TexturePage)] = true;
- }
- }
- UpdateProgress();
- }
- for (var j = 0; j < bgCandidates.Count; j++)
- {
- UndertaleBackground bg = Data.Backgrounds.ByName(bgCandidates[j]);
- if (bg.Texture != null)
- {
- SpriteSheetsCopyNeeded[Data.EmbeddedTextures.IndexOf(bg.Texture.TexturePage)] = true;
- }
- UpdateProgress();
- }
- for (var j = 0; j < fntCandidates.Count; j++)
- {
- UndertaleFont fnt = Data.Fonts.ByName(fntCandidates[j]);
- if (fnt.Texture != null)
- {
- SpriteSheetsCopyNeeded[Data.EmbeddedTextures.IndexOf(fnt.Texture.TexturePage)] = true;
- }
- UpdateProgress();
- }
-}
-*/
-
-List GetSplitStringsList(string assetType)
-{
- ScriptMessage("Enter the " + assetType + "(s) to copy");
- List splitStringsList = new List();
- string InputtedText = "";
- InputtedText = SimpleTextInput("Menu", "Enter the name(s) of the " + assetType + "(s)", InputtedText, true);
- string[] IndividualLineArray = InputtedText.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
- foreach (var OneLine in IndividualLineArray)
- {
- splitStringsList.Add(OneLine.Trim());
- }
- return splitStringsList;
-}
+//Adapted from original script by Grossley
+using System.Text;
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using UndertaleModLib.Util;
+
+EnsureDataLoaded();
+
+// Initialization Start
+
+var DataEmbeddedTexturesCount = Data.EmbeddedTextures.Count;
+List tex_TargetX = new List();
+List tex_TargetY = new List();
+List tex_SourceX = new List();
+List tex_SourceY = new List();
+List tex_SourceWidth = new List();
+List tex_SourceHeight = new List();
+List tex_TargetWidth = new List();
+List tex_TargetHeight = new List();
+List tex_BoundingWidth = new List();
+List tex_BoundingHeight = new List();
+List tex_Frame = new List();
+List tex_EmbeddedTextureID = new List();
+List tex_Name = new List();
+List tex_Type = new List();
+List tex_IsNull = new List();
+List TexturePageItemsUsed = new List();
+
+// Initialization End
+
+ScriptMessage("Select the file to copy from");
+
+UndertaleData DonorData;
+string DonorDataPath = PromptLoadFile(null, null);
+if (DonorDataPath == null)
+ throw new ScriptException("The donor data path was not set.");
+
+using (var stream = new FileStream(DonorDataPath, FileMode.Open, FileAccess.Read))
+ DonorData = UndertaleIO.Read(stream, warning => ScriptMessage("A warning occured while trying to load " + DonorDataPath + ":\n" + warning));
+var DonorDataEmbeddedTexturesCount = DonorData.EmbeddedTextures.Count;
+int copiedSpritesCount = 0;
+int copiedBackgroundsCount = 0;
+int copiedFontsCount = 0;
+int copiedAssetsCount = 0;
+List splitStringsList = GetSplitStringsList("sprite(s)/background(s)/font");
+bool[] SpriteSheetsCopyNeeded = new bool[DonorDataEmbeddedTexturesCount];
+bool[] SpriteSheetsUsed = new bool[(DataEmbeddedTexturesCount + DonorDataEmbeddedTexturesCount)];
+
+int lastTextPage = Data.EmbeddedTextures.Count - 1;
+
+SetProgressBar(null, "Textures Exported", 0, DonorData.TexturePageItems.Count);
+StartProgressBarUpdater();
+
+SyncBinding("EmbeddedTextures, Strings, Backgrounds, Sprites, Fonts, TexturePageItems", true);
+await Task.Run(() => {
+ for (int i = 0; i < SpriteSheetsCopyNeeded.Length; i++)
+ {
+ SpriteSheetsCopyNeeded[i] = false;
+ }
+ for (int i = 0; i < SpriteSheetsUsed.Length; i++)
+ {
+ SpriteSheetsUsed[i] = false;
+ }
+ for (var i = 0; i < DonorDataEmbeddedTexturesCount; i++)
+ {
+ UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
+ texture.Name = new UndertaleString("Texture " + ++lastTextPage);
+ texture.TextureData.TextureBlob = DonorData.EmbeddedTextures[i].TextureData.TextureBlob;
+ Data.EmbeddedTextures.Add(texture);
+ }
+ for (var j = 0; j < splitStringsList.Count; j++)
+ {
+ foreach (UndertaleBackground bg in DonorData.Backgrounds)
+ {
+ if (splitStringsList[j].ToLower() == bg.Name.Content.ToLower())
+ {
+ UndertaleBackground nativeBG = Data.Backgrounds.ByName(bg.Name.Content);
+ UndertaleBackground donorBG = DonorData.Backgrounds.ByName(bg.Name.Content);
+ if (nativeBG == null)
+ {
+ nativeBG = new UndertaleBackground();
+ nativeBG.Name = Data.Strings.MakeString(bg.Name.Content);
+ Data.Backgrounds.Add(nativeBG);
+ }
+ nativeBG.Transparent = donorBG.Transparent;
+ nativeBG.Smooth = donorBG.Smooth;
+ nativeBG.Preload = donorBG.Preload;
+ nativeBG.GMS2UnknownAlways2 = donorBG.GMS2UnknownAlways2;
+ nativeBG.GMS2TileWidth = donorBG.GMS2TileWidth;
+ nativeBG.GMS2TileHeight = donorBG.GMS2TileHeight;
+ nativeBG.GMS2OutputBorderX = donorBG.GMS2OutputBorderX;
+ nativeBG.GMS2OutputBorderY = donorBG.GMS2OutputBorderY;
+ nativeBG.GMS2TileColumns = donorBG.GMS2TileColumns;
+ nativeBG.GMS2ItemsPerTileCount = donorBG.GMS2ItemsPerTileCount;
+ nativeBG.GMS2TileCount = donorBG.GMS2TileCount;
+ nativeBG.GMS2UnknownAlwaysZero = donorBG.GMS2UnknownAlwaysZero;
+ nativeBG.GMS2FrameLength = donorBG.GMS2FrameLength;
+ nativeBG.GMS2TileIds = donorBG.GMS2TileIds;
+ DumpBackground(donorBG);
+ copiedBackgroundsCount += 1;
+ }
+ }
+ foreach (UndertaleSprite sprite in DonorData.Sprites)
+ {
+ if (splitStringsList[j].ToLower() == sprite.Name.Content.ToLower())
+ {
+ UndertaleSprite nativeSPR = Data.Sprites.ByName(sprite.Name.Content);
+ UndertaleSprite donorSPR = DonorData.Sprites.ByName(sprite.Name.Content);
+ if (nativeSPR != null)
+ {
+ nativeSPR.CollisionMasks.Clear();
+ }
+ else
+ {
+ nativeSPR = new UndertaleSprite();
+ nativeSPR.Name = Data.Strings.MakeString(sprite.Name.Content);
+ Data.Sprites.Add(nativeSPR);
+ }
+ for (var i = 0; i < donorSPR.CollisionMasks.Count; i++)
+ nativeSPR.CollisionMasks.Add(new UndertaleSprite.MaskEntry(donorSPR.CollisionMasks[i].Data));
+ nativeSPR.Width = donorSPR.Width;
+ nativeSPR.Height = donorSPR.Height;
+ nativeSPR.MarginLeft = donorSPR.MarginLeft;
+ nativeSPR.MarginRight = donorSPR.MarginRight;
+ nativeSPR.MarginBottom = donorSPR.MarginBottom;
+ nativeSPR.MarginTop = donorSPR.MarginTop;
+ nativeSPR.Transparent = donorSPR.Transparent;
+ nativeSPR.Smooth = donorSPR.Smooth;
+ nativeSPR.Preload = donorSPR.Preload;
+ nativeSPR.BBoxMode = donorSPR.BBoxMode;
+ nativeSPR.OriginX = donorSPR.OriginX;
+ nativeSPR.OriginY = donorSPR.OriginY;
+
+ // Special sprite types (always used in GMS2)
+ nativeSPR.SVersion = donorSPR.SVersion;
+ nativeSPR.GMS2PlaybackSpeed = donorSPR.GMS2PlaybackSpeed;
+ nativeSPR.IsSpecialType = donorSPR.IsSpecialType;
+ nativeSPR.SpineVersion = donorSPR.SpineVersion;
+ nativeSPR.SpineJSON = donorSPR.SpineJSON;
+ nativeSPR.SpineAtlas = donorSPR.SpineAtlas;
+ nativeSPR.SWFVersion = donorSPR.SWFVersion;
+
+ //Possibly will break
+ nativeSPR.SepMasks = donorSPR.SepMasks;
+ nativeSPR.SSpriteType = donorSPR.SSpriteType;
+ nativeSPR.GMS2PlaybackSpeedType = donorSPR.GMS2PlaybackSpeedType;
+ nativeSPR.SpineTextures = donorSPR.SpineTextures;
+ nativeSPR.YYSWF = donorSPR.YYSWF;
+ nativeSPR.V2Sequence = donorSPR.V2Sequence;
+ nativeSPR.V3NineSlice = donorSPR.V3NineSlice;
+
+ DumpSprite(donorSPR);
+ copiedSpritesCount += 1;
+ }
+ }
+ foreach (UndertaleFont fnt in DonorData.Fonts)
+ {
+ if (splitStringsList[j].ToLower() == fnt.Name.Content.ToLower())
+ {
+ UndertaleFont nativeFNT = Data.Fonts.ByName(fnt.Name.Content);
+ UndertaleFont donorFNT = DonorData.Fonts.ByName(fnt.Name.Content);
+ if (nativeFNT == null)
+ {
+ nativeFNT = new UndertaleFont();
+ nativeFNT.Name = Data.Strings.MakeString(fnt.Name.Content);
+ Data.Fonts.Add(nativeFNT);
+ }
+ nativeFNT.Glyphs.Clear();
+ nativeFNT.RangeStart = donorFNT.RangeStart;
+ nativeFNT.DisplayName = Data.Strings.MakeString(donorFNT.DisplayName.Content);
+ nativeFNT.EmSize = donorFNT.EmSize;
+ nativeFNT.Bold = donorFNT.Bold;
+ nativeFNT.Italic = donorFNT.Italic;
+ nativeFNT.Charset = donorFNT.Charset;
+ nativeFNT.AntiAliasing = donorFNT.AntiAliasing;
+ nativeFNT.ScaleX = donorFNT.ScaleX;
+ nativeFNT.ScaleY = donorFNT.ScaleY;
+ foreach (UndertaleFont.Glyph glyph in donorFNT.Glyphs)
+ {
+ UndertaleFont.Glyph glyph_new = new UndertaleFont.Glyph();
+ glyph_new.Character = glyph.Character;
+ glyph_new.SourceX = glyph.SourceX;
+ glyph_new.SourceY = glyph.SourceY;
+ glyph_new.SourceWidth = glyph.SourceWidth;
+ glyph_new.SourceHeight = glyph.SourceHeight;
+ glyph_new.Shift = glyph.Shift;
+ glyph_new.Offset = glyph.Offset;
+ nativeFNT.Glyphs.Add(glyph_new);
+ }
+ nativeFNT.RangeEnd = donorFNT.RangeEnd;
+ DumpFont(donorFNT);
+ copiedFontsCount += 1;
+ }
+ }
+ }
+ for (var i = 0; i < tex_IsNull.Count; i++)
+ {
+ if (tex_IsNull[i] == false)
+ {
+ UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
+ texturePageItem.TargetX = (ushort)tex_TargetX[i];
+ texturePageItem.TargetY = (ushort)tex_TargetY[i];
+ texturePageItem.TargetWidth = (ushort)tex_TargetWidth[i];
+ texturePageItem.TargetHeight = (ushort)tex_TargetHeight[i];
+ texturePageItem.SourceX = (ushort)tex_SourceX[i];
+ texturePageItem.SourceY = (ushort)tex_SourceY[i];
+ texturePageItem.SourceWidth = (ushort)tex_SourceWidth[i];
+ texturePageItem.SourceHeight = (ushort)tex_SourceHeight[i];
+ texturePageItem.BoundingWidth = (ushort)tex_BoundingWidth[i];
+ texturePageItem.BoundingHeight = (ushort)tex_BoundingHeight[i];
+ texturePageItem.TexturePage = Data.EmbeddedTextures[(DataEmbeddedTexturesCount + tex_EmbeddedTextureID[i])];
+ Data.TexturePageItems.Add(texturePageItem);
+ texturePageItem.Name = new UndertaleString("PageItem " + Data.TexturePageItems.IndexOf(texturePageItem).ToString());
+ if (tex_Type[i].Equals("bg"))
+ {
+ UndertaleBackground background = Data.Backgrounds.ByName(tex_Name[i]);
+ background.Texture = texturePageItem;
+ }
+ else if (tex_Type[i].Equals("fnt"))
+ {
+ UndertaleFont font = Data.Fonts.ByName(tex_Name[i]);
+ font.Texture = texturePageItem;
+ }
+ else
+ {
+ int frame = tex_Frame[i];
+ UndertaleSprite sprite = Data.Sprites.ByName(tex_Name[i]);
+ UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
+ texentry.Texture = texturePageItem;
+ if (frame > sprite.Textures.Count - 1)
+ {
+ while (frame > sprite.Textures.Count - 1)
+ {
+ sprite.Textures.Add(texentry);
+ }
+ }
+ else
+ {
+ sprite.Textures[frame] = texentry;
+ }
+ }
+ }
+ else
+ {
+ if (tex_Type[i] == "spr")
+ {
+ UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
+ texentry.Texture = null;
+ Data.Sprites.ByName(tex_Name[i]).Textures.Add(texentry);
+ }
+ if (tex_Type[i] == "bg")
+ {
+ Data.Backgrounds.ByName(tex_Name[i]).Texture = null;
+ }
+ if (tex_Type[i] == "fnt")
+ {
+ Data.Fonts.ByName(tex_Name[i]).Texture = null;
+ }
+ }
+ }
+ SpriteSheetsUsedUpdate();
+ RemoveUnusedSpriteSheets();
+ TexturePageItemsUsedUpdate();
+ RemoveUnusedTexturePageItems();
+});
+DisableAllSyncBindings();
+
+await StopProgressBarUpdater();
+HideProgressBar();
+copiedAssetsCount = (copiedFontsCount + copiedBackgroundsCount + copiedSpritesCount);
+ScriptMessage(copiedAssetsCount.ToString() + " assets were copied (" + copiedSpritesCount.ToString() + " Sprites, " + copiedBackgroundsCount.ToString() + " Backgrounds, and " + copiedFontsCount.ToString() + " Fonts)");
+
+
+
+
+// Functions
+
+void RemoveUnusedTexturePageItems()
+{
+ for (int i = (TexturePageItemsUsed.Count - 1); i > -1; i--)
+ {
+ if (TexturePageItemsUsed[i] == false)
+ {
+ Data.TexturePageItems.Remove(Data.TexturePageItems[i]);
+ }
+ }
+ foreach (UndertaleTexturePageItem texture in Data.TexturePageItems)
+ {
+ texture.Name = new UndertaleString("PageItem " + Data.TexturePageItems.IndexOf(texture).ToString());
+ }
+}
+void RemoveUnusedSpriteSheets()
+{
+ for (int i = (SpriteSheetsUsed.Length - 1); i > -1; i--)
+ {
+ if (SpriteSheetsUsed[i] == false)
+ {
+ Data.EmbeddedTextures.Remove(Data.EmbeddedTextures[i]);
+ }
+ }
+ foreach (UndertaleEmbeddedTexture texture in Data.EmbeddedTextures)
+ {
+ texture.Name = new UndertaleString("Texture " + Data.EmbeddedTextures.IndexOf(texture).ToString());
+ }
+}
+void DumpSprite(UndertaleSprite sprite)
+{
+ for (int i = 0; i < sprite.Textures.Count; i++)
+ {
+ if (sprite.Textures[i]?.Texture != null)
+ NotNullHandler(sprite.Textures[i].Texture);
+ else
+ NullHandler();
+ tex_Frame.Add(i);
+ tex_Name.Add(sprite.Name.Content);
+ tex_Type.Add("spr");
+ }
+
+ AddProgress(sprite.Textures.Count);
+}
+void DumpFont(UndertaleFont font)
+{
+ if (font.Texture != null)
+ NotNullHandler(font.Texture);
+ else
+ NullHandler();
+ tex_Frame.Add(0);
+ tex_Name.Add(font.Name.Content);
+ tex_Type.Add("fnt");
+
+ IncrementProgress();
+}
+void DumpBackground(UndertaleBackground background)
+{
+ if (background.Texture != null)
+ NotNullHandler(background.Texture);
+ else
+ NullHandler();
+ tex_Frame.Add(0);
+ tex_Name.Add(background.Name.Content);
+ tex_Type.Add("bg");
+
+ IncrementProgress();
+}
+void NullHandler()
+{
+ tex_TargetX.Add(-16000);
+ tex_TargetY.Add(-16000);
+ tex_SourceWidth.Add(-16000);
+ tex_SourceHeight.Add(-16000);
+ tex_SourceX.Add(-16000);
+ tex_SourceY.Add(-16000);
+ tex_TargetWidth.Add(-16000);
+ tex_TargetHeight.Add(-16000);
+ tex_BoundingWidth.Add(-16000);
+ tex_BoundingHeight.Add(-16000);
+ tex_EmbeddedTextureID.Add(-16000);
+ tex_IsNull.Add(true);
+}
+void NotNullHandler(UndertaleTexturePageItem tex)
+{
+ tex_TargetX.Add(tex.TargetX);
+ tex_TargetY.Add(tex.TargetY);
+ tex_SourceWidth.Add(tex.SourceWidth);
+ tex_SourceHeight.Add(tex.SourceHeight);
+ tex_SourceX.Add(tex.SourceX);
+ tex_SourceY.Add(tex.SourceY);
+ tex_TargetWidth.Add(tex.TargetWidth);
+ tex_TargetHeight.Add(tex.TargetHeight);
+ tex_BoundingWidth.Add(tex.BoundingWidth);
+ tex_BoundingHeight.Add(tex.BoundingHeight);
+ tex_EmbeddedTextureID.Add(DonorData.EmbeddedTextures.IndexOf(tex.TexturePage));
+ tex_IsNull.Add(false);
+}
+void TexturePageItemsUsedUpdate()
+{
+ foreach (UndertaleTexturePageItem texture in Data.TexturePageItems)
+ {
+ TexturePageItemsUsed.Add(false);
+ }
+ foreach(UndertaleSprite sprite in Data.Sprites)
+ {
+ for (int i = 0; i < sprite.Textures.Count; i++)
+ {
+ if (sprite.Textures[i]?.Texture != null)
+ {
+ TexturePageItemsUsed[Data.TexturePageItems.IndexOf(sprite.Textures[i]?.Texture)] = true;
+ }
+ }
+ }
+ foreach (UndertaleBackground bg in Data.Backgrounds)
+ {
+ if (bg.Texture != null)
+ {
+ TexturePageItemsUsed[Data.TexturePageItems.IndexOf(bg.Texture)] = true;
+ }
+ }
+ foreach (UndertaleFont fnt in Data.Fonts)
+ {
+ if (fnt.Texture != null)
+ {
+ TexturePageItemsUsed[Data.TexturePageItems.IndexOf(fnt.Texture)] = true;
+ }
+ }
+}
+void SpriteSheetsUsedUpdate()
+{
+ foreach(UndertaleSprite sprite in Data.Sprites)
+ {
+ for (int i = 0; i < sprite.Textures.Count; i++)
+ {
+ if (sprite.Textures[i]?.Texture != null)
+ {
+ SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(sprite.Textures[i]?.Texture.TexturePage)] = true;
+ }
+ }
+ }
+ foreach (UndertaleBackground bg in Data.Backgrounds)
+ {
+ if (bg.Texture != null)
+ {
+ SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(bg.Texture.TexturePage)] = true;
+ }
+ }
+ foreach (UndertaleFont fnt in Data.Fonts)
+ {
+ if (fnt.Texture != null)
+ {
+ SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(fnt.Texture.TexturePage)] = true;
+ }
+ }
+}
+//Unused
+/*
+void UpdateSpriteSheetsCopyNeeded()
+{
+ for (var j = 0; j < sprCandidates.Count; j++)
+ {
+ UndertaleSprite sprite = Data.Sprites.ByName(sprCandidates[j]);
+ for (int i = 0; i < sprite.Textures.Count; i++)
+ {
+ if (sprite.Textures[i]?.Texture != null)
+ {
+ SpriteSheetsCopyNeeded[Data.EmbeddedTextures.IndexOf(sprite.Textures[i]?.Texture.TexturePage)] = true;
+ }
+ }
+ UpdateProgress();
+ }
+ for (var j = 0; j < bgCandidates.Count; j++)
+ {
+ UndertaleBackground bg = Data.Backgrounds.ByName(bgCandidates[j]);
+ if (bg.Texture != null)
+ {
+ SpriteSheetsCopyNeeded[Data.EmbeddedTextures.IndexOf(bg.Texture.TexturePage)] = true;
+ }
+ UpdateProgress();
+ }
+ for (var j = 0; j < fntCandidates.Count; j++)
+ {
+ UndertaleFont fnt = Data.Fonts.ByName(fntCandidates[j]);
+ if (fnt.Texture != null)
+ {
+ SpriteSheetsCopyNeeded[Data.EmbeddedTextures.IndexOf(fnt.Texture.TexturePage)] = true;
+ }
+ UpdateProgress();
+ }
+}
+*/
+
+List GetSplitStringsList(string assetType)
+{
+ ScriptMessage("Enter the " + assetType + "(s) to copy");
+ List splitStringsList = new List();
+ string InputtedText = "";
+ InputtedText = SimpleTextInput("Menu", "Enter the name(s) of the " + assetType + "(s)", InputtedText, true);
+ string[] IndividualLineArray = InputtedText.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var OneLine in IndividualLineArray)
+ {
+ splitStringsList.Add(OneLine.Trim());
+ }
+ return splitStringsList;
+}
diff --git a/UndertaleModTool/Repackers/CopySpriteBgFontInternal.csx b/UndertaleModTool/Repackers/CopySpriteBgFontInternal.csx
index c22c7400b..cfa937952 100644
--- a/UndertaleModTool/Repackers/CopySpriteBgFontInternal.csx
+++ b/UndertaleModTool/Repackers/CopySpriteBgFontInternal.csx
@@ -1,422 +1,422 @@
-//Adapted from original script by Grossley
-using System.Text;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using UndertaleModLib.Util;
-
-EnsureDataLoaded();
-
-// Initialization Start
-
-var DataEmbeddedTexturesCount = Data.EmbeddedTextures.Count;
-List tex_TargetX = new List();
-List tex_TargetY = new List();
-List tex_SourceX = new List();
-List tex_SourceY = new List();
-List tex_SourceWidth = new List();
-List tex_SourceHeight = new List();
-List tex_TargetWidth = new List();
-List tex_TargetHeight = new List();
-List tex_BoundingWidth = new List();
-List tex_BoundingHeight = new List();
-List tex_Frame = new List();
-List tex_EmbeddedTextureID = new List();
-List tex_Name = new List();
-List tex_Type = new List();
-List tex_IsNull = new List();
-List TexturePageItemsUsed = new List();
-
-// Initialization End
-
-int copiedSpritesCount = 0;
-int copiedBackgroundsCount = 0;
-int copiedFontsCount = 0;
-int copiedAssetsCount = 0;
-List splitStringsList = GetSplitStringsList("sprite(s)/background(s)/font");
-bool[] SpriteSheetsCopyNeeded = new bool[DataEmbeddedTexturesCount];
-bool[] SpriteSheetsUsed = new bool[(DataEmbeddedTexturesCount + DataEmbeddedTexturesCount)];
-
-int lastTextPage = Data.EmbeddedTextures.Count - 1;
-
-SetProgressBar(null, "Textures Exported", 0, Data.TexturePageItems.Count);
-StartProgressBarUpdater();
-
-SyncBinding("EmbeddedTextures, Strings, Backgrounds, Sprites, Fonts, TexturePageItems", true);
-await Task.Run(() => {
- for (int i = 0; i < SpriteSheetsCopyNeeded.Length; i++)
- {
- SpriteSheetsCopyNeeded[i] = false;
- }
- for (int i = 0; i < SpriteSheetsUsed.Length; i++)
- {
- SpriteSheetsUsed[i] = false;
- }
- for (var i = 0; i < DataEmbeddedTexturesCount; i++)
- {
- UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
- texture.Name = new UndertaleString("Texture " + ++lastTextPage);
- texture.TextureData.TextureBlob = Data.EmbeddedTextures[i].TextureData.TextureBlob;
- Data.EmbeddedTextures.Add(texture);
- }
- for (var j = 0; j < splitStringsList.Count; j++)
- {
- int DataBackgroundsLength = Data.Backgrounds.Count;
- for (var i = 0; i < DataBackgroundsLength; i++)
- {
- UndertaleBackground bg = Data.Backgrounds[i];
- if (splitStringsList[j].ToLower() == bg.Name.Content.ToLower())
- {
- UndertaleBackground donorBG = Data.Backgrounds.ByName(bg.Name.Content);
- UndertaleBackground nativeBG = new UndertaleBackground();
- nativeBG.Name = Data.Strings.MakeString(bg.Name.Content + "_Copy");
- Data.Backgrounds.Add(nativeBG);
- nativeBG.Transparent = donorBG.Transparent;
- nativeBG.Smooth = donorBG.Smooth;
- nativeBG.Preload = donorBG.Preload;
- nativeBG.GMS2UnknownAlways2 = donorBG.GMS2UnknownAlways2;
- nativeBG.GMS2TileWidth = donorBG.GMS2TileWidth;
- nativeBG.GMS2TileHeight = donorBG.GMS2TileHeight;
- nativeBG.GMS2OutputBorderX = donorBG.GMS2OutputBorderX;
- nativeBG.GMS2OutputBorderY = donorBG.GMS2OutputBorderY;
- nativeBG.GMS2TileColumns = donorBG.GMS2TileColumns;
- nativeBG.GMS2ItemsPerTileCount = donorBG.GMS2ItemsPerTileCount;
- nativeBG.GMS2TileCount = donorBG.GMS2TileCount;
- nativeBG.GMS2UnknownAlwaysZero = donorBG.GMS2UnknownAlwaysZero;
- nativeBG.GMS2FrameLength = donorBG.GMS2FrameLength;
- nativeBG.GMS2TileIds = donorBG.GMS2TileIds;
- DumpBackground(donorBG);
- copiedBackgroundsCount += 1;
- }
- }
- int DataSpritesLength = Data.Sprites.Count;
- for (var k = 0; k < DataSpritesLength; k++)
- {
- UndertaleSprite sprite = Data.Sprites[k];
- if (splitStringsList[j].ToLower() == sprite.Name.Content.ToLower())
- {
- UndertaleSprite donorSPR = Data.Sprites.ByName(sprite.Name.Content);
- UndertaleSprite nativeSPR = new UndertaleSprite();
- nativeSPR.Name = Data.Strings.MakeString(sprite.Name.Content + "_Copy");
- Data.Sprites.Add(nativeSPR);
- for (var i = 0; i < donorSPR.CollisionMasks.Count; i++)
- nativeSPR.CollisionMasks.Add(new UndertaleSprite.MaskEntry(donorSPR.CollisionMasks[i].Data));
- nativeSPR.Width = donorSPR.Width;
- nativeSPR.Height = donorSPR.Height;
- nativeSPR.MarginLeft = donorSPR.MarginLeft;
- nativeSPR.MarginRight = donorSPR.MarginRight;
- nativeSPR.MarginBottom = donorSPR.MarginBottom;
- nativeSPR.MarginTop = donorSPR.MarginTop;
- nativeSPR.Transparent = donorSPR.Transparent;
- nativeSPR.Smooth = donorSPR.Smooth;
- nativeSPR.Preload = donorSPR.Preload;
- nativeSPR.BBoxMode = donorSPR.BBoxMode;
- nativeSPR.OriginX = donorSPR.OriginX;
- nativeSPR.OriginY = donorSPR.OriginY;
-
- // Special sprite types (always used in GMS2)
- nativeSPR.SVersion = donorSPR.SVersion;
- nativeSPR.GMS2PlaybackSpeed = donorSPR.GMS2PlaybackSpeed;
- nativeSPR.IsSpecialType = donorSPR.IsSpecialType;
- nativeSPR.SpineVersion = donorSPR.SpineVersion;
- nativeSPR.SpineJSON = donorSPR.SpineJSON;
- nativeSPR.SpineAtlas = donorSPR.SpineAtlas;
- nativeSPR.SWFVersion = donorSPR.SWFVersion;
-
- //Possibly will break
- nativeSPR.SepMasks = donorSPR.SepMasks;
- nativeSPR.SSpriteType = donorSPR.SSpriteType;
- nativeSPR.GMS2PlaybackSpeedType = donorSPR.GMS2PlaybackSpeedType;
- nativeSPR.SpineTextures = donorSPR.SpineTextures;
- nativeSPR.YYSWF = donorSPR.YYSWF;
- nativeSPR.V2Sequence = donorSPR.V2Sequence;
- nativeSPR.V3NineSlice = donorSPR.V3NineSlice;
-
- DumpSprite(donorSPR);
- copiedSpritesCount += 1;
- }
- }
- int DataFontsLength = Data.Fonts.Count;
- for (var i = 0; i < DataFontsLength; i++)
- {
- UndertaleFont fnt = Data.Fonts[i];
- if (splitStringsList[j].ToLower() == fnt.Name.Content.ToLower())
- {
- UndertaleFont donorFNT = Data.Fonts.ByName(fnt.Name.Content);
- UndertaleFont nativeFNT = new UndertaleFont();
- nativeFNT.Name = Data.Strings.MakeString(fnt.Name.Content + "_Copy");
- Data.Fonts.Add(nativeFNT);
- nativeFNT.Glyphs.Clear();
- nativeFNT.RangeStart = donorFNT.RangeStart;
- nativeFNT.DisplayName = Data.Strings.MakeString(donorFNT.DisplayName.Content + "_Copy");
- nativeFNT.EmSize = donorFNT.EmSize;
- nativeFNT.Bold = donorFNT.Bold;
- nativeFNT.Italic = donorFNT.Italic;
- nativeFNT.Charset = donorFNT.Charset;
- nativeFNT.AntiAliasing = donorFNT.AntiAliasing;
- nativeFNT.ScaleX = donorFNT.ScaleX;
- nativeFNT.ScaleY = donorFNT.ScaleY;
- foreach (UndertaleFont.Glyph glyph in donorFNT.Glyphs)
- {
- UndertaleFont.Glyph glyph_new = new UndertaleFont.Glyph();
- glyph_new.Character = glyph.Character;
- glyph_new.SourceX = glyph.SourceX;
- glyph_new.SourceY = glyph.SourceY;
- glyph_new.SourceWidth = glyph.SourceWidth;
- glyph_new.SourceHeight = glyph.SourceHeight;
- glyph_new.Shift = glyph.Shift;
- glyph_new.Offset = glyph.Offset;
- nativeFNT.Glyphs.Add(glyph_new);
- }
- nativeFNT.RangeEnd = donorFNT.RangeEnd;
- DumpFont(donorFNT);
- copiedFontsCount += 1;
- }
- }
- }
- for (var i = 0; i < tex_IsNull.Count; i++)
- {
- if (tex_IsNull[i] == false)
- {
- UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
- texturePageItem.TargetX = (ushort)tex_TargetX[i];
- texturePageItem.TargetY = (ushort)tex_TargetY[i];
- texturePageItem.TargetWidth = (ushort)tex_TargetWidth[i];
- texturePageItem.TargetHeight = (ushort)tex_TargetHeight[i];
- texturePageItem.SourceX = (ushort)tex_SourceX[i];
- texturePageItem.SourceY = (ushort)tex_SourceY[i];
- texturePageItem.SourceWidth = (ushort)tex_SourceWidth[i];
- texturePageItem.SourceHeight = (ushort)tex_SourceHeight[i];
- texturePageItem.BoundingWidth = (ushort)tex_BoundingWidth[i];
- texturePageItem.BoundingHeight = (ushort)tex_BoundingHeight[i];
- texturePageItem.TexturePage = Data.EmbeddedTextures[(DataEmbeddedTexturesCount + tex_EmbeddedTextureID[i])];
- Data.TexturePageItems.Add(texturePageItem);
- texturePageItem.Name = new UndertaleString("PageItem " + Data.TexturePageItems.IndexOf(texturePageItem).ToString());
- if (tex_Type[i].Equals("bg"))
- {
- UndertaleBackground background = Data.Backgrounds.ByName(tex_Name[i]);
- background.Texture = texturePageItem;
- }
- else if (tex_Type[i].Equals("fnt"))
- {
- UndertaleFont font = Data.Fonts.ByName(tex_Name[i]);
- font.Texture = texturePageItem;
- }
- else
- {
- int frame = tex_Frame[i];
- UndertaleSprite sprite = Data.Sprites.ByName(tex_Name[i]);
- UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
- texentry.Texture = texturePageItem;
- if (frame > sprite.Textures.Count - 1)
- {
- while (frame > sprite.Textures.Count - 1)
- {
- sprite.Textures.Add(texentry);
- }
- }
- else
- {
- sprite.Textures[frame] = texentry;
- }
- }
- }
- else
- {
- if (tex_Type[i] == "spr")
- {
- UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
- texentry.Texture = null;
- Data.Sprites.ByName(tex_Name[i]).Textures.Add(texentry);
- }
- if (tex_Type[i] == "bg")
- {
- Data.Backgrounds.ByName(tex_Name[i]).Texture = null;
- }
- if (tex_Type[i] == "fnt")
- {
- Data.Fonts.ByName(tex_Name[i]).Texture = null;
- }
- }
- }
- SpriteSheetsUsedUpdate();
- RemoveUnusedSpriteSheets();
- TexturePageItemsUsedUpdate();
- RemoveUnusedTexturePageItems();
-});
-DisableAllSyncBindings();
-
-await StopProgressBarUpdater();
-HideProgressBar();
-copiedAssetsCount = (copiedFontsCount + copiedBackgroundsCount + copiedSpritesCount);
-ScriptMessage(copiedAssetsCount.ToString() + " assets were copied (" + copiedSpritesCount.ToString() + " Sprites, " + copiedBackgroundsCount.ToString() + " Backgrounds, and " + copiedFontsCount.ToString() + " Fonts)");
-
-// Functions
-
-void RemoveUnusedTexturePageItems()
-{
- for (int i = (TexturePageItemsUsed.Count - 1); i > -1; i--)
- {
- if (TexturePageItemsUsed[i] == false)
- {
- Data.TexturePageItems.Remove(Data.TexturePageItems[i]);
- }
- }
- foreach (UndertaleTexturePageItem texture in Data.TexturePageItems)
- {
- texture.Name = new UndertaleString("PageItem " + Data.TexturePageItems.IndexOf(texture).ToString());
- }
-}
-void RemoveUnusedSpriteSheets()
-{
- for (int i = (SpriteSheetsUsed.Length - 1); i > -1; i--)
- {
- if (SpriteSheetsUsed[i] == false)
- {
- Data.EmbeddedTextures.Remove(Data.EmbeddedTextures[i]);
- }
- }
- foreach (UndertaleEmbeddedTexture texture in Data.EmbeddedTextures)
- {
- texture.Name = new UndertaleString("Texture " + Data.EmbeddedTextures.IndexOf(texture).ToString());
- }
-}
-void DumpSprite(UndertaleSprite sprite)
-{
- for (int i = 0; i < sprite.Textures.Count; i++)
- {
- if (sprite.Textures[i]?.Texture != null)
- NotNullHandler(sprite.Textures[i].Texture);
- else
- NullHandler();
- tex_Frame.Add(i);
- tex_Name.Add(sprite.Name.Content + "_Copy");
- tex_Type.Add("spr");
- }
- AddProgress(sprite.Textures.Count);
-}
-void DumpFont(UndertaleFont font)
-{
- if (font.Texture != null)
- NotNullHandler(font.Texture);
- else
- NullHandler();
- tex_Frame.Add(0);
- tex_Name.Add(font.Name.Content + "_Copy");
- tex_Type.Add("fnt");
- IncrementProgress();
-}
-void DumpBackground(UndertaleBackground background)
-{
- if (background.Texture != null)
- NotNullHandler(background.Texture);
- else
- NullHandler();
- tex_Frame.Add(0);
- tex_Name.Add(background.Name.Content + "_Copy");
- tex_Type.Add("bg");
- IncrementProgress();
-}
-void NullHandler()
-{
- tex_TargetX.Add(-16000);
- tex_TargetY.Add(-16000);
- tex_SourceWidth.Add(-16000);
- tex_SourceHeight.Add(-16000);
- tex_SourceX.Add(-16000);
- tex_SourceY.Add(-16000);
- tex_TargetWidth.Add(-16000);
- tex_TargetHeight.Add(-16000);
- tex_BoundingWidth.Add(-16000);
- tex_BoundingHeight.Add(-16000);
- tex_EmbeddedTextureID.Add(-16000);
- tex_IsNull.Add(true);
-}
-void NotNullHandler(UndertaleTexturePageItem tex)
-{
- tex_TargetX.Add(tex.TargetX);
- tex_TargetY.Add(tex.TargetY);
- tex_SourceWidth.Add(tex.SourceWidth);
- tex_SourceHeight.Add(tex.SourceHeight);
- tex_SourceX.Add(tex.SourceX);
- tex_SourceY.Add(tex.SourceY);
- tex_TargetWidth.Add(tex.TargetWidth);
- tex_TargetHeight.Add(tex.TargetHeight);
- tex_BoundingWidth.Add(tex.BoundingWidth);
- tex_BoundingHeight.Add(tex.BoundingHeight);
- tex_EmbeddedTextureID.Add(Data.EmbeddedTextures.IndexOf(tex.TexturePage));
- tex_IsNull.Add(false);
-}
-void TexturePageItemsUsedUpdate()
-{
- foreach (UndertaleTexturePageItem texture in Data.TexturePageItems)
- {
- TexturePageItemsUsed.Add(false);
- }
- foreach(UndertaleSprite sprite in Data.Sprites)
- {
- for (int i = 0; i < sprite.Textures.Count; i++)
- {
- if (sprite.Textures[i]?.Texture != null)
- {
- TexturePageItemsUsed[Data.TexturePageItems.IndexOf(sprite.Textures[i]?.Texture)] = true;
- }
- }
- }
- foreach (UndertaleBackground bg in Data.Backgrounds)
- {
- if (bg.Texture != null)
- {
- TexturePageItemsUsed[Data.TexturePageItems.IndexOf(bg.Texture)] = true;
- }
- }
- foreach (UndertaleFont fnt in Data.Fonts)
- {
- if (fnt.Texture != null)
- {
- TexturePageItemsUsed[Data.TexturePageItems.IndexOf(fnt.Texture)] = true;
- }
- }
-}
-void SpriteSheetsUsedUpdate()
-{
- foreach(UndertaleSprite sprite in Data.Sprites)
- {
- for (int i = 0; i < sprite.Textures.Count; i++)
- {
- if (sprite.Textures[i]?.Texture != null)
- {
- SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(sprite.Textures[i]?.Texture.TexturePage)] = true;
- }
- }
- }
- foreach (UndertaleBackground bg in Data.Backgrounds)
- {
- if (bg.Texture != null)
- {
- SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(bg.Texture.TexturePage)] = true;
- }
- }
- foreach (UndertaleFont fnt in Data.Fonts)
- {
- if (fnt.Texture != null)
- {
- SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(fnt.Texture.TexturePage)] = true;
- }
- }
-}
-
-List GetSplitStringsList(string assetType)
-{
- ScriptMessage("Enter the " + assetType + "(s) to copy");
- List splitStringsList = new List();
- string InputtedText = "";
- InputtedText = SimpleTextInput("Menu", "Enter the name(s) of the " + assetType + "(s)", InputtedText, true);
- string[] IndividualLineArray = InputtedText.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
- foreach (var OneLine in IndividualLineArray)
- {
- splitStringsList.Add(OneLine.Trim());
- }
- return splitStringsList;
-}
+//Adapted from original script by Grossley
+using System.Text;
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using UndertaleModLib.Util;
+
+EnsureDataLoaded();
+
+// Initialization Start
+
+var DataEmbeddedTexturesCount = Data.EmbeddedTextures.Count;
+List tex_TargetX = new List();
+List tex_TargetY = new List();
+List tex_SourceX = new List();
+List tex_SourceY = new List();
+List tex_SourceWidth = new List();
+List tex_SourceHeight = new List();
+List tex_TargetWidth = new List();
+List tex_TargetHeight = new List();
+List tex_BoundingWidth = new List();
+List tex_BoundingHeight = new List();
+List tex_Frame = new List();
+List tex_EmbeddedTextureID = new List();
+List tex_Name = new List();
+List tex_Type = new List();
+List tex_IsNull = new List();
+List TexturePageItemsUsed = new List();
+
+// Initialization End
+
+int copiedSpritesCount = 0;
+int copiedBackgroundsCount = 0;
+int copiedFontsCount = 0;
+int copiedAssetsCount = 0;
+List splitStringsList = GetSplitStringsList("sprite(s)/background(s)/font");
+bool[] SpriteSheetsCopyNeeded = new bool[DataEmbeddedTexturesCount];
+bool[] SpriteSheetsUsed = new bool[(DataEmbeddedTexturesCount + DataEmbeddedTexturesCount)];
+
+int lastTextPage = Data.EmbeddedTextures.Count - 1;
+
+SetProgressBar(null, "Textures Exported", 0, Data.TexturePageItems.Count);
+StartProgressBarUpdater();
+
+SyncBinding("EmbeddedTextures, Strings, Backgrounds, Sprites, Fonts, TexturePageItems", true);
+await Task.Run(() => {
+ for (int i = 0; i < SpriteSheetsCopyNeeded.Length; i++)
+ {
+ SpriteSheetsCopyNeeded[i] = false;
+ }
+ for (int i = 0; i < SpriteSheetsUsed.Length; i++)
+ {
+ SpriteSheetsUsed[i] = false;
+ }
+ for (var i = 0; i < DataEmbeddedTexturesCount; i++)
+ {
+ UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
+ texture.Name = new UndertaleString("Texture " + ++lastTextPage);
+ texture.TextureData.TextureBlob = Data.EmbeddedTextures[i].TextureData.TextureBlob;
+ Data.EmbeddedTextures.Add(texture);
+ }
+ for (var j = 0; j < splitStringsList.Count; j++)
+ {
+ int DataBackgroundsLength = Data.Backgrounds.Count;
+ for (var i = 0; i < DataBackgroundsLength; i++)
+ {
+ UndertaleBackground bg = Data.Backgrounds[i];
+ if (splitStringsList[j].ToLower() == bg.Name.Content.ToLower())
+ {
+ UndertaleBackground donorBG = Data.Backgrounds.ByName(bg.Name.Content);
+ UndertaleBackground nativeBG = new UndertaleBackground();
+ nativeBG.Name = Data.Strings.MakeString(bg.Name.Content + "_Copy");
+ Data.Backgrounds.Add(nativeBG);
+ nativeBG.Transparent = donorBG.Transparent;
+ nativeBG.Smooth = donorBG.Smooth;
+ nativeBG.Preload = donorBG.Preload;
+ nativeBG.GMS2UnknownAlways2 = donorBG.GMS2UnknownAlways2;
+ nativeBG.GMS2TileWidth = donorBG.GMS2TileWidth;
+ nativeBG.GMS2TileHeight = donorBG.GMS2TileHeight;
+ nativeBG.GMS2OutputBorderX = donorBG.GMS2OutputBorderX;
+ nativeBG.GMS2OutputBorderY = donorBG.GMS2OutputBorderY;
+ nativeBG.GMS2TileColumns = donorBG.GMS2TileColumns;
+ nativeBG.GMS2ItemsPerTileCount = donorBG.GMS2ItemsPerTileCount;
+ nativeBG.GMS2TileCount = donorBG.GMS2TileCount;
+ nativeBG.GMS2UnknownAlwaysZero = donorBG.GMS2UnknownAlwaysZero;
+ nativeBG.GMS2FrameLength = donorBG.GMS2FrameLength;
+ nativeBG.GMS2TileIds = donorBG.GMS2TileIds;
+ DumpBackground(donorBG);
+ copiedBackgroundsCount += 1;
+ }
+ }
+ int DataSpritesLength = Data.Sprites.Count;
+ for (var k = 0; k < DataSpritesLength; k++)
+ {
+ UndertaleSprite sprite = Data.Sprites[k];
+ if (splitStringsList[j].ToLower() == sprite.Name.Content.ToLower())
+ {
+ UndertaleSprite donorSPR = Data.Sprites.ByName(sprite.Name.Content);
+ UndertaleSprite nativeSPR = new UndertaleSprite();
+ nativeSPR.Name = Data.Strings.MakeString(sprite.Name.Content + "_Copy");
+ Data.Sprites.Add(nativeSPR);
+ for (var i = 0; i < donorSPR.CollisionMasks.Count; i++)
+ nativeSPR.CollisionMasks.Add(new UndertaleSprite.MaskEntry(donorSPR.CollisionMasks[i].Data));
+ nativeSPR.Width = donorSPR.Width;
+ nativeSPR.Height = donorSPR.Height;
+ nativeSPR.MarginLeft = donorSPR.MarginLeft;
+ nativeSPR.MarginRight = donorSPR.MarginRight;
+ nativeSPR.MarginBottom = donorSPR.MarginBottom;
+ nativeSPR.MarginTop = donorSPR.MarginTop;
+ nativeSPR.Transparent = donorSPR.Transparent;
+ nativeSPR.Smooth = donorSPR.Smooth;
+ nativeSPR.Preload = donorSPR.Preload;
+ nativeSPR.BBoxMode = donorSPR.BBoxMode;
+ nativeSPR.OriginX = donorSPR.OriginX;
+ nativeSPR.OriginY = donorSPR.OriginY;
+
+ // Special sprite types (always used in GMS2)
+ nativeSPR.SVersion = donorSPR.SVersion;
+ nativeSPR.GMS2PlaybackSpeed = donorSPR.GMS2PlaybackSpeed;
+ nativeSPR.IsSpecialType = donorSPR.IsSpecialType;
+ nativeSPR.SpineVersion = donorSPR.SpineVersion;
+ nativeSPR.SpineJSON = donorSPR.SpineJSON;
+ nativeSPR.SpineAtlas = donorSPR.SpineAtlas;
+ nativeSPR.SWFVersion = donorSPR.SWFVersion;
+
+ //Possibly will break
+ nativeSPR.SepMasks = donorSPR.SepMasks;
+ nativeSPR.SSpriteType = donorSPR.SSpriteType;
+ nativeSPR.GMS2PlaybackSpeedType = donorSPR.GMS2PlaybackSpeedType;
+ nativeSPR.SpineTextures = donorSPR.SpineTextures;
+ nativeSPR.YYSWF = donorSPR.YYSWF;
+ nativeSPR.V2Sequence = donorSPR.V2Sequence;
+ nativeSPR.V3NineSlice = donorSPR.V3NineSlice;
+
+ DumpSprite(donorSPR);
+ copiedSpritesCount += 1;
+ }
+ }
+ int DataFontsLength = Data.Fonts.Count;
+ for (var i = 0; i < DataFontsLength; i++)
+ {
+ UndertaleFont fnt = Data.Fonts[i];
+ if (splitStringsList[j].ToLower() == fnt.Name.Content.ToLower())
+ {
+ UndertaleFont donorFNT = Data.Fonts.ByName(fnt.Name.Content);
+ UndertaleFont nativeFNT = new UndertaleFont();
+ nativeFNT.Name = Data.Strings.MakeString(fnt.Name.Content + "_Copy");
+ Data.Fonts.Add(nativeFNT);
+ nativeFNT.Glyphs.Clear();
+ nativeFNT.RangeStart = donorFNT.RangeStart;
+ nativeFNT.DisplayName = Data.Strings.MakeString(donorFNT.DisplayName.Content + "_Copy");
+ nativeFNT.EmSize = donorFNT.EmSize;
+ nativeFNT.Bold = donorFNT.Bold;
+ nativeFNT.Italic = donorFNT.Italic;
+ nativeFNT.Charset = donorFNT.Charset;
+ nativeFNT.AntiAliasing = donorFNT.AntiAliasing;
+ nativeFNT.ScaleX = donorFNT.ScaleX;
+ nativeFNT.ScaleY = donorFNT.ScaleY;
+ foreach (UndertaleFont.Glyph glyph in donorFNT.Glyphs)
+ {
+ UndertaleFont.Glyph glyph_new = new UndertaleFont.Glyph();
+ glyph_new.Character = glyph.Character;
+ glyph_new.SourceX = glyph.SourceX;
+ glyph_new.SourceY = glyph.SourceY;
+ glyph_new.SourceWidth = glyph.SourceWidth;
+ glyph_new.SourceHeight = glyph.SourceHeight;
+ glyph_new.Shift = glyph.Shift;
+ glyph_new.Offset = glyph.Offset;
+ nativeFNT.Glyphs.Add(glyph_new);
+ }
+ nativeFNT.RangeEnd = donorFNT.RangeEnd;
+ DumpFont(donorFNT);
+ copiedFontsCount += 1;
+ }
+ }
+ }
+ for (var i = 0; i < tex_IsNull.Count; i++)
+ {
+ if (tex_IsNull[i] == false)
+ {
+ UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
+ texturePageItem.TargetX = (ushort)tex_TargetX[i];
+ texturePageItem.TargetY = (ushort)tex_TargetY[i];
+ texturePageItem.TargetWidth = (ushort)tex_TargetWidth[i];
+ texturePageItem.TargetHeight = (ushort)tex_TargetHeight[i];
+ texturePageItem.SourceX = (ushort)tex_SourceX[i];
+ texturePageItem.SourceY = (ushort)tex_SourceY[i];
+ texturePageItem.SourceWidth = (ushort)tex_SourceWidth[i];
+ texturePageItem.SourceHeight = (ushort)tex_SourceHeight[i];
+ texturePageItem.BoundingWidth = (ushort)tex_BoundingWidth[i];
+ texturePageItem.BoundingHeight = (ushort)tex_BoundingHeight[i];
+ texturePageItem.TexturePage = Data.EmbeddedTextures[(DataEmbeddedTexturesCount + tex_EmbeddedTextureID[i])];
+ Data.TexturePageItems.Add(texturePageItem);
+ texturePageItem.Name = new UndertaleString("PageItem " + Data.TexturePageItems.IndexOf(texturePageItem).ToString());
+ if (tex_Type[i].Equals("bg"))
+ {
+ UndertaleBackground background = Data.Backgrounds.ByName(tex_Name[i]);
+ background.Texture = texturePageItem;
+ }
+ else if (tex_Type[i].Equals("fnt"))
+ {
+ UndertaleFont font = Data.Fonts.ByName(tex_Name[i]);
+ font.Texture = texturePageItem;
+ }
+ else
+ {
+ int frame = tex_Frame[i];
+ UndertaleSprite sprite = Data.Sprites.ByName(tex_Name[i]);
+ UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
+ texentry.Texture = texturePageItem;
+ if (frame > sprite.Textures.Count - 1)
+ {
+ while (frame > sprite.Textures.Count - 1)
+ {
+ sprite.Textures.Add(texentry);
+ }
+ }
+ else
+ {
+ sprite.Textures[frame] = texentry;
+ }
+ }
+ }
+ else
+ {
+ if (tex_Type[i] == "spr")
+ {
+ UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
+ texentry.Texture = null;
+ Data.Sprites.ByName(tex_Name[i]).Textures.Add(texentry);
+ }
+ if (tex_Type[i] == "bg")
+ {
+ Data.Backgrounds.ByName(tex_Name[i]).Texture = null;
+ }
+ if (tex_Type[i] == "fnt")
+ {
+ Data.Fonts.ByName(tex_Name[i]).Texture = null;
+ }
+ }
+ }
+ SpriteSheetsUsedUpdate();
+ RemoveUnusedSpriteSheets();
+ TexturePageItemsUsedUpdate();
+ RemoveUnusedTexturePageItems();
+});
+DisableAllSyncBindings();
+
+await StopProgressBarUpdater();
+HideProgressBar();
+copiedAssetsCount = (copiedFontsCount + copiedBackgroundsCount + copiedSpritesCount);
+ScriptMessage(copiedAssetsCount.ToString() + " assets were copied (" + copiedSpritesCount.ToString() + " Sprites, " + copiedBackgroundsCount.ToString() + " Backgrounds, and " + copiedFontsCount.ToString() + " Fonts)");
+
+// Functions
+
+void RemoveUnusedTexturePageItems()
+{
+ for (int i = (TexturePageItemsUsed.Count - 1); i > -1; i--)
+ {
+ if (TexturePageItemsUsed[i] == false)
+ {
+ Data.TexturePageItems.Remove(Data.TexturePageItems[i]);
+ }
+ }
+ foreach (UndertaleTexturePageItem texture in Data.TexturePageItems)
+ {
+ texture.Name = new UndertaleString("PageItem " + Data.TexturePageItems.IndexOf(texture).ToString());
+ }
+}
+void RemoveUnusedSpriteSheets()
+{
+ for (int i = (SpriteSheetsUsed.Length - 1); i > -1; i--)
+ {
+ if (SpriteSheetsUsed[i] == false)
+ {
+ Data.EmbeddedTextures.Remove(Data.EmbeddedTextures[i]);
+ }
+ }
+ foreach (UndertaleEmbeddedTexture texture in Data.EmbeddedTextures)
+ {
+ texture.Name = new UndertaleString("Texture " + Data.EmbeddedTextures.IndexOf(texture).ToString());
+ }
+}
+void DumpSprite(UndertaleSprite sprite)
+{
+ for (int i = 0; i < sprite.Textures.Count; i++)
+ {
+ if (sprite.Textures[i]?.Texture != null)
+ NotNullHandler(sprite.Textures[i].Texture);
+ else
+ NullHandler();
+ tex_Frame.Add(i);
+ tex_Name.Add(sprite.Name.Content + "_Copy");
+ tex_Type.Add("spr");
+ }
+ AddProgress(sprite.Textures.Count);
+}
+void DumpFont(UndertaleFont font)
+{
+ if (font.Texture != null)
+ NotNullHandler(font.Texture);
+ else
+ NullHandler();
+ tex_Frame.Add(0);
+ tex_Name.Add(font.Name.Content + "_Copy");
+ tex_Type.Add("fnt");
+ IncrementProgress();
+}
+void DumpBackground(UndertaleBackground background)
+{
+ if (background.Texture != null)
+ NotNullHandler(background.Texture);
+ else
+ NullHandler();
+ tex_Frame.Add(0);
+ tex_Name.Add(background.Name.Content + "_Copy");
+ tex_Type.Add("bg");
+ IncrementProgress();
+}
+void NullHandler()
+{
+ tex_TargetX.Add(-16000);
+ tex_TargetY.Add(-16000);
+ tex_SourceWidth.Add(-16000);
+ tex_SourceHeight.Add(-16000);
+ tex_SourceX.Add(-16000);
+ tex_SourceY.Add(-16000);
+ tex_TargetWidth.Add(-16000);
+ tex_TargetHeight.Add(-16000);
+ tex_BoundingWidth.Add(-16000);
+ tex_BoundingHeight.Add(-16000);
+ tex_EmbeddedTextureID.Add(-16000);
+ tex_IsNull.Add(true);
+}
+void NotNullHandler(UndertaleTexturePageItem tex)
+{
+ tex_TargetX.Add(tex.TargetX);
+ tex_TargetY.Add(tex.TargetY);
+ tex_SourceWidth.Add(tex.SourceWidth);
+ tex_SourceHeight.Add(tex.SourceHeight);
+ tex_SourceX.Add(tex.SourceX);
+ tex_SourceY.Add(tex.SourceY);
+ tex_TargetWidth.Add(tex.TargetWidth);
+ tex_TargetHeight.Add(tex.TargetHeight);
+ tex_BoundingWidth.Add(tex.BoundingWidth);
+ tex_BoundingHeight.Add(tex.BoundingHeight);
+ tex_EmbeddedTextureID.Add(Data.EmbeddedTextures.IndexOf(tex.TexturePage));
+ tex_IsNull.Add(false);
+}
+void TexturePageItemsUsedUpdate()
+{
+ foreach (UndertaleTexturePageItem texture in Data.TexturePageItems)
+ {
+ TexturePageItemsUsed.Add(false);
+ }
+ foreach(UndertaleSprite sprite in Data.Sprites)
+ {
+ for (int i = 0; i < sprite.Textures.Count; i++)
+ {
+ if (sprite.Textures[i]?.Texture != null)
+ {
+ TexturePageItemsUsed[Data.TexturePageItems.IndexOf(sprite.Textures[i]?.Texture)] = true;
+ }
+ }
+ }
+ foreach (UndertaleBackground bg in Data.Backgrounds)
+ {
+ if (bg.Texture != null)
+ {
+ TexturePageItemsUsed[Data.TexturePageItems.IndexOf(bg.Texture)] = true;
+ }
+ }
+ foreach (UndertaleFont fnt in Data.Fonts)
+ {
+ if (fnt.Texture != null)
+ {
+ TexturePageItemsUsed[Data.TexturePageItems.IndexOf(fnt.Texture)] = true;
+ }
+ }
+}
+void SpriteSheetsUsedUpdate()
+{
+ foreach(UndertaleSprite sprite in Data.Sprites)
+ {
+ for (int i = 0; i < sprite.Textures.Count; i++)
+ {
+ if (sprite.Textures[i]?.Texture != null)
+ {
+ SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(sprite.Textures[i]?.Texture.TexturePage)] = true;
+ }
+ }
+ }
+ foreach (UndertaleBackground bg in Data.Backgrounds)
+ {
+ if (bg.Texture != null)
+ {
+ SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(bg.Texture.TexturePage)] = true;
+ }
+ }
+ foreach (UndertaleFont fnt in Data.Fonts)
+ {
+ if (fnt.Texture != null)
+ {
+ SpriteSheetsUsed[Data.EmbeddedTextures.IndexOf(fnt.Texture.TexturePage)] = true;
+ }
+ }
+}
+
+List GetSplitStringsList(string assetType)
+{
+ ScriptMessage("Enter the " + assetType + "(s) to copy");
+ List splitStringsList = new List();
+ string InputtedText = "";
+ InputtedText = SimpleTextInput("Menu", "Enter the name(s) of the " + assetType + "(s)", InputtedText, true);
+ string[] IndividualLineArray = InputtedText.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var OneLine in IndividualLineArray)
+ {
+ splitStringsList.Add(OneLine.Trim());
+ }
+ return splitStringsList;
+}
diff --git a/UndertaleModTool/Repackers/ImportASM.csx b/UndertaleModTool/Repackers/ImportASM.csx
index 8752dfe5d..bbe1c107b 100644
--- a/UndertaleModTool/Repackers/ImportASM.csx
+++ b/UndertaleModTool/Repackers/ImportASM.csx
@@ -1,53 +1,53 @@
-// Script by Jockeholm based off of a script by Kneesnap.
-// Major help and edited by Samuel Roy
-
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using System.Linq;
-using UndertaleModLib.Util;
-
-EnsureDataLoaded();
-
-if (Data.ToolInfo.ProfileMode)
-{
- if (!ScriptQuestion("This will cause desyncs! As such, your copy of the code(s) you are importing will be cleared, and will be overwritten with a copy decompiled from this ASM. Continue?"))
- return;
-}
-
-// Check code directory.
-string importFolder = PromptChooseDirectory("Import From Where");
-if (importFolder == null)
- throw new ScriptException("The import folder was not set.");
-
-string[] dirFiles = Directory.GetFiles(importFolder);
-if (dirFiles.Length == 0)
- throw new ScriptException("The selected folder is empty.");
-else if (!dirFiles.Any(x => x.EndsWith(".asm")))
- throw new ScriptException("The selected folder doesn't contain any ASM file.");
-
-// Ask whether they want to link code. If no, will only generate code entry.
-// If yes, will try to add code to objects and scripts depending upon its name
-bool doParse = ScriptQuestion("Do you want to automatically attempt to link imported code?");
-
-bool stopOnError = ScriptQuestion("Stop importing on error?");
-
-
-
-SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartProgressBarUpdater();
-
-SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
-await Task.Run(() => {
- foreach (string file in dirFiles)
- {
- ImportASMFile(file, doParse, true, false, stopOnError);
-
- IncrementProgress();
- }
-});
-DisableAllSyncBindings();
-
-await StopProgressBarUpdater();
-HideProgressBar();
+// Script by Jockeholm based off of a script by Kneesnap.
+// Major help and edited by Samuel Roy
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Linq;
+using UndertaleModLib.Util;
+
+EnsureDataLoaded();
+
+if (Data.ToolInfo.ProfileMode)
+{
+ if (!ScriptQuestion("This will cause desyncs! As such, your copy of the code(s) you are importing will be cleared, and will be overwritten with a copy decompiled from this ASM. Continue?"))
+ return;
+}
+
+// Check code directory.
+string importFolder = PromptChooseDirectory();
+if (importFolder == null)
+ throw new ScriptException("The import folder was not set.");
+
+string[] dirFiles = Directory.GetFiles(importFolder);
+if (dirFiles.Length == 0)
+ throw new ScriptException("The selected folder is empty.");
+else if (!dirFiles.Any(x => x.EndsWith(".asm")))
+ throw new ScriptException("The selected folder doesn't contain any ASM file.");
+
+// Ask whether they want to link code. If no, will only generate code entry.
+// If yes, will try to add code to objects and scripts depending upon its name
+bool doParse = ScriptQuestion("Do you want to automatically attempt to link imported code?");
+
+bool stopOnError = ScriptQuestion("Stop importing on error?");
+
+
+
+SetProgressBar(null, "Files", 0, dirFiles.Length);
+StartProgressBarUpdater();
+
+SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
+await Task.Run(() => {
+ foreach (string file in dirFiles)
+ {
+ ImportASMFile(file, doParse, true, false, stopOnError);
+
+ IncrementProgress();
+ }
+});
+DisableAllSyncBindings();
+
+await StopProgressBarUpdater();
+HideProgressBar();
ScriptMessage("All files successfully imported.");
\ No newline at end of file
diff --git a/UndertaleModTool/Repackers/ImportASM_2_3.csx b/UndertaleModTool/Repackers/ImportASM_2_3.csx
index 2a88377f9..dba62ebf1 100644
--- a/UndertaleModTool/Repackers/ImportASM_2_3.csx
+++ b/UndertaleModTool/Repackers/ImportASM_2_3.csx
@@ -1,255 +1,255 @@
-// Script by Jockeholm based off of a script by Kneesnap.
-// Major help and edited by Samuel Roy
-
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using UndertaleModLib.Util;
-
-EnsureDataLoaded();
-
-bool is2_3 = false;
-if (!((Data.GMS2_3 == false) && (Data.GMS2_3_1 == false) && (Data.GMS2_3_2 == false)))
-{
- is2_3 = true;
- ScriptMessage("This script is for GMS 2.3 games code from \"ExportAllCode2_3.csx\", because some code names get so long that Windows cannot write them adequately.");
-}
-else
-{
- ScriptError("Use the regular ImportASM please!", "Incompatible");
-}
-
-enum EventTypes
-{
- Create,
- Destroy,
- Alarm,
- Step,
- Collision,
- Keyboard,
- Mouse,
- Other,
- Draw,
- KeyPress,
- KeyRelease,
- Gesture,
- Asynchronous,
- PreCreate
-}
-
-// Check code directory.
-string importFolder = PromptChooseDirectory("Import From Where");
-if (importFolder == null)
- throw new ScriptException("The import folder was not set.");
-
-List CodeList = new List();
-
-if (File.Exists(importFolder + "/LookUpTable.txt"))
-{
- int counter = 0;
- string line;
- System.IO.StreamReader file = new System.IO.StreamReader(importFolder + "/" + "LookUpTable.txt");
- while((line = file.ReadLine()) != null)
- {
- if (counter > 0)
- CodeList.Add(line);
- counter++;
- }
- file.Close();
-}
-else
-{
- ScriptError("No LookUpTable.txt!", "Error");
- return;
-}
-
-// Ask whether they want to link code. If no, will only generate code entry.
-// If yes, will try to add code to objects and scripts depending upon its name
-bool doParse = ScriptQuestion("Do you want to automatically attempt to link imported code?");
-
-string[] dirFiles = Directory.GetFiles(importFolder);
-bool skipGlobalScripts = true;
-bool skipGlobalScriptsPrompted = false;
-
-SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartProgressBarUpdater();
-
-SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
-await Task.Run(() => {
- foreach (string file in dirFiles)
- {
- IncrementProgress();
-
- string fileName = Path.GetFileName(file);
- if (!(fileName.EndsWith(".asm")))
- continue;
- fileName = Path.GetFileNameWithoutExtension(file);
- int number;
- bool success = Int32.TryParse(fileName, out number);
- string codeName = "";
- if (success)
- {
- codeName = CodeList[number];
- fileName = codeName + ".asm";
- }
- else
- {
- ScriptError("ASM file not in range of look up table!", "Error");
- return;
- }
- if (fileName.EndsWith("PreCreate_0.asm") && (Data.GeneralInfo.Major < 2))
- continue; // Restarts loop if file is not a valid code asset.
- string asmCode = File.ReadAllText(file);
- if (codeName.Substring(0, 17).Equals("gml_GlobalScript_") && is2_3 && (!(skipGlobalScriptsPrompted)))
- {
- skipGlobalScriptsPrompted = true;
- skipGlobalScripts = ScriptQuestion("Skip global scripts parsing?");
- }
- if (codeName.Substring(0, 17).Equals("gml_GlobalScript_") && is2_3 && ((skipGlobalScriptsPrompted)))
- {
- if (skipGlobalScripts)
- continue;
- }
- UndertaleCode code = Data.Code.ByName(codeName);
- if (code == null) // Should keep from adding duplicate scripts; haven't tested
- {
- code = new UndertaleCode();
- code.Name = Data.Strings.MakeString(codeName);
- Data.Code.Add(code);
- }
- if ((Data?.GeneralInfo.BytecodeVersion > 14) && (Data.CodeLocals.ByName(codeName) == null))
- {
- UndertaleCodeLocals locals = new UndertaleCodeLocals();
- locals.Name = code.Name;
- UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar();
- argsLocal.Name = Data.Strings.MakeString("arguments");
- argsLocal.Index = 0;
- locals.Locals.Add(argsLocal);
- code.LocalsCount = 1;
- code.GenerateLocalVarDefinitions(code.FindReferencedLocalVars(), locals); // Dunno if we actually need this line, but it seems to work?
- Data.CodeLocals.Add(locals);
- }
- if (doParse)
- {
- // This portion links code.
- if (codeName.Substring(0, 10).Equals("gml_Script"))
- {
- // Add code to scripts section.
- if (Data.Scripts.ByName(codeName.Substring(11)) == null)
- {
- UndertaleScript scr = new UndertaleScript();
- scr.Name = Data.Strings.MakeString(codeName.Substring(11));
- scr.Code = code;
- Data.Scripts.Add(scr);
- }
- else
- {
- UndertaleScript scr = Data.Scripts.ByName(codeName.Substring(11));
- scr.Code = code;
- }
- }
- else if (codeName.Substring(0, 10).Equals("gml_Object"))
- {
- // Add code to object methods.
- string afterPrefix = codeName.Substring(11);
- // Dumb substring stuff, don't mess with this.
- int underCount = 0;
- string methodNumberStr = "", methodName = "", objName = "";
- for (int i = afterPrefix.Length - 1; i >= 0; i--)
- {
- if (afterPrefix[i] == '_')
- {
- underCount++;
- if (underCount == 1)
- {
- methodNumberStr = afterPrefix.Substring(i + 1);
- }
- else if (underCount == 2)
- {
- objName = afterPrefix.Substring(0, i);
- methodName = afterPrefix.Substring(i + 1, afterPrefix.Length - objName.Length - methodNumberStr.Length - 2);
- break;
- }
- }
- }
- int methodNumber = Int32.Parse(methodNumberStr);
- UndertaleGameObject obj = Data.GameObjects.ByName(objName);
- if (obj == null)
- {
- bool doNewObj = ScriptQuestion("Object " + objName + " was not found.\nAdd new object called " + objName + "?");
- if (doNewObj)
- {
- UndertaleGameObject gameObj = new UndertaleGameObject();
- gameObj.Name = Data.Strings.MakeString(objName);
- Data.GameObjects.Add(gameObj);
- }
- else
- {
- try
- {
- var instructions = Assembler.Assemble(asmCode, Data);
- code.Replace(instructions);
- }
- catch (Exception ex)
- {
- ScriptMessage("Assembler error at file: " + codeName);
- return;
- }
- continue;
- }
- }
- obj = Data.GameObjects.ByName(objName);
- int eventIdx = (int)Enum.Parse(typeof(EventTypes), methodName);
-
- bool duplicate = false;
- try
- {
- foreach (UndertaleGameObject.Event evnt in obj.Events[eventIdx])
- {
- foreach (UndertaleGameObject.EventAction action in evnt.Actions)
- {
- if (action.CodeId.Name.Content == codeName)
- duplicate = true;
- }
- }
- }
- catch
- {
- //something went wrong, but probably because it's trying to check something non-existent
- //we're gonna make it so
- //keep going
- }
- if (duplicate == false)
- {
- UndertalePointerList eventList = obj.Events[eventIdx];
- UndertaleGameObject.EventAction action = new UndertaleGameObject.EventAction();
- UndertaleGameObject.Event evnt = new UndertaleGameObject.Event();
- action.ActionName = code.Name;
- action.CodeId = code;
- evnt.EventSubtype = (uint)methodNumber;
- evnt.Actions.Add(action);
- eventList.Add(evnt);
- }
- }
- // Code which does not match these criteria cannot link, but are still added to the code section.
- }
- else
- {
- try
- {
- var instructions = Assembler.Assemble(asmCode, Data);
- code.Replace(instructions);
- }
- catch (Exception ex)
- {
- ScriptMessage("Assembler error at file: " + codeName);
- return;
- }
- }
- }
-});
-DisableAllSyncBindings();
-
-await StopProgressBarUpdater();
-HideProgressBar();
+// Script by Jockeholm based off of a script by Kneesnap.
+// Major help and edited by Samuel Roy
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using UndertaleModLib.Util;
+
+EnsureDataLoaded();
+
+bool is2_3 = false;
+if (!((Data.GMS2_3 == false) && (Data.GMS2_3_1 == false) && (Data.GMS2_3_2 == false)))
+{
+ is2_3 = true;
+ ScriptMessage("This script is for GMS 2.3 games code from \"ExportAllCode2_3.csx\", because some code names get so long that Windows cannot write them adequately.");
+}
+else
+{
+ ScriptError("Use the regular ImportASM please!", "Incompatible");
+}
+
+enum EventTypes
+{
+ Create,
+ Destroy,
+ Alarm,
+ Step,
+ Collision,
+ Keyboard,
+ Mouse,
+ Other,
+ Draw,
+ KeyPress,
+ KeyRelease,
+ Gesture,
+ Asynchronous,
+ PreCreate
+}
+
+// Check code directory.
+string importFolder = PromptChooseDirectory();
+if (importFolder == null)
+ throw new ScriptException("The import folder was not set.");
+
+List CodeList = new List();
+
+if (File.Exists(importFolder + "/LookUpTable.txt"))
+{
+ int counter = 0;
+ string line;
+ System.IO.StreamReader file = new System.IO.StreamReader(importFolder + "/" + "LookUpTable.txt");
+ while((line = file.ReadLine()) != null)
+ {
+ if (counter > 0)
+ CodeList.Add(line);
+ counter++;
+ }
+ file.Close();
+}
+else
+{
+ ScriptError("No LookUpTable.txt!", "Error");
+ return;
+}
+
+// Ask whether they want to link code. If no, will only generate code entry.
+// If yes, will try to add code to objects and scripts depending upon its name
+bool doParse = ScriptQuestion("Do you want to automatically attempt to link imported code?");
+
+string[] dirFiles = Directory.GetFiles(importFolder);
+bool skipGlobalScripts = true;
+bool skipGlobalScriptsPrompted = false;
+
+SetProgressBar(null, "Files", 0, dirFiles.Length);
+StartProgressBarUpdater();
+
+SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
+await Task.Run(() => {
+ foreach (string file in dirFiles)
+ {
+ IncrementProgress();
+
+ string fileName = Path.GetFileName(file);
+ if (!(fileName.EndsWith(".asm")))
+ continue;
+ fileName = Path.GetFileNameWithoutExtension(file);
+ int number;
+ bool success = Int32.TryParse(fileName, out number);
+ string codeName = "";
+ if (success)
+ {
+ codeName = CodeList[number];
+ fileName = codeName + ".asm";
+ }
+ else
+ {
+ ScriptError("ASM file not in range of look up table!", "Error");
+ return;
+ }
+ if (fileName.EndsWith("PreCreate_0.asm") && (Data.GeneralInfo.Major < 2))
+ continue; // Restarts loop if file is not a valid code asset.
+ string asmCode = File.ReadAllText(file);
+ if (codeName.Substring(0, 17).Equals("gml_GlobalScript_") && is2_3 && (!(skipGlobalScriptsPrompted)))
+ {
+ skipGlobalScriptsPrompted = true;
+ skipGlobalScripts = ScriptQuestion("Skip global scripts parsing?");
+ }
+ if (codeName.Substring(0, 17).Equals("gml_GlobalScript_") && is2_3 && ((skipGlobalScriptsPrompted)))
+ {
+ if (skipGlobalScripts)
+ continue;
+ }
+ UndertaleCode code = Data.Code.ByName(codeName);
+ if (code == null) // Should keep from adding duplicate scripts; haven't tested
+ {
+ code = new UndertaleCode();
+ code.Name = Data.Strings.MakeString(codeName);
+ Data.Code.Add(code);
+ }
+ if ((Data?.GeneralInfo.BytecodeVersion > 14) && (Data.CodeLocals.ByName(codeName) == null))
+ {
+ UndertaleCodeLocals locals = new UndertaleCodeLocals();
+ locals.Name = code.Name;
+ UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar();
+ argsLocal.Name = Data.Strings.MakeString("arguments");
+ argsLocal.Index = 0;
+ locals.Locals.Add(argsLocal);
+ code.LocalsCount = 1;
+ code.GenerateLocalVarDefinitions(code.FindReferencedLocalVars(), locals); // Dunno if we actually need this line, but it seems to work?
+ Data.CodeLocals.Add(locals);
+ }
+ if (doParse)
+ {
+ // This portion links code.
+ if (codeName.Substring(0, 10).Equals("gml_Script"))
+ {
+ // Add code to scripts section.
+ if (Data.Scripts.ByName(codeName.Substring(11)) == null)
+ {
+ UndertaleScript scr = new UndertaleScript();
+ scr.Name = Data.Strings.MakeString(codeName.Substring(11));
+ scr.Code = code;
+ Data.Scripts.Add(scr);
+ }
+ else
+ {
+ UndertaleScript scr = Data.Scripts.ByName(codeName.Substring(11));
+ scr.Code = code;
+ }
+ }
+ else if (codeName.Substring(0, 10).Equals("gml_Object"))
+ {
+ // Add code to object methods.
+ string afterPrefix = codeName.Substring(11);
+ // Dumb substring stuff, don't mess with this.
+ int underCount = 0;
+ string methodNumberStr = "", methodName = "", objName = "";
+ for (int i = afterPrefix.Length - 1; i >= 0; i--)
+ {
+ if (afterPrefix[i] == '_')
+ {
+ underCount++;
+ if (underCount == 1)
+ {
+ methodNumberStr = afterPrefix.Substring(i + 1);
+ }
+ else if (underCount == 2)
+ {
+ objName = afterPrefix.Substring(0, i);
+ methodName = afterPrefix.Substring(i + 1, afterPrefix.Length - objName.Length - methodNumberStr.Length - 2);
+ break;
+ }
+ }
+ }
+ int methodNumber = Int32.Parse(methodNumberStr);
+ UndertaleGameObject obj = Data.GameObjects.ByName(objName);
+ if (obj == null)
+ {
+ bool doNewObj = ScriptQuestion("Object " + objName + " was not found.\nAdd new object called " + objName + "?");
+ if (doNewObj)
+ {
+ UndertaleGameObject gameObj = new UndertaleGameObject();
+ gameObj.Name = Data.Strings.MakeString(objName);
+ Data.GameObjects.Add(gameObj);
+ }
+ else
+ {
+ try
+ {
+ var instructions = Assembler.Assemble(asmCode, Data);
+ code.Replace(instructions);
+ }
+ catch (Exception ex)
+ {
+ ScriptMessage("Assembler error at file: " + codeName);
+ return;
+ }
+ continue;
+ }
+ }
+ obj = Data.GameObjects.ByName(objName);
+ int eventIdx = (int)Enum.Parse(typeof(EventTypes), methodName);
+
+ bool duplicate = false;
+ try
+ {
+ foreach (UndertaleGameObject.Event evnt in obj.Events[eventIdx])
+ {
+ foreach (UndertaleGameObject.EventAction action in evnt.Actions)
+ {
+ if (action.CodeId.Name.Content == codeName)
+ duplicate = true;
+ }
+ }
+ }
+ catch
+ {
+ //something went wrong, but probably because it's trying to check something non-existent
+ //we're gonna make it so
+ //keep going
+ }
+ if (duplicate == false)
+ {
+ UndertalePointerList eventList = obj.Events[eventIdx];
+ UndertaleGameObject.EventAction action = new UndertaleGameObject.EventAction();
+ UndertaleGameObject.Event evnt = new UndertaleGameObject.Event();
+ action.ActionName = code.Name;
+ action.CodeId = code;
+ evnt.EventSubtype = (uint)methodNumber;
+ evnt.Actions.Add(action);
+ eventList.Add(evnt);
+ }
+ }
+ // Code which does not match these criteria cannot link, but are still added to the code section.
+ }
+ else
+ {
+ try
+ {
+ var instructions = Assembler.Assemble(asmCode, Data);
+ code.Replace(instructions);
+ }
+ catch (Exception ex)
+ {
+ ScriptMessage("Assembler error at file: " + codeName);
+ return;
+ }
+ }
+ }
+});
+DisableAllSyncBindings();
+
+await StopProgressBarUpdater();
+HideProgressBar();
ScriptMessage("All files successfully imported.");
\ No newline at end of file
diff --git a/UndertaleModTool/Repackers/ImportAllStrings.csx b/UndertaleModTool/Repackers/ImportAllStrings.csx
index ad0557c1a..25b161969 100644
--- a/UndertaleModTool/Repackers/ImportAllStrings.csx
+++ b/UndertaleModTool/Repackers/ImportAllStrings.csx
@@ -1,100 +1,100 @@
-// Adapted from original script by Grossley
-
-using System.Text;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using UndertaleModLib.Util;
-
-EnsureDataLoaded();
-
-if (Data.ToolInfo.ProfileMode)
-{
- ScriptMessage("This script will not modify your existing edited GML code registered in your profile. Please use GML editing for text editing, or a script like FindAndReplace, for editing strings within these code entries.");
-}
-else
-{
- if (!(ScriptQuestion("This script will recompile all code entries in your profile (if they exist) to the default decompiled output. Continue?")))
- return;
- foreach (UndertaleCode c in Data.Code)
- NukeProfileGML(c.Name.Content);
-}
-
-string importFolder = PromptChooseDirectory("Import from where");
-if (importFolder == null)
- throw new ScriptException("The import folder was not set.");
-
-//Overwrite Check One
-if (!File.Exists(importFolder + "/strings.txt"))
-{
- ScriptError("No 'strings.txt' file exists!", "Error");
- return;
-}
-
-int file_length = 0;
-string line = "";
-using (StreamReader reader = new StreamReader(importFolder + "/strings.txt"))
-{
- while ((line = reader.ReadLine()) != null)
- {
- file_length += 1;
- }
-}
-
-int validStringsCount = 0;
-foreach (var str in Data.Strings)
-{
- if (str.Content.Contains("\n") || str.Content.Contains("\r"))
- continue;
- validStringsCount += 1;
-}
-
-if (file_length < validStringsCount)
-{
- ScriptError("ERROR 0: Unexpected end of file at line: " + file_length.ToString() + ". Expected file length was: " + validStringsCount.ToString() + ". No changes have been made.", "Error");
- return;
-}
-else if (file_length > validStringsCount)
-{
- ScriptError("ERROR 1: Line count exceeds expected count. Current count: " + file_length.ToString() + ". Expected count: " + validStringsCount.ToString() + ". No changes have been made.", "Error");
- return;
-}
-
-using (StreamReader reader = new StreamReader(importFolder + "/strings.txt"))
-{
- int line_no = 1;
- line = "";
- foreach (var str in Data.Strings)
- {
- if (str.Content.Contains("\n") || str.Content.Contains("\r"))
- continue;
- if (!((line = reader.ReadLine()) != null))
- {
- ScriptError("ERROR 2: Unexpected end of file at line: " + line_no.ToString() + ". Expected file length was: " + validStringsCount.ToString() + ". No changes have been made.", "Error");
- return;
- }
- line_no += 1;
- }
-}
-
-using (StreamReader reader = new StreamReader(importFolder + "/strings.txt"))
-{
- int line_no = 1;
- line = "";
- foreach (var str in Data.Strings)
- {
- if (str.Content.Contains("\n") || str.Content.Contains("\r"))
- continue;
- if ((line = reader.ReadLine()) != null)
- str.Content = line;
- else
- {
- ScriptError("ERROR 3: Unexpected end of file at line: " + line_no.ToString() + ". Expected file length was: " + validStringsCount.ToString() + ". All lines within the file have been applied. Please check for errors.", "Error");
- return;
- }
- line_no += 1;
- }
-}
-
+// Adapted from original script by Grossley
+
+using System.Text;
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using UndertaleModLib.Util;
+
+EnsureDataLoaded();
+
+if (Data.ToolInfo.ProfileMode)
+{
+ ScriptMessage("This script will not modify your existing edited GML code registered in your profile. Please use GML editing for text editing, or a script like FindAndReplace, for editing strings within these code entries.");
+}
+else
+{
+ if (!(ScriptQuestion("This script will recompile all code entries in your profile (if they exist) to the default decompiled output. Continue?")))
+ return;
+ foreach (UndertaleCode c in Data.Code)
+ NukeProfileGML(c.Name.Content);
+}
+
+string importFolder = PromptChooseDirectory();
+if (importFolder == null)
+ throw new ScriptException("The import folder was not set.");
+
+//Overwrite Check One
+if (!File.Exists(importFolder + "/strings.txt"))
+{
+ ScriptError("No 'strings.txt' file exists!", "Error");
+ return;
+}
+
+int file_length = 0;
+string line = "";
+using (StreamReader reader = new StreamReader(importFolder + "/strings.txt"))
+{
+ while ((line = reader.ReadLine()) != null)
+ {
+ file_length += 1;
+ }
+}
+
+int validStringsCount = 0;
+foreach (var str in Data.Strings)
+{
+ if (str.Content.Contains("\n") || str.Content.Contains("\r"))
+ continue;
+ validStringsCount += 1;
+}
+
+if (file_length < validStringsCount)
+{
+ ScriptError("ERROR 0: Unexpected end of file at line: " + file_length.ToString() + ". Expected file length was: " + validStringsCount.ToString() + ". No changes have been made.", "Error");
+ return;
+}
+else if (file_length > validStringsCount)
+{
+ ScriptError("ERROR 1: Line count exceeds expected count. Current count: " + file_length.ToString() + ". Expected count: " + validStringsCount.ToString() + ". No changes have been made.", "Error");
+ return;
+}
+
+using (StreamReader reader = new StreamReader(importFolder + "/strings.txt"))
+{
+ int line_no = 1;
+ line = "";
+ foreach (var str in Data.Strings)
+ {
+ if (str.Content.Contains("\n") || str.Content.Contains("\r"))
+ continue;
+ if (!((line = reader.ReadLine()) != null))
+ {
+ ScriptError("ERROR 2: Unexpected end of file at line: " + line_no.ToString() + ". Expected file length was: " + validStringsCount.ToString() + ". No changes have been made.", "Error");
+ return;
+ }
+ line_no += 1;
+ }
+}
+
+using (StreamReader reader = new StreamReader(importFolder + "/strings.txt"))
+{
+ int line_no = 1;
+ line = "";
+ foreach (var str in Data.Strings)
+ {
+ if (str.Content.Contains("\n") || str.Content.Contains("\r"))
+ continue;
+ if ((line = reader.ReadLine()) != null)
+ str.Content = line;
+ else
+ {
+ ScriptError("ERROR 3: Unexpected end of file at line: " + line_no.ToString() + ". Expected file length was: " + validStringsCount.ToString() + ". All lines within the file have been applied. Please check for errors.", "Error");
+ return;
+ }
+ line_no += 1;
+ }
+}
+
ReapplyProfileCode();
\ No newline at end of file
diff --git a/UndertaleModTool/Repackers/ImportAllTilesets.csx b/UndertaleModTool/Repackers/ImportAllTilesets.csx
index be811e675..29deba530 100644
--- a/UndertaleModTool/Repackers/ImportAllTilesets.csx
+++ b/UndertaleModTool/Repackers/ImportAllTilesets.csx
@@ -1,62 +1,62 @@
-// Adapted from original script by Grossley
-
-using System.Text;
-using System;
-using System.IO;
-using System.Drawing;
-using System.Threading;
-using System.Threading.Tasks;
-
-EnsureDataLoaded();
-
-// Setup root export folder.
-string winFolder = GetFolder(FilePath); // The folder data.win is located in.
-
-string subPath = winFolder + "Export_Tilesets";
-int i = 0;
-
-string GetFolder(string path)
-{
- return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
-}
-
-// Folder Check One
-if (!Directory.Exists(winFolder + "Export_Tilesets\\"))
-{
- ScriptError("There is no 'Export_Tilesets' folder to import.", "Error: Nothing to import.");
- return;
-}
-
-SetProgressBar(null, "Tilesets", 0, Data.Backgrounds.Count);
-StartProgressBarUpdater();
-
-await ImportTilesets();
-
-await StopProgressBarUpdater();
-HideProgressBar();
-ScriptMessage("Import Complete.");
-
-
-async Task ImportTilesets()
-{
- await Task.Run(() => Parallel.ForEach(Data.Backgrounds, ImportTileset));
-}
-
-void ImportTileset(UndertaleBackground tileset)
-{
- try
- {
- string path = subPath + "\\" + tileset.Name.Content + ".png";
- if (File.Exists(path))
- {
- Bitmap img = new Bitmap(path);
- tileset.Texture.ReplaceTexture((Image)img);
- }
- }
- catch (Exception ex)
- {
- ScriptMessage($"Failed to import file {tileset.Name} (index - {Data.Backgrounds.IndexOf(tileset)}) due to: " + ex.Message);
- }
-
- IncrementProgress();
-}
+// Adapted from original script by Grossley
+
+using System.Text;
+using System;
+using System.IO;
+using System.Drawing;
+using System.Threading;
+using System.Threading.Tasks;
+
+EnsureDataLoaded();
+
+// Setup root export folder.
+string winFolder = GetFolder(FilePath); // The folder data.win is located in.
+
+string subPath = winFolder + "Export_Tilesets";
+int i = 0;
+
+string GetFolder(string path)
+{
+ return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
+}
+
+// Folder Check One
+if (!Directory.Exists(winFolder + "Export_Tilesets\\"))
+{
+ ScriptError("There is no 'Export_Tilesets' folder to import.", "Error: Nothing to import.");
+ return;
+}
+
+SetProgressBar(null, "Tilesets", 0, Data.Backgrounds.Count);
+StartProgressBarUpdater();
+
+await ImportTilesets();
+
+await StopProgressBarUpdater();
+HideProgressBar();
+ScriptMessage("Import Complete.");
+
+
+async Task ImportTilesets()
+{
+ await Task.Run(() => Parallel.ForEach(Data.Backgrounds, ImportTileset));
+}
+
+void ImportTileset(UndertaleBackground tileset)
+{
+ try
+ {
+ string path = subPath + "\\" + tileset.Name.Content + ".png";
+ if (File.Exists(path))
+ {
+ Bitmap img = new Bitmap(path);
+ tileset.Texture.ReplaceTexture((Image)img);
+ }
+ }
+ catch (Exception ex)
+ {
+ ScriptMessage($"Failed to import file {tileset.Name} (index - {Data.Backgrounds.IndexOf(tileset)}) due to: " + ex.Message);
+ }
+
+ IncrementProgress();
+}
diff --git a/UndertaleModTool/Repackers/ImportFontData.csx b/UndertaleModTool/Repackers/ImportFontData.csx
index 2edb720b4..9f1b5d4e2 100644
--- a/UndertaleModTool/Repackers/ImportFontData.csx
+++ b/UndertaleModTool/Repackers/ImportFontData.csx
@@ -1,456 +1,456 @@
-//Texture packer by Samuel Roy
-// Uses code from https://github.com/mfascia/TexturePacker
-
-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();
-
-string importFolder = PromptChooseDirectory("Import From Where");
-if (importFolder == null)
- throw new ScriptException("The import folder was not set.");
-
-System.IO.Directory.CreateDirectory("Packager");
-string sourcePath = importFolder;
-string searchPattern = "*.png";
-string outName = "Packager/atlas.txt";
-int textureSize = 2048;
-int border = 2;
-bool debug = false;
-Packer packer = new Packer();
-packer.Process(sourcePath, searchPattern, textureSize, border, debug);
-packer.SaveAtlasses(outName);
-
-int lastTextPage = Data.EmbeddedTextures.Count - 1;
-int lastTextPageItem = Data.TexturePageItems.Count - 1;
-
-string prefix = outName.Replace(Path.GetExtension(outName), "");
-int atlasCount = 0;
-foreach (Atlas atlas in packer.Atlasses)
-{
- string atlasName = String.Format(prefix + "{0:000}" + ".png", atlasCount);
- Bitmap atlasBitmap = new Bitmap(atlasName);
- UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
- texture.Name = new UndertaleString("Texture " + ++lastTextPage);
- texture.TextureData.TextureBlob = File.ReadAllBytes(atlasName);
- Data.EmbeddedTextures.Add(texture);
- foreach (Node n in atlas.Nodes)
- {
- if (n.Texture != null)
- {
- UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
- texturePageItem.Name = new UndertaleString("PageItem " + ++lastTextPageItem);
- texturePageItem.SourceX = (ushort)n.Bounds.X;
- texturePageItem.SourceY = (ushort)n.Bounds.Y;
- texturePageItem.SourceWidth = (ushort)n.Bounds.Width;
- texturePageItem.SourceHeight = (ushort)n.Bounds.Height;
- texturePageItem.TargetX = 0;
- texturePageItem.TargetY = 0;
- texturePageItem.TargetWidth = (ushort)n.Bounds.Width;
- texturePageItem.TargetHeight = (ushort)n.Bounds.Height;
- texturePageItem.BoundingWidth = (ushort)n.Bounds.Width;
- texturePageItem.BoundingHeight = (ushort)n.Bounds.Height;
- texturePageItem.TexturePage = texture;
- Data.TexturePageItems.Add(texturePageItem);
- string stripped = Path.GetFileNameWithoutExtension(n.Texture.Source);
- int lastUnderscore = stripped.LastIndexOf('_');
- string spriteName = stripped.Substring(0, lastUnderscore);
-
- UndertaleFont font = null;
- font = Data.Fonts.ByName(stripped);
-
- if(font == null)
- {
- UndertaleString fontUTString = Data.Strings.MakeString(stripped);
- UndertaleFont newFont = new UndertaleFont();
- newFont.Name = fontUTString;
-
- fontUpdate(newFont);
- newFont.Texture = texturePageItem;
- Data.Fonts.Add(newFont);
- continue;
- }
-
- fontUpdate(font);
- font.Texture = texturePageItem;
- UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
- texentry.Texture = texturePageItem;
- }
- }
- atlasCount++;
-}
-
-
-
-HideProgressBar();
-ScriptMessage("Import Complete!");
-
-public void fontUpdate(UndertaleFont newFont)
-{
- using(StreamReader reader = new StreamReader(sourcePath + "glyphs_" + newFont.Name.Content + ".csv"))
- {
- newFont.Glyphs.Clear();
- string line;
- int head = 0;
- while((line = reader.ReadLine()) != null)
- {
- string[] s = line.Split(';');
-
- if (head == 1)
- {
- newFont.RangeStart = UInt16.Parse(s[0]);
- head++;
- }
-
- if (head == 0)
- {
- String namae = s[0].Replace("\"", "");
- newFont.DisplayName = Data.Strings.MakeString(namae);
- newFont.EmSize = UInt16.Parse(s[1]);
- newFont.Bold = Boolean.Parse(s[2]);
- newFont.Italic = Boolean.Parse(s[3]);
- newFont.Charset = Byte.Parse(s[4]);
- newFont.AntiAliasing = Byte.Parse(s[5]);
- newFont.ScaleX = UInt16.Parse(s[6]);
- newFont.ScaleY = UInt16.Parse(s[7]);
- head++;
- }
-
- if (head > 1)
- {
- newFont.Glyphs.Add(new UndertaleFont.Glyph()
- {
- Character = UInt16.Parse(s[0]),
- SourceX = UInt16.Parse(s[1]),
- SourceY = UInt16.Parse(s[2]),
- SourceWidth = UInt16.Parse(s[3]),
- SourceHeight = UInt16.Parse(s[4]),
- Shift = Int16.Parse(s[5]),
- Offset = Int16.Parse(s[6]),
- });
- newFont.RangeEnd = UInt32.Parse(s[0]);
- }
- }
-
- }
-}
-
-public class TextureInfo
-{
- public string Source;
- public int Width;
- public int Height;
-}
-
-public enum SplitType
-{
- Horizontal,
- Vertical,
-}
-
-public enum BestFitHeuristic
-{
- Area,
- MaxOneAxis,
-}
-
-public class Node
-{
- public Rectangle Bounds;
- public TextureInfo Texture;
- public SplitType SplitType;
-}
-
-public class Atlas
-{
- public int Width;
- public int Height;
- public List Nodes;
-}
-
-public class Packer
-{
- public List SourceTextures;
- public StringWriter Log;
- public StringWriter Error;
- public int Padding;
- public int AtlasSize;
- public bool DebugMode;
- public BestFitHeuristic FitHeuristic;
- public List Atlasses;
-
- public Packer()
- {
- SourceTextures = new List();
- Log = new StringWriter();
- Error = new StringWriter();
- }
-
- public void Process(string _SourceDir, string _Pattern, int _AtlasSize, int _Padding, bool _DebugMode)
- {
- Padding = _Padding;
- AtlasSize = _AtlasSize;
- DebugMode = _DebugMode;
- //1: scan for all the textures we need to pack
- ScanForTextures(_SourceDir, _Pattern);
- List textures = new List();
- textures = SourceTextures.ToList();
- //2: generate as many atlasses as needed (with the latest one as small as possible)
- Atlasses = new List();
- while (textures.Count > 0)
- {
- Atlas atlas = new Atlas();
- atlas.Width = _AtlasSize;
- atlas.Height = _AtlasSize;
- List leftovers = LayoutAtlas(textures, atlas);
- if (leftovers.Count == 0)
- {
- // we reached the last atlas. Check if this last atlas could have been twice smaller
- while (leftovers.Count == 0)
- {
- atlas.Width /= 2;
- atlas.Height /= 2;
- leftovers = LayoutAtlas(textures, atlas);
- }
- // we need to go 1 step larger as we found the first size that is to small
- atlas.Width *= 2;
- atlas.Height *= 2;
- leftovers = LayoutAtlas(textures, atlas);
- }
- Atlasses.Add(atlas);
- textures = leftovers;
- }
- }
-
- public void SaveAtlasses(string _Destination)
- {
- int atlasCount = 0;
- string prefix = _Destination.Replace(Path.GetExtension(_Destination), "");
- string descFile = _Destination;
- StreamWriter tw = new StreamWriter(_Destination);
- tw.WriteLine("source_tex, atlas_tex, x, y, width, height");
- foreach (Atlas atlas in Atlasses)
- {
- string atlasName = String.Format(prefix + "{0:000}" + ".png", atlasCount);
- //1: Save images
- Image img = CreateAtlasImage(atlas);
- //DPI fix start
- Bitmap ResolutionFix = new Bitmap(img);
- ResolutionFix.SetResolution(96.0F, 96.0F);
- Image img2 = ResolutionFix;
- //DPI fix end
- img2.Save(atlasName, System.Drawing.Imaging.ImageFormat.Png);
- //2: save description in file
- foreach (Node n in atlas.Nodes)
- {
- if (n.Texture != null)
- {
- tw.Write(n.Texture.Source + ", ");
- tw.Write(atlasName + ", ");
- tw.Write((n.Bounds.X).ToString() + ", ");
- tw.Write((n.Bounds.Y).ToString() + ", ");
- tw.Write((n.Bounds.Width).ToString() + ", ");
- tw.WriteLine((n.Bounds.Height).ToString());
- }
- }
- ++atlasCount;
- }
- tw.Close();
- tw = new StreamWriter(prefix + ".log");
- tw.WriteLine("--- LOG -------------------------------------------");
- tw.WriteLine(Log.ToString());
- tw.WriteLine("--- ERROR -----------------------------------------");
- tw.WriteLine(Error.ToString());
- tw.Close();
- }
-
- private void ScanForTextures(string _Path, string _Wildcard)
- {
- DirectoryInfo di = new DirectoryInfo(_Path);
- FileInfo[] files = di.GetFiles(_Wildcard, SearchOption.AllDirectories);
- foreach (FileInfo fi in files)
- {
- Image img = Image.FromFile(fi.FullName);
- if (img != null)
- {
- if (img.Width <= AtlasSize && img.Height <= AtlasSize)
- {
- TextureInfo ti = new TextureInfo();
-
- ti.Source = fi.FullName;
- ti.Width = img.Width;
- ti.Height = img.Height;
-
- SourceTextures.Add(ti);
-
- Log.WriteLine("Added " + fi.FullName);
- }
- else
- {
- Error.WriteLine(fi.FullName + " is too large to fix in the atlas. Skipping!");
- }
- }
- }
- }
-
- private void HorizontalSplit(Node _ToSplit, int _Width, int _Height, List _List)
- {
- Node n1 = new Node();
- n1.Bounds.X = _ToSplit.Bounds.X + _Width + Padding;
- n1.Bounds.Y = _ToSplit.Bounds.Y;
- n1.Bounds.Width = _ToSplit.Bounds.Width - _Width - Padding;
- n1.Bounds.Height = _Height;
- n1.SplitType = SplitType.Vertical;
- Node n2 = new Node();
- n2.Bounds.X = _ToSplit.Bounds.X;
- n2.Bounds.Y = _ToSplit.Bounds.Y + _Height + Padding;
- n2.Bounds.Width = _ToSplit.Bounds.Width;
- n2.Bounds.Height = _ToSplit.Bounds.Height - _Height - Padding;
- n2.SplitType = SplitType.Horizontal;
- if (n1.Bounds.Width > 0 && n1.Bounds.Height > 0)
- _List.Add(n1);
- if (n2.Bounds.Width > 0 && n2.Bounds.Height > 0)
- _List.Add(n2);
- }
-
- private void VerticalSplit(Node _ToSplit, int _Width, int _Height, List _List)
- {
- Node n1 = new Node();
- n1.Bounds.X = _ToSplit.Bounds.X + _Width + Padding;
- n1.Bounds.Y = _ToSplit.Bounds.Y;
- n1.Bounds.Width = _ToSplit.Bounds.Width - _Width - Padding;
- n1.Bounds.Height = _ToSplit.Bounds.Height;
- n1.SplitType = SplitType.Vertical;
- Node n2 = new Node();
- n2.Bounds.X = _ToSplit.Bounds.X;
- n2.Bounds.Y = _ToSplit.Bounds.Y + _Height + Padding;
- n2.Bounds.Width = _Width;
- n2.Bounds.Height = _ToSplit.Bounds.Height - _Height - Padding;
- n2.SplitType = SplitType.Horizontal;
- if (n1.Bounds.Width > 0 && n1.Bounds.Height > 0)
- _List.Add(n1);
- if (n2.Bounds.Width > 0 && n2.Bounds.Height > 0)
- _List.Add(n2);
- }
-
- private TextureInfo FindBestFitForNode(Node _Node, List _Textures)
- {
- TextureInfo bestFit = null;
- float nodeArea = _Node.Bounds.Width * _Node.Bounds.Height;
- float maxCriteria = 0.0f;
- foreach (TextureInfo ti in _Textures)
- {
- switch (FitHeuristic)
- {
- // Max of Width and Height ratios
- case BestFitHeuristic.MaxOneAxis:
- if (ti.Width <= _Node.Bounds.Width && ti.Height <= _Node.Bounds.Height)
- {
- float wRatio = (float)ti.Width / (float)_Node.Bounds.Width;
- float hRatio = (float)ti.Height / (float)_Node.Bounds.Height;
- float ratio = wRatio > hRatio ? wRatio : hRatio;
- if (ratio > maxCriteria)
- {
- maxCriteria = ratio;
- bestFit = ti;
- }
- }
- break;
- // Maximize Area coverage
- case BestFitHeuristic.Area:
- if (ti.Width <= _Node.Bounds.Width && ti.Height <= _Node.Bounds.Height)
- {
- float textureArea = ti.Width * ti.Height;
- float coverage = textureArea / nodeArea;
- if (coverage > maxCriteria)
- {
- maxCriteria = coverage;
- bestFit = ti;
- }
- }
- break;
- }
- }
- return bestFit;
- }
-
- private List LayoutAtlas(List _Textures, Atlas _Atlas)
- {
- List freeList = new List();
- List textures = new List();
- _Atlas.Nodes = new List();
- textures = _Textures.ToList();
- Node root = new Node();
- root.Bounds.Size = new Size(_Atlas.Width, _Atlas.Height);
- root.SplitType = SplitType.Horizontal;
- freeList.Add(root);
- while (freeList.Count > 0 && textures.Count > 0)
- {
- Node node = freeList[0];
- freeList.RemoveAt(0);
- TextureInfo bestFit = FindBestFitForNode(node, textures);
- if (bestFit != null)
- {
- if (node.SplitType == SplitType.Horizontal)
- {
- HorizontalSplit(node, bestFit.Width, bestFit.Height, freeList);
- }
- else
- {
- VerticalSplit(node, bestFit.Width, bestFit.Height, freeList);
- }
- node.Texture = bestFit;
- node.Bounds.Width = bestFit.Width;
- node.Bounds.Height = bestFit.Height;
- textures.Remove(bestFit);
- }
- _Atlas.Nodes.Add(node);
- }
- return textures;
- }
-
- private Image CreateAtlasImage(Atlas _Atlas)
- {
- Image img = new Bitmap(_Atlas.Width, _Atlas.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- Graphics g = Graphics.FromImage(img);
- if (DebugMode)
- {
- g.FillRectangle(Brushes.Green, new Rectangle(0, 0, _Atlas.Width, _Atlas.Height));
- }
- foreach (Node n in _Atlas.Nodes)
- {
- if (n.Texture != null)
- {
- Image sourceImg = Image.FromFile(n.Texture.Source);
- g.DrawImage(sourceImg, n.Bounds);
- if (DebugMode)
- {
- string label = Path.GetFileNameWithoutExtension(n.Texture.Source);
- SizeF labelBox = g.MeasureString(label, SystemFonts.MenuFont, new SizeF(n.Bounds.Size));
- RectangleF rectBounds = new Rectangle(n.Bounds.Location, new Size((int)labelBox.Width, (int)labelBox.Height));
- g.FillRectangle(Brushes.Black, rectBounds);
- g.DrawString(label, SystemFonts.MenuFont, Brushes.White, rectBounds);
- }
- }
- else
- {
- g.FillRectangle(Brushes.DarkMagenta, n.Bounds);
- if (DebugMode)
- {
- string label = n.Bounds.Width.ToString() + "x" + n.Bounds.Height.ToString();
- SizeF labelBox = g.MeasureString(label, SystemFonts.MenuFont, new SizeF(n.Bounds.Size));
- RectangleF rectBounds = new Rectangle(n.Bounds.Location, new Size((int)labelBox.Width, (int)labelBox.Height));
- g.FillRectangle(Brushes.Black, rectBounds);
- g.DrawString(label, SystemFonts.MenuFont, Brushes.White, rectBounds);
- }
- }
- }
- return img;
- }
-}
+//Texture packer by Samuel Roy
+// Uses code from https://github.com/mfascia/TexturePacker
+
+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();
+
+string importFolder = PromptChooseDirectory();
+if (importFolder == null)
+ throw new ScriptException("The import folder was not set.");
+
+System.IO.Directory.CreateDirectory("Packager");
+string sourcePath = importFolder;
+string searchPattern = "*.png";
+string outName = "Packager/atlas.txt";
+int textureSize = 2048;
+int border = 2;
+bool debug = false;
+Packer packer = new Packer();
+packer.Process(sourcePath, searchPattern, textureSize, border, debug);
+packer.SaveAtlasses(outName);
+
+int lastTextPage = Data.EmbeddedTextures.Count - 1;
+int lastTextPageItem = Data.TexturePageItems.Count - 1;
+
+string prefix = outName.Replace(Path.GetExtension(outName), "");
+int atlasCount = 0;
+foreach (Atlas atlas in packer.Atlasses)
+{
+ string atlasName = String.Format(prefix + "{0:000}" + ".png", atlasCount);
+ Bitmap atlasBitmap = new Bitmap(atlasName);
+ UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
+ texture.Name = new UndertaleString("Texture " + ++lastTextPage);
+ texture.TextureData.TextureBlob = File.ReadAllBytes(atlasName);
+ Data.EmbeddedTextures.Add(texture);
+ foreach (Node n in atlas.Nodes)
+ {
+ if (n.Texture != null)
+ {
+ UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
+ texturePageItem.Name = new UndertaleString("PageItem " + ++lastTextPageItem);
+ texturePageItem.SourceX = (ushort)n.Bounds.X;
+ texturePageItem.SourceY = (ushort)n.Bounds.Y;
+ texturePageItem.SourceWidth = (ushort)n.Bounds.Width;
+ texturePageItem.SourceHeight = (ushort)n.Bounds.Height;
+ texturePageItem.TargetX = 0;
+ texturePageItem.TargetY = 0;
+ texturePageItem.TargetWidth = (ushort)n.Bounds.Width;
+ texturePageItem.TargetHeight = (ushort)n.Bounds.Height;
+ texturePageItem.BoundingWidth = (ushort)n.Bounds.Width;
+ texturePageItem.BoundingHeight = (ushort)n.Bounds.Height;
+ texturePageItem.TexturePage = texture;
+ Data.TexturePageItems.Add(texturePageItem);
+ string stripped = Path.GetFileNameWithoutExtension(n.Texture.Source);
+ int lastUnderscore = stripped.LastIndexOf('_');
+ string spriteName = stripped.Substring(0, lastUnderscore);
+
+ UndertaleFont font = null;
+ font = Data.Fonts.ByName(stripped);
+
+ if(font == null)
+ {
+ UndertaleString fontUTString = Data.Strings.MakeString(stripped);
+ UndertaleFont newFont = new UndertaleFont();
+ newFont.Name = fontUTString;
+
+ fontUpdate(newFont);
+ newFont.Texture = texturePageItem;
+ Data.Fonts.Add(newFont);
+ continue;
+ }
+
+ fontUpdate(font);
+ font.Texture = texturePageItem;
+ UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
+ texentry.Texture = texturePageItem;
+ }
+ }
+ atlasCount++;
+}
+
+
+
+HideProgressBar();
+ScriptMessage("Import Complete!");
+
+public void fontUpdate(UndertaleFont newFont)
+{
+ using(StreamReader reader = new StreamReader(sourcePath + "glyphs_" + newFont.Name.Content + ".csv"))
+ {
+ newFont.Glyphs.Clear();
+ string line;
+ int head = 0;
+ while((line = reader.ReadLine()) != null)
+ {
+ string[] s = line.Split(';');
+
+ if (head == 1)
+ {
+ newFont.RangeStart = UInt16.Parse(s[0]);
+ head++;
+ }
+
+ if (head == 0)
+ {
+ String namae = s[0].Replace("\"", "");
+ newFont.DisplayName = Data.Strings.MakeString(namae);
+ newFont.EmSize = UInt16.Parse(s[1]);
+ newFont.Bold = Boolean.Parse(s[2]);
+ newFont.Italic = Boolean.Parse(s[3]);
+ newFont.Charset = Byte.Parse(s[4]);
+ newFont.AntiAliasing = Byte.Parse(s[5]);
+ newFont.ScaleX = UInt16.Parse(s[6]);
+ newFont.ScaleY = UInt16.Parse(s[7]);
+ head++;
+ }
+
+ if (head > 1)
+ {
+ newFont.Glyphs.Add(new UndertaleFont.Glyph()
+ {
+ Character = UInt16.Parse(s[0]),
+ SourceX = UInt16.Parse(s[1]),
+ SourceY = UInt16.Parse(s[2]),
+ SourceWidth = UInt16.Parse(s[3]),
+ SourceHeight = UInt16.Parse(s[4]),
+ Shift = Int16.Parse(s[5]),
+ Offset = Int16.Parse(s[6]),
+ });
+ newFont.RangeEnd = UInt32.Parse(s[0]);
+ }
+ }
+
+ }
+}
+
+public class TextureInfo
+{
+ public string Source;
+ public int Width;
+ public int Height;
+}
+
+public enum SplitType
+{
+ Horizontal,
+ Vertical,
+}
+
+public enum BestFitHeuristic
+{
+ Area,
+ MaxOneAxis,
+}
+
+public class Node
+{
+ public Rectangle Bounds;
+ public TextureInfo Texture;
+ public SplitType SplitType;
+}
+
+public class Atlas
+{
+ public int Width;
+ public int Height;
+ public List Nodes;
+}
+
+public class Packer
+{
+ public List SourceTextures;
+ public StringWriter Log;
+ public StringWriter Error;
+ public int Padding;
+ public int AtlasSize;
+ public bool DebugMode;
+ public BestFitHeuristic FitHeuristic;
+ public List Atlasses;
+
+ public Packer()
+ {
+ SourceTextures = new List();
+ Log = new StringWriter();
+ Error = new StringWriter();
+ }
+
+ public void Process(string _SourceDir, string _Pattern, int _AtlasSize, int _Padding, bool _DebugMode)
+ {
+ Padding = _Padding;
+ AtlasSize = _AtlasSize;
+ DebugMode = _DebugMode;
+ //1: scan for all the textures we need to pack
+ ScanForTextures(_SourceDir, _Pattern);
+ List textures = new List();
+ textures = SourceTextures.ToList();
+ //2: generate as many atlasses as needed (with the latest one as small as possible)
+ Atlasses = new List();
+ while (textures.Count > 0)
+ {
+ Atlas atlas = new Atlas();
+ atlas.Width = _AtlasSize;
+ atlas.Height = _AtlasSize;
+ List leftovers = LayoutAtlas(textures, atlas);
+ if (leftovers.Count == 0)
+ {
+ // we reached the last atlas. Check if this last atlas could have been twice smaller
+ while (leftovers.Count == 0)
+ {
+ atlas.Width /= 2;
+ atlas.Height /= 2;
+ leftovers = LayoutAtlas(textures, atlas);
+ }
+ // we need to go 1 step larger as we found the first size that is to small
+ atlas.Width *= 2;
+ atlas.Height *= 2;
+ leftovers = LayoutAtlas(textures, atlas);
+ }
+ Atlasses.Add(atlas);
+ textures = leftovers;
+ }
+ }
+
+ public void SaveAtlasses(string _Destination)
+ {
+ int atlasCount = 0;
+ string prefix = _Destination.Replace(Path.GetExtension(_Destination), "");
+ string descFile = _Destination;
+ StreamWriter tw = new StreamWriter(_Destination);
+ tw.WriteLine("source_tex, atlas_tex, x, y, width, height");
+ foreach (Atlas atlas in Atlasses)
+ {
+ string atlasName = String.Format(prefix + "{0:000}" + ".png", atlasCount);
+ //1: Save images
+ Image img = CreateAtlasImage(atlas);
+ //DPI fix start
+ Bitmap ResolutionFix = new Bitmap(img);
+ ResolutionFix.SetResolution(96.0F, 96.0F);
+ Image img2 = ResolutionFix;
+ //DPI fix end
+ img2.Save(atlasName, System.Drawing.Imaging.ImageFormat.Png);
+ //2: save description in file
+ foreach (Node n in atlas.Nodes)
+ {
+ if (n.Texture != null)
+ {
+ tw.Write(n.Texture.Source + ", ");
+ tw.Write(atlasName + ", ");
+ tw.Write((n.Bounds.X).ToString() + ", ");
+ tw.Write((n.Bounds.Y).ToString() + ", ");
+ tw.Write((n.Bounds.Width).ToString() + ", ");
+ tw.WriteLine((n.Bounds.Height).ToString());
+ }
+ }
+ ++atlasCount;
+ }
+ tw.Close();
+ tw = new StreamWriter(prefix + ".log");
+ tw.WriteLine("--- LOG -------------------------------------------");
+ tw.WriteLine(Log.ToString());
+ tw.WriteLine("--- ERROR -----------------------------------------");
+ tw.WriteLine(Error.ToString());
+ tw.Close();
+ }
+
+ private void ScanForTextures(string _Path, string _Wildcard)
+ {
+ DirectoryInfo di = new DirectoryInfo(_Path);
+ FileInfo[] files = di.GetFiles(_Wildcard, SearchOption.AllDirectories);
+ foreach (FileInfo fi in files)
+ {
+ Image img = Image.FromFile(fi.FullName);
+ if (img != null)
+ {
+ if (img.Width <= AtlasSize && img.Height <= AtlasSize)
+ {
+ TextureInfo ti = new TextureInfo();
+
+ ti.Source = fi.FullName;
+ ti.Width = img.Width;
+ ti.Height = img.Height;
+
+ SourceTextures.Add(ti);
+
+ Log.WriteLine("Added " + fi.FullName);
+ }
+ else
+ {
+ Error.WriteLine(fi.FullName + " is too large to fix in the atlas. Skipping!");
+ }
+ }
+ }
+ }
+
+ private void HorizontalSplit(Node _ToSplit, int _Width, int _Height, List _List)
+ {
+ Node n1 = new Node();
+ n1.Bounds.X = _ToSplit.Bounds.X + _Width + Padding;
+ n1.Bounds.Y = _ToSplit.Bounds.Y;
+ n1.Bounds.Width = _ToSplit.Bounds.Width - _Width - Padding;
+ n1.Bounds.Height = _Height;
+ n1.SplitType = SplitType.Vertical;
+ Node n2 = new Node();
+ n2.Bounds.X = _ToSplit.Bounds.X;
+ n2.Bounds.Y = _ToSplit.Bounds.Y + _Height + Padding;
+ n2.Bounds.Width = _ToSplit.Bounds.Width;
+ n2.Bounds.Height = _ToSplit.Bounds.Height - _Height - Padding;
+ n2.SplitType = SplitType.Horizontal;
+ if (n1.Bounds.Width > 0 && n1.Bounds.Height > 0)
+ _List.Add(n1);
+ if (n2.Bounds.Width > 0 && n2.Bounds.Height > 0)
+ _List.Add(n2);
+ }
+
+ private void VerticalSplit(Node _ToSplit, int _Width, int _Height, List _List)
+ {
+ Node n1 = new Node();
+ n1.Bounds.X = _ToSplit.Bounds.X + _Width + Padding;
+ n1.Bounds.Y = _ToSplit.Bounds.Y;
+ n1.Bounds.Width = _ToSplit.Bounds.Width - _Width - Padding;
+ n1.Bounds.Height = _ToSplit.Bounds.Height;
+ n1.SplitType = SplitType.Vertical;
+ Node n2 = new Node();
+ n2.Bounds.X = _ToSplit.Bounds.X;
+ n2.Bounds.Y = _ToSplit.Bounds.Y + _Height + Padding;
+ n2.Bounds.Width = _Width;
+ n2.Bounds.Height = _ToSplit.Bounds.Height - _Height - Padding;
+ n2.SplitType = SplitType.Horizontal;
+ if (n1.Bounds.Width > 0 && n1.Bounds.Height > 0)
+ _List.Add(n1);
+ if (n2.Bounds.Width > 0 && n2.Bounds.Height > 0)
+ _List.Add(n2);
+ }
+
+ private TextureInfo FindBestFitForNode(Node _Node, List _Textures)
+ {
+ TextureInfo bestFit = null;
+ float nodeArea = _Node.Bounds.Width * _Node.Bounds.Height;
+ float maxCriteria = 0.0f;
+ foreach (TextureInfo ti in _Textures)
+ {
+ switch (FitHeuristic)
+ {
+ // Max of Width and Height ratios
+ case BestFitHeuristic.MaxOneAxis:
+ if (ti.Width <= _Node.Bounds.Width && ti.Height <= _Node.Bounds.Height)
+ {
+ float wRatio = (float)ti.Width / (float)_Node.Bounds.Width;
+ float hRatio = (float)ti.Height / (float)_Node.Bounds.Height;
+ float ratio = wRatio > hRatio ? wRatio : hRatio;
+ if (ratio > maxCriteria)
+ {
+ maxCriteria = ratio;
+ bestFit = ti;
+ }
+ }
+ break;
+ // Maximize Area coverage
+ case BestFitHeuristic.Area:
+ if (ti.Width <= _Node.Bounds.Width && ti.Height <= _Node.Bounds.Height)
+ {
+ float textureArea = ti.Width * ti.Height;
+ float coverage = textureArea / nodeArea;
+ if (coverage > maxCriteria)
+ {
+ maxCriteria = coverage;
+ bestFit = ti;
+ }
+ }
+ break;
+ }
+ }
+ return bestFit;
+ }
+
+ private List LayoutAtlas(List _Textures, Atlas _Atlas)
+ {
+ List freeList = new List();
+ List textures = new List();
+ _Atlas.Nodes = new List();
+ textures = _Textures.ToList();
+ Node root = new Node();
+ root.Bounds.Size = new Size(_Atlas.Width, _Atlas.Height);
+ root.SplitType = SplitType.Horizontal;
+ freeList.Add(root);
+ while (freeList.Count > 0 && textures.Count > 0)
+ {
+ Node node = freeList[0];
+ freeList.RemoveAt(0);
+ TextureInfo bestFit = FindBestFitForNode(node, textures);
+ if (bestFit != null)
+ {
+ if (node.SplitType == SplitType.Horizontal)
+ {
+ HorizontalSplit(node, bestFit.Width, bestFit.Height, freeList);
+ }
+ else
+ {
+ VerticalSplit(node, bestFit.Width, bestFit.Height, freeList);
+ }
+ node.Texture = bestFit;
+ node.Bounds.Width = bestFit.Width;
+ node.Bounds.Height = bestFit.Height;
+ textures.Remove(bestFit);
+ }
+ _Atlas.Nodes.Add(node);
+ }
+ return textures;
+ }
+
+ private Image CreateAtlasImage(Atlas _Atlas)
+ {
+ Image img = new Bitmap(_Atlas.Width, _Atlas.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ Graphics g = Graphics.FromImage(img);
+ if (DebugMode)
+ {
+ g.FillRectangle(Brushes.Green, new Rectangle(0, 0, _Atlas.Width, _Atlas.Height));
+ }
+ foreach (Node n in _Atlas.Nodes)
+ {
+ if (n.Texture != null)
+ {
+ Image sourceImg = Image.FromFile(n.Texture.Source);
+ g.DrawImage(sourceImg, n.Bounds);
+ if (DebugMode)
+ {
+ string label = Path.GetFileNameWithoutExtension(n.Texture.Source);
+ SizeF labelBox = g.MeasureString(label, SystemFonts.MenuFont, new SizeF(n.Bounds.Size));
+ RectangleF rectBounds = new Rectangle(n.Bounds.Location, new Size((int)labelBox.Width, (int)labelBox.Height));
+ g.FillRectangle(Brushes.Black, rectBounds);
+ g.DrawString(label, SystemFonts.MenuFont, Brushes.White, rectBounds);
+ }
+ }
+ else
+ {
+ g.FillRectangle(Brushes.DarkMagenta, n.Bounds);
+ if (DebugMode)
+ {
+ string label = n.Bounds.Width.ToString() + "x" + n.Bounds.Height.ToString();
+ SizeF labelBox = g.MeasureString(label, SystemFonts.MenuFont, new SizeF(n.Bounds.Size));
+ RectangleF rectBounds = new Rectangle(n.Bounds.Location, new Size((int)labelBox.Width, (int)labelBox.Height));
+ g.FillRectangle(Brushes.Black, rectBounds);
+ g.DrawString(label, SystemFonts.MenuFont, Brushes.White, rectBounds);
+ }
+ }
+ }
+ return img;
+ }
+}
diff --git a/UndertaleModTool/Repackers/ImportGML.csx b/UndertaleModTool/Repackers/ImportGML.csx
index 72c1c30b0..9fcd255bc 100644
--- a/UndertaleModTool/Repackers/ImportGML.csx
+++ b/UndertaleModTool/Repackers/ImportGML.csx
@@ -1,45 +1,45 @@
-// Script by Jockeholm based off of a script by Kneesnap.
-// Major help and edited by Samuel Roy
-
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using System.Linq;
-using UndertaleModLib.Util;
-
-EnsureDataLoaded();
-
-// Check code directory.
-string importFolder = PromptChooseDirectory("Import From Where");
-if (importFolder == null)
- throw new ScriptException("The import folder was not set.");
-
-string[] dirFiles = Directory.GetFiles(importFolder);
-if (dirFiles.Length == 0)
- throw new ScriptException("The selected folder is empty.");
-else if (!dirFiles.Any(x => x.EndsWith(".gml")))
- throw new ScriptException("The selected folder doesn't contain any GML file.");
-
-// Ask whether they want to link code. If no, will only generate code entry.
-// If yes, will try to add code to objects and scripts depending upon its name
-bool doParse = ScriptQuestion("Do you want to automatically attempt to link imported code?");
-
-bool stopOnError = ScriptQuestion("Stop importing on error?");
-
-SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartProgressBarUpdater();
-
-SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
-await Task.Run(() => {
- foreach (string file in dirFiles)
- {
- IncrementProgress();
-
- ImportGMLFile(file, doParse, false, stopOnError);
- }
-});
-DisableAllSyncBindings();
-
-await StopProgressBarUpdater();
-HideProgressBar();
-ScriptMessage("All files successfully imported.");
+// Script by Jockeholm based off of a script by Kneesnap.
+// Major help and edited by Samuel Roy
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Linq;
+using UndertaleModLib.Util;
+
+EnsureDataLoaded();
+
+// Check code directory.
+string importFolder = PromptChooseDirectory();
+if (importFolder == null)
+ throw new ScriptException("The import folder was not set.");
+
+string[] dirFiles = Directory.GetFiles(importFolder);
+if (dirFiles.Length == 0)
+ throw new ScriptException("The selected folder is empty.");
+else if (!dirFiles.Any(x => x.EndsWith(".gml")))
+ throw new ScriptException("The selected folder doesn't contain any GML file.");
+
+// Ask whether they want to link code. If no, will only generate code entry.
+// If yes, will try to add code to objects and scripts depending upon its name
+bool doParse = ScriptQuestion("Do you want to automatically attempt to link imported code?");
+
+bool stopOnError = ScriptQuestion("Stop importing on error?");
+
+SetProgressBar(null, "Files", 0, dirFiles.Length);
+StartProgressBarUpdater();
+
+SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
+await Task.Run(() => {
+ foreach (string file in dirFiles)
+ {
+ IncrementProgress();
+
+ ImportGMLFile(file, doParse, false, stopOnError);
+ }
+});
+DisableAllSyncBindings();
+
+await StopProgressBarUpdater();
+HideProgressBar();
+ScriptMessage("All files successfully imported.");
diff --git a/UndertaleModTool/Repackers/ImportGML_2_3.csx b/UndertaleModTool/Repackers/ImportGML_2_3.csx
index 4c0b3ddbf..3457687e3 100644
--- a/UndertaleModTool/Repackers/ImportGML_2_3.csx
+++ b/UndertaleModTool/Repackers/ImportGML_2_3.csx
@@ -1,265 +1,265 @@
-// Script by Jockeholm based off of a script by Kneesnap.
-// Major help and edited by Samuel Roy
-
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using UndertaleModLib.Util;
-
-EnsureDataLoaded();
-
-bool is2_3 = false;
-if (!((Data.GMS2_3 == false) && (Data.GMS2_3_1 == false) && (Data.GMS2_3_2 == false)))
-{
- is2_3 = true;
- ScriptMessage("This script is for GMS 2.3 games code from \"ExportAllCode2_3.csx\", because some code names get so long that Windows cannot write them adequately.");
-}
-else
-{
- ScriptError("Use the regular ImportGML please!", "Incompatible");
-}
-
-enum EventTypes
-{
- Create,
- Destroy,
- Alarm,
- Step,
- Collision,
- Keyboard,
- Mouse,
- Other,
- Draw,
- KeyPress,
- KeyRelease,
- Gesture,
- Asynchronous,
- PreCreate
-}
-
-// Check code directory.
-string importFolder = PromptChooseDirectory("Import From Where");
-if (importFolder == null)
- throw new ScriptException("The import folder was not set.");
-
-List CodeList = new List();
-
-if (File.Exists(importFolder + "/LookUpTable.txt"))
-{
- int counter = 0;
- string line;
- System.IO.StreamReader file = new System.IO.StreamReader(importFolder + "/" + "LookUpTable.txt");
- while((line = file.ReadLine()) != null)
- {
- if (counter > 0)
- CodeList.Add(line);
- counter++;
- }
- file.Close();
-}
-else
-{
- ScriptError("No LookUpTable.txt!", "Error");
- return;
-}
-
-// Ask whether they want to link code. If no, will only generate code entry.
-// If yes, will try to add code to objects and scripts depending upon its name
-bool doParse = ScriptQuestion("Do you want to automatically attempt to link imported code?");
-
-string[] dirFiles = Directory.GetFiles(importFolder);
-bool skipGlobalScripts = true;
-bool skipGlobalScriptsPrompted = false;
-
-SetProgressBar(null, "Files", 0, dirFiles.Length);
-StartProgressBarUpdater();
-
-SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
-await Task.Run(() => {
- foreach (string file in dirFiles)
- {
- IncrementProgress();
-
- string fileName = Path.GetFileName(file);
- if (!(fileName.EndsWith(".gml")))
- continue;
- fileName = Path.GetFileNameWithoutExtension(file);
- int number;
- bool success = Int32.TryParse(fileName, out number);
- string codeName;
- if (success)
- {
- codeName = CodeList[number];
- fileName = codeName + ".gml";
- }
- else
- {
- ScriptError("GML file not in range of look up table!", "Error");
- return;
- }
- if (fileName.EndsWith("PreCreate_0.gml") && (Data.GeneralInfo.Major < 2))
- continue; // Restarts loop if file is not a valid code asset.
- string gmlCode = File.ReadAllText(file);
- if (codeName.Substring(0, 17).Equals("gml_GlobalScript_") && is2_3 && (!(skipGlobalScriptsPrompted)))
- {
- skipGlobalScriptsPrompted = true;
- skipGlobalScripts = ScriptQuestion("Skip global scripts parsing?");
- }
- if (codeName.Substring(0, 17).Equals("gml_GlobalScript_") && is2_3 && ((skipGlobalScriptsPrompted)))
- {
- if (skipGlobalScripts)
- continue;
- }
- UndertaleCode code = Data.Code.ByName(codeName);
- if (code == null) // Should keep from adding duplicate scripts; haven't tested
- {
- code = new UndertaleCode();
- code.Name = Data.Strings.MakeString(codeName);
- Data.Code.Add(code);
- }
- if ((Data?.GeneralInfo.BytecodeVersion > 14) && (Data.CodeLocals.ByName(codeName) == null))
- {
- UndertaleCodeLocals locals = new UndertaleCodeLocals();
- locals.Name = code.Name;
-
- UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar();
- argsLocal.Name = Data.Strings.MakeString("arguments");
- argsLocal.Index = 0;
-
- locals.Locals.Add(argsLocal);
-
- code.LocalsCount = 1;
- code.GenerateLocalVarDefinitions(code.FindReferencedLocalVars(), locals); // Dunno if we actually need this line, but it seems to work?
- Data.CodeLocals.Add(locals);
- }
- if (doParse)
- {
- // This portion links code.
- if (codeName.Substring(0, 10).Equals("gml_Script"))
- {
- // Add code to scripts section.
- if (Data.Scripts.ByName(codeName.Substring(11)) == null)
- {
- UndertaleScript scr = new UndertaleScript();
- scr.Name = Data.Strings.MakeString(codeName.Substring(11));
- scr.Code = code;
- Data.Scripts.Add(scr);
- }
- else
- {
- UndertaleScript scr = Data.Scripts.ByName(codeName.Substring(11));
- scr.Code = code;
- }
- }
- else if (codeName.Substring(0, 10).Equals("gml_Object"))
- {
- // Add code to object methods.
- string afterPrefix = codeName.Substring(11);
- // Dumb substring stuff, don't mess with this.
- int underCount = 0;
- string methodNumberStr = "", methodName = "", objName = "";
- for (int i = afterPrefix.Length - 1; i >= 0; i--)
- {
- if (afterPrefix[i] == '_')
- {
- underCount++;
- if (underCount == 1)
- {
- methodNumberStr = afterPrefix.Substring(i + 1);
- }
- else if (underCount == 2)
- {
- objName = afterPrefix.Substring(0, i);
- methodName = afterPrefix.Substring(i + 1, afterPrefix.Length - objName.Length - methodNumberStr.Length - 2);
- break;
- }
- }
- }
-
- int methodNumber = Int32.Parse(methodNumberStr);
- UndertaleGameObject obj = Data.GameObjects.ByName(objName);
- if (obj == null)
- {
- bool doNewObj = ScriptQuestion("Object " + objName + " was not found.\nAdd new object called " + objName + "?");
- if (doNewObj)
- {
- UndertaleGameObject gameObj = new UndertaleGameObject();
- gameObj.Name = Data.Strings.MakeString(objName);
- Data.GameObjects.Add(gameObj);
- }
- else
- {
- try
- {
- code.ReplaceGML(gmlCode, Data);
- }
- catch (Exception ex)
- {
- string errorMSG = "Error in " + codeName + ":\r\n" + ex.ToString() + "\r\nAborted";
- ScriptMessage(errorMSG);
- SetUMTConsoleText(errorMSG);
- SetFinishedMessage(false);
- return;
- }
- continue;
- }
- }
-
- obj = Data.GameObjects.ByName(objName);
- int eventIdx = (int)Enum.Parse(typeof(EventTypes), methodName);
-
- bool duplicate = false;
- try
- {
- foreach (UndertaleGameObject.Event evnt in obj.Events[eventIdx])
- {
- foreach (UndertaleGameObject.EventAction action in evnt.Actions)
- {
- if (action.CodeId.Name.Content == codeName)
- duplicate = true;
- }
- }
- }
- catch
- {
- //something went wrong, but probably because it's trying to check something non-existent
- //we're gonna make it so
- //keep going
- }
- if (duplicate == false)
- {
- UndertalePointerList eventList = obj.Events[eventIdx];
- UndertaleGameObject.EventAction action = new UndertaleGameObject.EventAction();
- UndertaleGameObject.Event evnt = new UndertaleGameObject.Event();
-
- action.ActionName = code.Name;
- action.CodeId = code;
- evnt.EventSubtype = (uint)methodNumber;
- evnt.Actions.Add(action);
- eventList.Add(evnt);
- }
- }
- // Code which does not match these criteria cannot link, but are still added to the code section.
- }
- else
- {
- try
- {
- code.ReplaceGML(gmlCode, Data);
- }
- catch (Exception ex)
- {
- string errorMSG = "Error in " + codeName + ":\r\n" + ex.ToString() + "\r\nAborted";
- ScriptMessage(errorMSG);
- SetUMTConsoleText(errorMSG);
- SetFinishedMessage(false);
- return;
- }
- }
- }
-});
-DisableAllSyncBindings();
-
-await StopProgressBarUpdater();
-HideProgressBar();
+// Script by Jockeholm based off of a script by Kneesnap.
+// Major help and edited by Samuel Roy
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using UndertaleModLib.Util;
+
+EnsureDataLoaded();
+
+bool is2_3 = false;
+if (!((Data.GMS2_3 == false) && (Data.GMS2_3_1 == false) && (Data.GMS2_3_2 == false)))
+{
+ is2_3 = true;
+ ScriptMessage("This script is for GMS 2.3 games code from \"ExportAllCode2_3.csx\", because some code names get so long that Windows cannot write them adequately.");
+}
+else
+{
+ ScriptError("Use the regular ImportGML please!", "Incompatible");
+}
+
+enum EventTypes
+{
+ Create,
+ Destroy,
+ Alarm,
+ Step,
+ Collision,
+ Keyboard,
+ Mouse,
+ Other,
+ Draw,
+ KeyPress,
+ KeyRelease,
+ Gesture,
+ Asynchronous,
+ PreCreate
+}
+
+// Check code directory.
+string importFolder = PromptChooseDirectory();
+if (importFolder == null)
+ throw new ScriptException("The import folder was not set.");
+
+List CodeList = new List();
+
+if (File.Exists(importFolder + "/LookUpTable.txt"))
+{
+ int counter = 0;
+ string line;
+ System.IO.StreamReader file = new System.IO.StreamReader(importFolder + "/" + "LookUpTable.txt");
+ while((line = file.ReadLine()) != null)
+ {
+ if (counter > 0)
+ CodeList.Add(line);
+ counter++;
+ }
+ file.Close();
+}
+else
+{
+ ScriptError("No LookUpTable.txt!", "Error");
+ return;
+}
+
+// Ask whether they want to link code. If no, will only generate code entry.
+// If yes, will try to add code to objects and scripts depending upon its name
+bool doParse = ScriptQuestion("Do you want to automatically attempt to link imported code?");
+
+string[] dirFiles = Directory.GetFiles(importFolder);
+bool skipGlobalScripts = true;
+bool skipGlobalScriptsPrompted = false;
+
+SetProgressBar(null, "Files", 0, dirFiles.Length);
+StartProgressBarUpdater();
+
+SyncBinding("Strings, Code, CodeLocals, Scripts, GlobalInitScripts, GameObjects, Functions, Variables", true);
+await Task.Run(() => {
+ foreach (string file in dirFiles)
+ {
+ IncrementProgress();
+
+ string fileName = Path.GetFileName(file);
+ if (!(fileName.EndsWith(".gml")))
+ continue;
+ fileName = Path.GetFileNameWithoutExtension(file);
+ int number;
+ bool success = Int32.TryParse(fileName, out number);
+ string codeName;
+ if (success)
+ {
+ codeName = CodeList[number];
+ fileName = codeName + ".gml";
+ }
+ else
+ {
+ ScriptError("GML file not in range of look up table!", "Error");
+ return;
+ }
+ if (fileName.EndsWith("PreCreate_0.gml") && (Data.GeneralInfo.Major < 2))
+ continue; // Restarts loop if file is not a valid code asset.
+ string gmlCode = File.ReadAllText(file);
+ if (codeName.Substring(0, 17).Equals("gml_GlobalScript_") && is2_3 && (!(skipGlobalScriptsPrompted)))
+ {
+ skipGlobalScriptsPrompted = true;
+ skipGlobalScripts = ScriptQuestion("Skip global scripts parsing?");
+ }
+ if (codeName.Substring(0, 17).Equals("gml_GlobalScript_") && is2_3 && ((skipGlobalScriptsPrompted)))
+ {
+ if (skipGlobalScripts)
+ continue;
+ }
+ UndertaleCode code = Data.Code.ByName(codeName);
+ if (code == null) // Should keep from adding duplicate scripts; haven't tested
+ {
+ code = new UndertaleCode();
+ code.Name = Data.Strings.MakeString(codeName);
+ Data.Code.Add(code);
+ }
+ if ((Data?.GeneralInfo.BytecodeVersion > 14) && (Data.CodeLocals.ByName(codeName) == null))
+ {
+ UndertaleCodeLocals locals = new UndertaleCodeLocals();
+ locals.Name = code.Name;
+
+ UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar();
+ argsLocal.Name = Data.Strings.MakeString("arguments");
+ argsLocal.Index = 0;
+
+ locals.Locals.Add(argsLocal);
+
+ code.LocalsCount = 1;
+ code.GenerateLocalVarDefinitions(code.FindReferencedLocalVars(), locals); // Dunno if we actually need this line, but it seems to work?
+ Data.CodeLocals.Add(locals);
+ }
+ if (doParse)
+ {
+ // This portion links code.
+ if (codeName.Substring(0, 10).Equals("gml_Script"))
+ {
+ // Add code to scripts section.
+ if (Data.Scripts.ByName(codeName.Substring(11)) == null)
+ {
+ UndertaleScript scr = new UndertaleScript();
+ scr.Name = Data.Strings.MakeString(codeName.Substring(11));
+ scr.Code = code;
+ Data.Scripts.Add(scr);
+ }
+ else
+ {
+ UndertaleScript scr = Data.Scripts.ByName(codeName.Substring(11));
+ scr.Code = code;
+ }
+ }
+ else if (codeName.Substring(0, 10).Equals("gml_Object"))
+ {
+ // Add code to object methods.
+ string afterPrefix = codeName.Substring(11);
+ // Dumb substring stuff, don't mess with this.
+ int underCount = 0;
+ string methodNumberStr = "", methodName = "", objName = "";
+ for (int i = afterPrefix.Length - 1; i >= 0; i--)
+ {
+ if (afterPrefix[i] == '_')
+ {
+ underCount++;
+ if (underCount == 1)
+ {
+ methodNumberStr = afterPrefix.Substring(i + 1);
+ }
+ else if (underCount == 2)
+ {
+ objName = afterPrefix.Substring(0, i);
+ methodName = afterPrefix.Substring(i + 1, afterPrefix.Length - objName.Length - methodNumberStr.Length - 2);
+ break;
+ }
+ }
+ }
+
+ int methodNumber = Int32.Parse(methodNumberStr);
+ UndertaleGameObject obj = Data.GameObjects.ByName(objName);
+ if (obj == null)
+ {
+ bool doNewObj = ScriptQuestion("Object " + objName + " was not found.\nAdd new object called " + objName + "?");
+ if (doNewObj)
+ {
+ UndertaleGameObject gameObj = new UndertaleGameObject();
+ gameObj.Name = Data.Strings.MakeString(objName);
+ Data.GameObjects.Add(gameObj);
+ }
+ else
+ {
+ try
+ {
+ code.ReplaceGML(gmlCode, Data);
+ }
+ catch (Exception ex)
+ {
+ string errorMSG = "Error in " + codeName + ":\r\n" + ex.ToString() + "\r\nAborted";
+ ScriptMessage(errorMSG);
+ SetUMTConsoleText(errorMSG);
+ SetFinishedMessage(false);
+ return;
+ }
+ continue;
+ }
+ }
+
+ obj = Data.GameObjects.ByName(objName);
+ int eventIdx = (int)Enum.Parse(typeof(EventTypes), methodName);
+
+ bool duplicate = false;
+ try
+ {
+ foreach (UndertaleGameObject.Event evnt in obj.Events[eventIdx])
+ {
+ foreach (UndertaleGameObject.EventAction action in evnt.Actions)
+ {
+ if (action.CodeId.Name.Content == codeName)
+ duplicate = true;
+ }
+ }
+ }
+ catch
+ {
+ //something went wrong, but probably because it's trying to check something non-existent
+ //we're gonna make it so
+ //keep going
+ }
+ if (duplicate == false)
+ {
+ UndertalePointerList eventList = obj.Events[eventIdx];
+ UndertaleGameObject.EventAction action = new UndertaleGameObject.EventAction();
+ UndertaleGameObject.Event evnt = new UndertaleGameObject.Event();
+
+ action.ActionName = code.Name;
+ action.CodeId = code;
+ evnt.EventSubtype = (uint)methodNumber;
+ evnt.Actions.Add(action);
+ eventList.Add(evnt);
+ }
+ }
+ // Code which does not match these criteria cannot link, but are still added to the code section.
+ }
+ else
+ {
+ try
+ {
+ code.ReplaceGML(gmlCode, Data);
+ }
+ catch (Exception ex)
+ {
+ string errorMSG = "Error in " + codeName + ":\r\n" + ex.ToString() + "\r\nAborted";
+ ScriptMessage(errorMSG);
+ SetUMTConsoleText(errorMSG);
+ SetFinishedMessage(false);
+ return;
+ }
+ }
+ }
+});
+DisableAllSyncBindings();
+
+await StopProgressBarUpdater();
+HideProgressBar();
ScriptMessage("All files successfully imported.");
\ No newline at end of file
diff --git a/UndertaleModTool/Repackers/ImportGraphics.csx b/UndertaleModTool/Repackers/ImportGraphics.csx
index c052cba55..087eca90d 100644
--- a/UndertaleModTool/Repackers/ImportGraphics.csx
+++ b/UndertaleModTool/Repackers/ImportGraphics.csx
@@ -1,620 +1,620 @@
-// Texture packer by Samuel Roy
-// Uses code from https://github.com/mfascia/TexturePacker
-
-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();
-
-bool importAsSprite = false;
-
-string importFolder = CheckValidity();
-
-string workDirectory = Path.GetDirectoryName(FilePath) + Path.DirectorySeparatorChar;
-string packDir = Path.Combine(workDirectory, "Packager");
-Directory.CreateDirectory(packDir);
-
-string sourcePath = importFolder;
-string searchPattern = "*.png";
-string outName = Path.Combine(packDir, "atlas.txt");
-int textureSize = 2048;
-int PaddingValue = 2;
-bool debug = false;
-Packer packer = new Packer();
-packer.Process(sourcePath, searchPattern, textureSize, PaddingValue, debug);
-packer.SaveAtlasses(outName);
-
-int lastTextPage = Data.EmbeddedTextures.Count - 1;
-int lastTextPageItem = Data.TexturePageItems.Count - 1;
-
-// Import everything into UMT
-string prefix = outName.Replace(Path.GetExtension(outName), "");
-int atlasCount = 0;
-foreach (Atlas atlas in packer.Atlasses)
-{
- string atlasName = Path.Combine(packDir, String.Format(prefix + "{0:000}" + ".png", atlasCount));
- Bitmap atlasBitmap = new Bitmap(atlasName);
- UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
- texture.Name = new UndertaleString("Texture " + ++lastTextPage);
- texture.TextureData.TextureBlob = File.ReadAllBytes(atlasName);
- Data.EmbeddedTextures.Add(texture);
- foreach (Node n in atlas.Nodes)
- {
- if (n.Texture != null)
- {
- // Initalize values of this texture
- UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
- texturePageItem.Name = new UndertaleString("PageItem " + ++lastTextPageItem);
- texturePageItem.SourceX = (ushort)n.Bounds.X;
- texturePageItem.SourceY = (ushort)n.Bounds.Y;
- texturePageItem.SourceWidth = (ushort)n.Bounds.Width;
- texturePageItem.SourceHeight = (ushort)n.Bounds.Height;
- texturePageItem.TargetX = 0;
- texturePageItem.TargetY = 0;
- texturePageItem.TargetWidth = (ushort)n.Bounds.Width;
- texturePageItem.TargetHeight = (ushort)n.Bounds.Height;
- texturePageItem.BoundingWidth = (ushort)n.Bounds.Width;
- texturePageItem.BoundingHeight = (ushort)n.Bounds.Height;
- texturePageItem.TexturePage = texture;
-
- // Add this texture to UMT
- Data.TexturePageItems.Add(texturePageItem);
-
- // String processing
- string stripped = Path.GetFileNameWithoutExtension(n.Texture.Source);
-
- SpriteType spriteType = GetSpriteType(n.Texture.Source);
-
- if (importAsSprite)
- {
- if ((spriteType == SpriteType.Unknown) || (spriteType == SpriteType.Font))
- {
- spriteType = SpriteType.Sprite;
- }
- }
-
- setTextureTargetBounds(texturePageItem, stripped, n);
-
-
- if (spriteType == SpriteType.Background)
- {
- UndertaleBackground background = Data.Backgrounds.ByName(stripped);
- if (background != null)
- {
- background.Texture = texturePageItem;
- }
- else
- {
- // No background found, let's make one
- UndertaleString backgroundUTString = Data.Strings.MakeString(stripped);
- UndertaleBackground newBackground = new UndertaleBackground();
- newBackground.Name = backgroundUTString;
- newBackground.Transparent = false;
- newBackground.Preload = false;
- newBackground.Texture = texturePageItem;
- Data.Backgrounds.Add(newBackground);
- }
- }
- else if (spriteType == SpriteType.Sprite)
- {
- // Get sprite to add this texture to
- string spriteName;
- int lastUnderscore, frame;
- try
- {
- lastUnderscore = stripped.LastIndexOf('_');
- spriteName = stripped.Substring(0, lastUnderscore);
- frame = Int32.Parse(stripped.Substring(lastUnderscore + 1));
- }
- catch (Exception e)
- {
- ScriptMessage("Error: Image " + stripped + " has an invalid name. Skipping...");
- continue;
- }
- UndertaleSprite sprite = null;
- sprite = Data.Sprites.ByName(spriteName);
-
- // Create TextureEntry object
- UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
- texentry.Texture = texturePageItem;
-
- // Set values for new sprites
- if (sprite == null)
- {
- UndertaleString spriteUTString = Data.Strings.MakeString(spriteName);
- UndertaleSprite newSprite = new UndertaleSprite();
- newSprite.Name = spriteUTString;
- newSprite.Width = (uint)n.Bounds.Width;
- newSprite.Height = (uint)n.Bounds.Height;
- newSprite.MarginLeft = 0;
- newSprite.MarginRight = n.Bounds.Width - 1;
- newSprite.MarginTop = 0;
- newSprite.MarginBottom = n.Bounds.Height - 1;
- newSprite.OriginX = 0;
- newSprite.OriginY = 0;
- if (frame > 0)
- {
- for (int i = 0; i < frame; i++)
- newSprite.Textures.Add(null);
- }
- newSprite.CollisionMasks.Add(newSprite.NewMaskEntry());
- Rectangle bmpRect = new Rectangle(n.Bounds.X, n.Bounds.Y, n.Bounds.Width, n.Bounds.Height);
- System.Drawing.Imaging.PixelFormat format = atlasBitmap.PixelFormat;
- Bitmap cloneBitmap = atlasBitmap.Clone(bmpRect, format);
- int width = ((n.Bounds.Width + 7) / 8) * 8;
- BitArray maskingBitArray = new BitArray(width * n.Bounds.Height);
- for (int y = 0; y < n.Bounds.Height; y++)
- {
- for (int x = 0; x < n.Bounds.Width; x++)
- {
- Color pixelColor = cloneBitmap.GetPixel(x, y);
- maskingBitArray[y * width + x] = (pixelColor.A > 0);
- }
- }
- BitArray tempBitArray = new BitArray(width * n.Bounds.Height);
- for (int i = 0; i < maskingBitArray.Length; i += 8)
- {
- for (int j = 0; j < 8; j++)
- {
- tempBitArray[j + i] = maskingBitArray[-(j - 7) + i];
- }
- }
- int numBytes;
- numBytes = maskingBitArray.Length / 8;
- byte[] bytes = new byte[numBytes];
- tempBitArray.CopyTo(bytes, 0);
- for (int i = 0; i < bytes.Length; i++)
- newSprite.CollisionMasks[0].Data[i] = bytes[i];
- newSprite.Textures.Add(texentry);
- Data.Sprites.Add(newSprite);
- continue;
- }
- if (frame > sprite.Textures.Count - 1)
- {
- while (frame > sprite.Textures.Count - 1)
- {
- sprite.Textures.Add(texentry);
- }
- continue;
- }
- sprite.Textures[frame] = texentry;
- }
- }
- }
- // Increment atlas
- atlasCount++;
-}
-
-HideProgressBar();
-ScriptMessage("Import Complete!");
-
-void setTextureTargetBounds(UndertaleTexturePageItem tex, string textureName, Node n)
-{
- tex.TargetX = 0;
- tex.TargetY = 0;
- tex.TargetWidth = (ushort)n.Bounds.Width;
- tex.TargetHeight = (ushort)n.Bounds.Height;
-}
-
-public class TextureInfo
-{
- public string Source;
- public int Width;
- public int Height;
-}
-
-public enum SpriteType
-{
- Sprite,
- Background,
- Font,
- Unknown
-}
-
-
-public enum SplitType
-{
- Horizontal,
- Vertical,
-}
-
-public enum BestFitHeuristic
-{
- Area,
- MaxOneAxis,
-}
-
-public class Node
-{
- public Rectangle Bounds;
- public TextureInfo Texture;
- public SplitType SplitType;
-}
-
-public class Atlas
-{
- public int Width;
- public int Height;
- public List Nodes;
-}
-
-public class Packer
-{
- public List SourceTextures;
- public StringWriter Log;
- public StringWriter Error;
- public int Padding;
- public int AtlasSize;
- public bool DebugMode;
- public BestFitHeuristic FitHeuristic;
- public List Atlasses;
-
- public Packer()
- {
- SourceTextures = new List();
- Log = new StringWriter();
- Error = new StringWriter();
- }
-
- public void Process(string _SourceDir, string _Pattern, int _AtlasSize, int _Padding, bool _DebugMode)
- {
- Padding = _Padding;
- AtlasSize = _AtlasSize;
- DebugMode = _DebugMode;
- //1: scan for all the textures we need to pack
- ScanForTextures(_SourceDir, _Pattern);
- List textures = new List();
- textures = SourceTextures.ToList();
- //2: generate as many atlasses as needed (with the latest one as small as possible)
- Atlasses = new List();
- while (textures.Count > 0)
- {
- Atlas atlas = new Atlas();
- atlas.Width = _AtlasSize;
- atlas.Height = _AtlasSize;
- List leftovers = LayoutAtlas(textures, atlas);
- if (leftovers.Count == 0)
- {
- // we reached the last atlas. Check if this last atlas could have been twice smaller
- while (leftovers.Count == 0)
- {
- atlas.Width /= 2;
- atlas.Height /= 2;
- leftovers = LayoutAtlas(textures, atlas);
- }
- // we need to go 1 step larger as we found the first size that is to small
- atlas.Width *= 2;
- atlas.Height *= 2;
- leftovers = LayoutAtlas(textures, atlas);
- }
- Atlasses.Add(atlas);
- textures = leftovers;
- }
- }
-
- public void SaveAtlasses(string _Destination)
- {
- int atlasCount = 0;
- string prefix = _Destination.Replace(Path.GetExtension(_Destination), "");
- string descFile = _Destination;
- StreamWriter tw = new StreamWriter(_Destination);
- tw.WriteLine("source_tex, atlas_tex, x, y, width, height");
- foreach (Atlas atlas in Atlasses)
- {
- string atlasName = String.Format(prefix + "{0:000}" + ".png", atlasCount);
- //1: Save images
- Image img = CreateAtlasImage(atlas);
- img.Save(atlasName, System.Drawing.Imaging.ImageFormat.Png);
- //2: save description in file
- foreach (Node n in atlas.Nodes)
- {
- if (n.Texture != null)
- {
- tw.Write(n.Texture.Source + ", ");
- tw.Write(atlasName + ", ");
- tw.Write((n.Bounds.X).ToString() + ", ");
- tw.Write((n.Bounds.Y).ToString() + ", ");
- tw.Write((n.Bounds.Width).ToString() + ", ");
- tw.WriteLine((n.Bounds.Height).ToString());
- }
- }
- ++atlasCount;
- }
- tw.Close();
- tw = new StreamWriter(prefix + ".log");
- tw.WriteLine("--- LOG -------------------------------------------");
- tw.WriteLine(Log.ToString());
- tw.WriteLine("--- ERROR -----------------------------------------");
- tw.WriteLine(Error.ToString());
- tw.Close();
- }
-
- private void ScanForTextures(string _Path, string _Wildcard)
- {
- DirectoryInfo di = new DirectoryInfo(_Path);
- FileInfo[] files = di.GetFiles(_Wildcard, SearchOption.AllDirectories);
- foreach (FileInfo fi in files)
- {
- Image img = Image.FromFile(fi.FullName);
- if (img != null)
- {
- if (img.Width <= AtlasSize && img.Height <= AtlasSize)
- {
- TextureInfo ti = new TextureInfo();
-
- ti.Source = fi.FullName;
- ti.Width = img.Width;
- ti.Height = img.Height;
-
- SourceTextures.Add(ti);
-
- Log.WriteLine("Added " + fi.FullName);
- }
- else
- {
- Error.WriteLine(fi.FullName + " is too large to fix in the atlas. Skipping!");
- }
- }
- }
- }
-
- private void HorizontalSplit(Node _ToSplit, int _Width, int _Height, List _List)
- {
- Node n1 = new Node();
- n1.Bounds.X = _ToSplit.Bounds.X + _Width + Padding;
- n1.Bounds.Y = _ToSplit.Bounds.Y;
- n1.Bounds.Width = _ToSplit.Bounds.Width - _Width - Padding;
- n1.Bounds.Height = _Height;
- n1.SplitType = SplitType.Vertical;
- Node n2 = new Node();
- n2.Bounds.X = _ToSplit.Bounds.X;
- n2.Bounds.Y = _ToSplit.Bounds.Y + _Height + Padding;
- n2.Bounds.Width = _ToSplit.Bounds.Width;
- n2.Bounds.Height = _ToSplit.Bounds.Height - _Height - Padding;
- n2.SplitType = SplitType.Horizontal;
- if (n1.Bounds.Width > 0 && n1.Bounds.Height > 0)
- _List.Add(n1);
- if (n2.Bounds.Width > 0 && n2.Bounds.Height > 0)
- _List.Add(n2);
- }
-
- private void VerticalSplit(Node _ToSplit, int _Width, int _Height, List _List)
- {
- Node n1 = new Node();
- n1.Bounds.X = _ToSplit.Bounds.X + _Width + Padding;
- n1.Bounds.Y = _ToSplit.Bounds.Y;
- n1.Bounds.Width = _ToSplit.Bounds.Width - _Width - Padding;
- n1.Bounds.Height = _ToSplit.Bounds.Height;
- n1.SplitType = SplitType.Vertical;
- Node n2 = new Node();
- n2.Bounds.X = _ToSplit.Bounds.X;
- n2.Bounds.Y = _ToSplit.Bounds.Y + _Height + Padding;
- n2.Bounds.Width = _Width;
- n2.Bounds.Height = _ToSplit.Bounds.Height - _Height - Padding;
- n2.SplitType = SplitType.Horizontal;
- if (n1.Bounds.Width > 0 && n1.Bounds.Height > 0)
- _List.Add(n1);
- if (n2.Bounds.Width > 0 && n2.Bounds.Height > 0)
- _List.Add(n2);
- }
-
- private TextureInfo FindBestFitForNode(Node _Node, List _Textures)
- {
- TextureInfo bestFit = null;
- float nodeArea = _Node.Bounds.Width * _Node.Bounds.Height;
- float maxCriteria = 0.0f;
- foreach (TextureInfo ti in _Textures)
- {
- switch (FitHeuristic)
- {
- // Max of Width and Height ratios
- case BestFitHeuristic.MaxOneAxis:
- if (ti.Width <= _Node.Bounds.Width && ti.Height <= _Node.Bounds.Height)
- {
- float wRatio = (float)ti.Width / (float)_Node.Bounds.Width;
- float hRatio = (float)ti.Height / (float)_Node.Bounds.Height;
- float ratio = wRatio > hRatio ? wRatio : hRatio;
- if (ratio > maxCriteria)
- {
- maxCriteria = ratio;
- bestFit = ti;
- }
- }
- break;
- // Maximize Area coverage
- case BestFitHeuristic.Area:
- if (ti.Width <= _Node.Bounds.Width && ti.Height <= _Node.Bounds.Height)
- {
- float textureArea = ti.Width * ti.Height;
- float coverage = textureArea / nodeArea;
- if (coverage > maxCriteria)
- {
- maxCriteria = coverage;
- bestFit = ti;
- }
- }
- break;
- }
- }
- return bestFit;
- }
-
- private List LayoutAtlas(List _Textures, Atlas _Atlas)
- {
- List freeList = new List();
- List textures = new List();
- _Atlas.Nodes = new List();
- textures = _Textures.ToList();
- Node root = new Node();
- root.Bounds.Size = new Size(_Atlas.Width, _Atlas.Height);
- root.SplitType = SplitType.Horizontal;
- freeList.Add(root);
- while (freeList.Count > 0 && textures.Count > 0)
- {
- Node node = freeList[0];
- freeList.RemoveAt(0);
- TextureInfo bestFit = FindBestFitForNode(node, textures);
- if (bestFit != null)
- {
- if (node.SplitType == SplitType.Horizontal)
- {
- HorizontalSplit(node, bestFit.Width, bestFit.Height, freeList);
- }
- else
- {
- VerticalSplit(node, bestFit.Width, bestFit.Height, freeList);
- }
- node.Texture = bestFit;
- node.Bounds.Width = bestFit.Width;
- node.Bounds.Height = bestFit.Height;
- textures.Remove(bestFit);
- }
- _Atlas.Nodes.Add(node);
- }
- return textures;
- }
-
- private Image CreateAtlasImage(Atlas _Atlas)
- {
- Image img = new Bitmap(_Atlas.Width, _Atlas.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- Graphics g = Graphics.FromImage(img);
- foreach (Node n in _Atlas.Nodes)
- {
- if (n.Texture != null)
- {
- Image sourceImg = Image.FromFile(n.Texture.Source);
- g.DrawImage(sourceImg, n.Bounds);
- }
- }
- // DPI FIX START
- Bitmap ResolutionFix = new Bitmap(img);
- ResolutionFix.SetResolution(96.0F, 96.0F);
- Image img2 = ResolutionFix;
- return img2;
- // DPI FIX END
- }
-}
-
-SpriteType GetSpriteType(string path)
-{
- string folderPath = Path.GetDirectoryName(path);
- string folderName = new DirectoryInfo(folderPath).Name;
- string lowerName = folderName.ToLower();
-
- if (lowerName == "backgrounds" || lowerName == "background")
- {
- return SpriteType.Background;
- }
- else if (lowerName == "fonts" || lowerName == "font")
- {
- return SpriteType.Font;
- }
- else if (lowerName == "sprites" || lowerName == "sprite")
- {
- return SpriteType.Sprite;
- }
- return SpriteType.Unknown;
-}
-
-string CheckValidity()
-{
- bool recursiveCheck = ScriptQuestion(@"This script imports all sprites in all subdirectories recursively.
-If an image file is in a folder named ""Backgrounds"", then the image will be imported as a background.
-Otherwise, the image will be imported as a sprite.
-Do you want to continue?");
- if (!recursiveCheck)
- throw new ScriptException("Script cancelled.");
-
- // Get import folder
- string importFolder = PromptChooseDirectory("Import From Where");
- if (importFolder == null)
- throw new ScriptException("The import folder was not set.");
-
- //Stop the script if there's missing sprite entries or w/e.
- bool hadMessage = false;
- string[] dirFiles = Directory.GetFiles(importFolder, "*.png", SearchOption.AllDirectories);
- foreach (string file in dirFiles)
- {
- string FileNameWithExtension = Path.GetFileName(file);
- string stripped = Path.GetFileNameWithoutExtension(file);
- int lastUnderscore = stripped.LastIndexOf('_');
- string spriteName = "";
-
- SpriteType spriteType = GetSpriteType(file);
-
- if ((spriteType != SpriteType.Sprite) && (spriteType != SpriteType.Background))
- {
- if (!hadMessage)
- {
- hadMessage = true;
- importAsSprite = ScriptQuestion(FileNameWithExtension + @" is in an incorrectly-named folder (valid names being ""Sprites"" and ""Backgrounds""). Would you like to import these images as sprites?
-Pressing ""No"" will cause the program to ignore these images.");
- }
-
- if (!importAsSprite)
- {
- continue;
- }
- else
- {
- spriteType = SpriteType.Sprite;
- }
- }
-
- // Check for duplicate filenames
- string[] dupFiles = Directory.GetFiles(importFolder, FileNameWithExtension, SearchOption.AllDirectories);
- if (dupFiles.Length > 1)
- throw new ScriptException("Duplicate file detected. There are " + dupFiles.Length + " files named: " + FileNameWithExtension);
-
- // Sprites can have multiple frames! Do some sprite-specific checking.
- if (spriteType == SpriteType.Sprite)
- {
- try
- {
- spriteName = stripped.Substring(0, lastUnderscore);
- }
- catch
- {
- throw new ScriptException("Getting the sprite name of " + FileNameWithExtension + " failed.");
- }
- Int32 validFrameNumber = 0;
- try
- {
- validFrameNumber = Int32.Parse(stripped.Substring(lastUnderscore + 1));
- }
- catch
- {
- throw new ScriptException("The index of " + FileNameWithExtension + " could not be determined.");
- }
- int frame = 0;
- try
- {
- frame = Int32.Parse(stripped.Substring(lastUnderscore + 1));
- }
- catch
- {
- throw new ScriptException(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 ScriptException(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, SearchOption.AllDirectories);
- if (previousFrameFiles.Length < 1)
- throw new ScriptException(spriteName + " is missing one or more indexes. The detected missing index is: " + prevFrameName);
- }
- }
- return importFolder;
-}
+// Texture packer by Samuel Roy
+// Uses code from https://github.com/mfascia/TexturePacker
+
+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();
+
+bool importAsSprite = false;
+
+string importFolder = CheckValidity();
+
+string workDirectory = Path.GetDirectoryName(FilePath) + Path.DirectorySeparatorChar;
+string packDir = Path.Combine(workDirectory, "Packager");
+Directory.CreateDirectory(packDir);
+
+string sourcePath = importFolder;
+string searchPattern = "*.png";
+string outName = Path.Combine(packDir, "atlas.txt");
+int textureSize = 2048;
+int PaddingValue = 2;
+bool debug = false;
+Packer packer = new Packer();
+packer.Process(sourcePath, searchPattern, textureSize, PaddingValue, debug);
+packer.SaveAtlasses(outName);
+
+int lastTextPage = Data.EmbeddedTextures.Count - 1;
+int lastTextPageItem = Data.TexturePageItems.Count - 1;
+
+// Import everything into UMT
+string prefix = outName.Replace(Path.GetExtension(outName), "");
+int atlasCount = 0;
+foreach (Atlas atlas in packer.Atlasses)
+{
+ string atlasName = Path.Combine(packDir, String.Format(prefix + "{0:000}" + ".png", atlasCount));
+ Bitmap atlasBitmap = new Bitmap(atlasName);
+ UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
+ texture.Name = new UndertaleString("Texture " + ++lastTextPage);
+ texture.TextureData.TextureBlob = File.ReadAllBytes(atlasName);
+ Data.EmbeddedTextures.Add(texture);
+ foreach (Node n in atlas.Nodes)
+ {
+ if (n.Texture != null)
+ {
+ // Initalize values of this texture
+ UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
+ texturePageItem.Name = new UndertaleString("PageItem " + ++lastTextPageItem);
+ texturePageItem.SourceX = (ushort)n.Bounds.X;
+ texturePageItem.SourceY = (ushort)n.Bounds.Y;
+ texturePageItem.SourceWidth = (ushort)n.Bounds.Width;
+ texturePageItem.SourceHeight = (ushort)n.Bounds.Height;
+ texturePageItem.TargetX = 0;
+ texturePageItem.TargetY = 0;
+ texturePageItem.TargetWidth = (ushort)n.Bounds.Width;
+ texturePageItem.TargetHeight = (ushort)n.Bounds.Height;
+ texturePageItem.BoundingWidth = (ushort)n.Bounds.Width;
+ texturePageItem.BoundingHeight = (ushort)n.Bounds.Height;
+ texturePageItem.TexturePage = texture;
+
+ // Add this texture to UMT
+ Data.TexturePageItems.Add(texturePageItem);
+
+ // String processing
+ string stripped = Path.GetFileNameWithoutExtension(n.Texture.Source);
+
+ SpriteType spriteType = GetSpriteType(n.Texture.Source);
+
+ if (importAsSprite)
+ {
+ if ((spriteType == SpriteType.Unknown) || (spriteType == SpriteType.Font))
+ {
+ spriteType = SpriteType.Sprite;
+ }
+ }
+
+ setTextureTargetBounds(texturePageItem, stripped, n);
+
+
+ if (spriteType == SpriteType.Background)
+ {
+ UndertaleBackground background = Data.Backgrounds.ByName(stripped);
+ if (background != null)
+ {
+ background.Texture = texturePageItem;
+ }
+ else
+ {
+ // No background found, let's make one
+ UndertaleString backgroundUTString = Data.Strings.MakeString(stripped);
+ UndertaleBackground newBackground = new UndertaleBackground();
+ newBackground.Name = backgroundUTString;
+ newBackground.Transparent = false;
+ newBackground.Preload = false;
+ newBackground.Texture = texturePageItem;
+ Data.Backgrounds.Add(newBackground);
+ }
+ }
+ else if (spriteType == SpriteType.Sprite)
+ {
+ // Get sprite to add this texture to
+ string spriteName;
+ int lastUnderscore, frame;
+ try
+ {
+ lastUnderscore = stripped.LastIndexOf('_');
+ spriteName = stripped.Substring(0, lastUnderscore);
+ frame = Int32.Parse(stripped.Substring(lastUnderscore + 1));
+ }
+ catch (Exception e)
+ {
+ ScriptMessage("Error: Image " + stripped + " has an invalid name. Skipping...");
+ continue;
+ }
+ UndertaleSprite sprite = null;
+ sprite = Data.Sprites.ByName(spriteName);
+
+ // Create TextureEntry object
+ UndertaleSprite.TextureEntry texentry = new UndertaleSprite.TextureEntry();
+ texentry.Texture = texturePageItem;
+
+ // Set values for new sprites
+ if (sprite == null)
+ {
+ UndertaleString spriteUTString = Data.Strings.MakeString(spriteName);
+ UndertaleSprite newSprite = new UndertaleSprite();
+ newSprite.Name = spriteUTString;
+ newSprite.Width = (uint)n.Bounds.Width;
+ newSprite.Height = (uint)n.Bounds.Height;
+ newSprite.MarginLeft = 0;
+ newSprite.MarginRight = n.Bounds.Width - 1;
+ newSprite.MarginTop = 0;
+ newSprite.MarginBottom = n.Bounds.Height - 1;
+ newSprite.OriginX = 0;
+ newSprite.OriginY = 0;
+ if (frame > 0)
+ {
+ for (int i = 0; i < frame; i++)
+ newSprite.Textures.Add(null);
+ }
+ newSprite.CollisionMasks.Add(newSprite.NewMaskEntry());
+ Rectangle bmpRect = new Rectangle(n.Bounds.X, n.Bounds.Y, n.Bounds.Width, n.Bounds.Height);
+ System.Drawing.Imaging.PixelFormat format = atlasBitmap.PixelFormat;
+ Bitmap cloneBitmap = atlasBitmap.Clone(bmpRect, format);
+ int width = ((n.Bounds.Width + 7) / 8) * 8;
+ BitArray maskingBitArray = new BitArray(width * n.Bounds.Height);
+ for (int y = 0; y < n.Bounds.Height; y++)
+ {
+ for (int x = 0; x < n.Bounds.Width; x++)
+ {
+ Color pixelColor = cloneBitmap.GetPixel(x, y);
+ maskingBitArray[y * width + x] = (pixelColor.A > 0);
+ }
+ }
+ BitArray tempBitArray = new BitArray(width * n.Bounds.Height);
+ for (int i = 0; i < maskingBitArray.Length; i += 8)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ tempBitArray[j + i] = maskingBitArray[-(j - 7) + i];
+ }
+ }
+ int numBytes;
+ numBytes = maskingBitArray.Length / 8;
+ byte[] bytes = new byte[numBytes];
+ tempBitArray.CopyTo(bytes, 0);
+ for (int i = 0; i < bytes.Length; i++)
+ newSprite.CollisionMasks[0].Data[i] = bytes[i];
+ newSprite.Textures.Add(texentry);
+ Data.Sprites.Add(newSprite);
+ continue;
+ }
+ if (frame > sprite.Textures.Count - 1)
+ {
+ while (frame > sprite.Textures.Count - 1)
+ {
+ sprite.Textures.Add(texentry);
+ }
+ continue;
+ }
+ sprite.Textures[frame] = texentry;
+ }
+ }
+ }
+ // Increment atlas
+ atlasCount++;
+}
+
+HideProgressBar();
+ScriptMessage("Import Complete!");
+
+void setTextureTargetBounds(UndertaleTexturePageItem tex, string textureName, Node n)
+{
+ tex.TargetX = 0;
+ tex.TargetY = 0;
+ tex.TargetWidth = (ushort)n.Bounds.Width;
+ tex.TargetHeight = (ushort)n.Bounds.Height;
+}
+
+public class TextureInfo
+{
+ public string Source;
+ public int Width;
+ public int Height;
+}
+
+public enum SpriteType
+{
+ Sprite,
+ Background,
+ Font,
+ Unknown
+}
+
+
+public enum SplitType
+{
+ Horizontal,
+ Vertical,
+}
+
+public enum BestFitHeuristic
+{
+ Area,
+ MaxOneAxis,
+}
+
+public class Node
+{
+ public Rectangle Bounds;
+ public TextureInfo Texture;
+ public SplitType SplitType;
+}
+
+public class Atlas
+{
+ public int Width;
+ public int Height;
+ public List