diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 6f71acf9..19ec69e6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,9 +1,6 @@ name: .NET -on: - pull_request: - push: - branches: [ "main" ] +on: [push, pull_request] jobs: build: diff --git a/MinecraftUSkinEditor/Classes/FileTypes/PCKAudioFile.cs b/MinecraftUSkinEditor/Classes/FileTypes/PCKAudioFile.cs new file mode 100644 index 00000000..43ea24b4 --- /dev/null +++ b/MinecraftUSkinEditor/Classes/FileTypes/PCKAudioFile.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Classes.FileTypes +{ + public class PCKAudioFile + { + public class InvalidCategoryException : Exception + { + public InvalidCategoryException(string message) : base(message) + { } + } + + public readonly int type = 1; + + public AudioCategory[] Categories => Array.FindAll(_categories, c => c is not null); + private AudioCategory[] _categories { get; } = new AudioCategory[9]; + + public Dictionary Credits { get; } = new Dictionary(); + + public class AudioCategory + { + public enum EAudioType : int + { + Overworld, + Nether, + End, + Creative, + Menu, + Battle, + Tumble, + Glide, + Unused, + } + + public enum EAudioParameterType : int + { + unk0, // dimension music + unk1, // unused music ? + } + + public string Name { get; set; } = string.Empty; + public EAudioParameterType parameterType { get; } + public EAudioType audioType { get; } + public List SongNames { get; } = new List(); + + public AudioCategory(string name, EAudioParameterType parameterType, EAudioType audioType) + { + this.Name = name; + this.parameterType = parameterType; + this.audioType = audioType; + } + } + + public string[] GetCredits() => Credits.Values.ToArray(); + public string GetCreditsString() => string.Join("\n", Credits.Values.ToArray()); + + public void AddCredits(params string[] credits) + { + foreach (var credit in credits) + { + AddCredit(credit); + } + } + + /// + /// Applies internal Credits to loc file + /// + public void ApplyCredits(LOCFile locFile) + { + foreach (var credit in Credits) + { + locFile.SetLocEntry(credit.Key, credit.Value); + } + } + + /// + /// Clears and sets the new supplied + /// + public void SetCredits(params string[] credits) + { + Credits.Clear(); + foreach (var credit in credits) + { + AddCredit(credit); + } + } + + public bool SetCredit(string creditId, string s) + { + if (!Credits.ContainsKey(creditId)) + return false; + Credits[creditId] = s; + return true; + } + + public void AddCredit(string credit) + { + Credits.Add($"IDS_CREDIT{(Credits.Count > 0 ? $"_{Credits.Count+1}" : string.Empty)}", credit); + } + + public void AddCreditId(string creditId) => Credits.Add(creditId, string.Empty); + + + /// + public bool HasCategory(AudioCategory.EAudioType category) => GetCategory(category) is AudioCategory; + + /// + public AudioCategory GetCategory(AudioCategory.EAudioType category) + { + if (category < AudioCategory.EAudioType.Overworld || + category > AudioCategory.EAudioType.Unused) + throw new InvalidCategoryException(nameof(category)); + return _categories[(int)category]; + } + + /// + public bool TryGetCategory(AudioCategory.EAudioType category, out AudioCategory audioCategory) + { + if (GetCategory(category) is AudioCategory a) + { + audioCategory = a; + return true; + } + audioCategory = null; + return false; + } + + /// True when category was created, otherwise false + /// + public bool AddCategory(AudioCategory.EAudioParameterType parameterType, AudioCategory.EAudioType category, string name = "") + { + if (category < AudioCategory.EAudioType.Overworld || + category > AudioCategory.EAudioType.Unused) + throw new InvalidCategoryException(nameof(category)); + bool exists = HasCategory(category); + if (!exists) _categories[(int)category] = new AudioCategory(name, parameterType, category); + return !exists; + } + + /// True when category was created, otherwise false + /// + public bool AddCategory(AudioCategory.EAudioType category) + => AddCategory(AudioCategory.EAudioParameterType.unk0, category); + + /// True when category was removed, otherwise false + /// + public bool RemoveCategory(AudioCategory.EAudioType category) + { + bool exists = HasCategory(category); + if (exists) _categories[(int)category] = null; + return exists; + } + + } +} diff --git a/MinecraftUSkinEditor/Classes/IO/PCK/PCKAudioFileReader.cs b/MinecraftUSkinEditor/Classes/IO/PCK/PCKAudioFileReader.cs new file mode 100644 index 00000000..8b704a0a --- /dev/null +++ b/MinecraftUSkinEditor/Classes/IO/PCK/PCKAudioFileReader.cs @@ -0,0 +1,117 @@ +using PckStudio.Classes.FileTypes; +using PckStudio.Classes.Utils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Classes.IO.PCK +{ + + public class InvalidAudioPckException : Exception + { + public InvalidAudioPckException(string message) : base(message) + { } + } + + internal class PCKAudioFileReader : StreamDataReader + { + private PCKAudioFile _file; + private List LUT = new List(); + + + public static PCKAudioFile Read(Stream stream, bool isLittleEndian) + { + return new PCKAudioFileReader(isLittleEndian).ReadFromStream(stream); + } + + private PCKAudioFileReader(bool isLittleEndian) : base(isLittleEndian) + { + } + + private PCKAudioFile ReadFromStream(Stream stream) + { + int pck_type = ReadInt(stream); + if (pck_type > 0xf00000) // 03 00 00 00 == true + throw new OverflowException(nameof(pck_type)); + if (pck_type > 1) + throw new InvalidAudioPckException(nameof(pck_type)); + _file = new PCKAudioFile(); + ReadLookUpTabel(stream); + ReadCategories(stream); + ReadCategorySongs(stream); + return _file; + } + + private void ReadLookUpTabel(Stream stream) + { + int count = ReadInt(stream); + LUT = new List(count); + for (int i = 0; i < count; i++) + { + int index = ReadInt(stream); + LUT.Insert(index, ReadString(stream)); + } + } + + private List original_audio_types = new List(); + private void ReadCategories(Stream stream) + { + int categoryEntryCount = ReadInt(stream); + for (; 0 < categoryEntryCount; categoryEntryCount--) + { + var parameterType = (PCKAudioFile.AudioCategory.EAudioParameterType)ReadInt(stream); + var audioType = (PCKAudioFile.AudioCategory.EAudioType)ReadInt(stream); + string name = ReadString(stream); + // AddCategory puts the file's categories out of order and causes some songs to be put in the wrong categories + // This is my simple fix for the issue. + original_audio_types.Add(audioType); + _file.AddCategory(parameterType, audioType, name); + } + } + + private void ReadCategorySongs(Stream stream) + { + List credits = new List(); + List creditIds = new List(); + foreach (var c in original_audio_types) + { + int audioCount = ReadInt(stream); + for (; 0 < audioCount; audioCount--) + { + string key = LUT[ReadInt(stream)]; + string value = ReadString(stream); + switch (key) + { + case "CUENAME": + _file.GetCategory(c).SongNames.Add(value); + break; + case "CREDIT": + credits.Add(value); + break; + case "CREDITID": + creditIds.Add(value); + _file.AddCreditId(value); + break; + default: + throw new InvalidDataException(nameof(key)); + } + } + }; + foreach (var credit in credits.Zip(creditIds, (str, id) => (str, id))) + { + _file.SetCredit(credit.id, credit.str); + } + } + + private string ReadString(Stream stream) + { + int len = ReadInt(stream); + string s = ReadString(stream, len, IsUsingLittleEndian ? Encoding.Unicode : Encoding.BigEndianUnicode); + ReadInt(stream); // padding + return s; + } + } +} diff --git a/MinecraftUSkinEditor/Classes/IO/PCK/PCKAudioFileWriter.cs b/MinecraftUSkinEditor/Classes/IO/PCK/PCKAudioFileWriter.cs new file mode 100644 index 00000000..18628ec4 --- /dev/null +++ b/MinecraftUSkinEditor/Classes/IO/PCK/PCKAudioFileWriter.cs @@ -0,0 +1,94 @@ +using PckStudio.Classes.FileTypes; +using PckStudio.Classes.Utils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Classes.IO.PCK +{ + internal class PCKAudioFileWriter : StreamDataWriter + { + + private PCKAudioFile _file; + private static readonly List LUT = new List + { + "CUENAME", + "CREDIT", + "CREDITID" + }; + + public static void Write(Stream stream, PCKAudioFile file, bool isLittleEndian) + { + new PCKAudioFileWriter(file, isLittleEndian).WriteToStream(stream); + } + + private PCKAudioFileWriter(PCKAudioFile file, bool isLittleEndian) : base(isLittleEndian) + { + _file = file; + } + + private void WriteToStream(Stream stream) + { + WriteInt(stream, _file.type); + WriteLookUpTable(stream); + WriteCategories(stream); + WriteCategorySongs(stream); + } + + private void WriteString(Stream stream, string s) + { + WriteInt(stream, s.Length); + WriteString(stream, s, IsUsingLittleEndian ? Encoding.Unicode : Encoding.BigEndianUnicode); + WriteInt(stream, 0); // padding + } + + private void WriteLookUpTable(Stream stream) + { + WriteInt(stream, 3); + for (int i = 0; i < 3; i++) + { + WriteInt(stream, i); + WriteString(stream, LUT[i]); + } + } + + private void WriteCategories(Stream stream) + { + WriteInt(stream, _file.Categories.Length); + foreach (var category in _file.Categories) + { + WriteInt(stream, (int)category.parameterType); + WriteInt(stream, (int)category.audioType); + WriteString(stream, category.Name); + } + } + + private void WriteCategorySongs(Stream stream) + { + bool addCredit = true; + foreach (var category in _file.Categories) + { + WriteInt(stream, category.SongNames.Count + (addCredit ? _file.Credits.Count * 2 : 0)); + foreach (var name in category.SongNames) + { + WriteInt(stream, LUT.IndexOf("CUENAME")); + WriteString(stream, name); + } + if (addCredit) + { + foreach (var credit in _file.Credits) + { + WriteInt(stream, LUT.IndexOf("CREDIT")); + WriteString(stream, credit.Value); + WriteInt(stream, LUT.IndexOf("CREDITID")); + WriteString(stream, credit.Key); + } + } + addCredit = false; + } + } + } +} diff --git a/MinecraftUSkinEditor/Classes/IO/Sounds/SoundIO.cs b/MinecraftUSkinEditor/Classes/IO/Sounds/SoundIO.cs new file mode 100644 index 00000000..5815d356 --- /dev/null +++ b/MinecraftUSkinEditor/Classes/IO/Sounds/SoundIO.cs @@ -0,0 +1,26 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace PckStudio.Classes.IO.Sounds +{ + public class SoundIO + { + public Dictionary Read(string Filepath) + { + var jObj = (Newtonsoft.Json.Linq.JObject)JsonConvert.DeserializeObject(File.ReadAllText(Filepath)); + var dict = JsonConvert.DeserializeObject>(jObj.ToString()); + + return dict; + } + + public string Serialize(Dictionary input) + { + return JsonConvert.SerializeObject(input, Formatting.Indented); + } + } +} diff --git a/MinecraftUSkinEditor/Classes/IO/Sounds/Sounds.cs b/MinecraftUSkinEditor/Classes/IO/Sounds/Sounds.cs new file mode 100644 index 00000000..a040eff3 --- /dev/null +++ b/MinecraftUSkinEditor/Classes/IO/Sounds/Sounds.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Classes.IO.Sounds +{ + public class Type + { + public bool replace { get; set; } + public List sounds = new List(); + } + + public class Sound + { + public string name { get; set; } + public string type { get; set; } + public bool stream { get; set; } + } +} diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/addCategory.Designer.cs b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/addCategory.Designer.cs similarity index 98% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/addCategory.Designer.cs rename to MinecraftUSkinEditor/Forms/Additional-Popups/Audio/addCategory.Designer.cs index 225e34bb..cb7dbe12 100644 --- a/MinecraftUSkinEditor/Forms/Utilities/Audio/addCategory.Designer.cs +++ b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/addCategory.Designer.cs @@ -1,4 +1,4 @@ -namespace PckStudio +namespace PckStudio.Forms.Additional_Popups.Audio { partial class addCategory { diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/addCategory.cs b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/addCategory.cs similarity index 94% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/addCategory.cs rename to MinecraftUSkinEditor/Forms/Additional-Popups/Audio/addCategory.cs index e0030883..aecd9c6b 100644 --- a/MinecraftUSkinEditor/Forms/Utilities/Audio/addCategory.cs +++ b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/addCategory.cs @@ -10,7 +10,7 @@ using System.Windows.Forms; // Audio Editor by MattNL -namespace PckStudio +namespace PckStudio.Forms.Additional_Popups.Audio { public partial class addCategory : MetroFramework.Forms.MetroForm { diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/addCategory.resx b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/addCategory.resx similarity index 100% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/addCategory.resx rename to MinecraftUSkinEditor/Forms/Additional-Popups/Audio/addCategory.resx diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/creditsEditor.Designer.cs b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/creditsEditor.Designer.cs similarity index 98% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/creditsEditor.Designer.cs rename to MinecraftUSkinEditor/Forms/Additional-Popups/Audio/creditsEditor.Designer.cs index 9287ccd5..72ab8658 100644 --- a/MinecraftUSkinEditor/Forms/Utilities/Audio/creditsEditor.Designer.cs +++ b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/creditsEditor.Designer.cs @@ -1,4 +1,4 @@ -namespace PckStudio +namespace PckStudio.Forms.Additional_Popups.Audio { partial class creditsEditor { diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/creditsEditor.cs b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/creditsEditor.cs similarity index 92% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/creditsEditor.cs rename to MinecraftUSkinEditor/Forms/Additional-Popups/Audio/creditsEditor.cs index 8503a1b9..c769d246 100644 --- a/MinecraftUSkinEditor/Forms/Utilities/Audio/creditsEditor.cs +++ b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/creditsEditor.cs @@ -10,7 +10,7 @@ using System.Windows.Forms; // Audio Editor by MattNL -namespace PckStudio +namespace PckStudio.Forms.Additional_Popups.Audio { public partial class creditsEditor : MetroFramework.Forms.MetroForm { diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/creditsEditor.resx b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/creditsEditor.resx similarity index 100% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/creditsEditor.resx rename to MinecraftUSkinEditor/Forms/Additional-Popups/Audio/creditsEditor.resx diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/pleaseWait.Designer.cs b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/pleaseWait.Designer.cs similarity index 97% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/pleaseWait.Designer.cs rename to MinecraftUSkinEditor/Forms/Additional-Popups/Audio/pleaseWait.Designer.cs index 9b76cde6..3e8cd5fd 100644 --- a/MinecraftUSkinEditor/Forms/Utilities/Audio/pleaseWait.Designer.cs +++ b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/pleaseWait.Designer.cs @@ -1,4 +1,4 @@ -namespace PckStudio.Forms.Utilities.Audio +namespace PckStudio.Forms.Additional_Popups.Audio { partial class pleaseWait { diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/pleaseWait.cs b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/pleaseWait.cs similarity index 87% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/pleaseWait.cs rename to MinecraftUSkinEditor/Forms/Additional-Popups/Audio/pleaseWait.cs index 1c351e45..23fe5fcd 100644 --- a/MinecraftUSkinEditor/Forms/Utilities/Audio/pleaseWait.cs +++ b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/pleaseWait.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using System.Windows.Forms; using MetroFramework.Forms; -namespace PckStudio.Forms.Utilities.Audio +namespace PckStudio.Forms.Additional_Popups.Audio { public partial class pleaseWait : MetroForm { diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/pleaseWait.resx b/MinecraftUSkinEditor/Forms/Additional-Popups/Audio/pleaseWait.resx similarity index 100% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/pleaseWait.resx rename to MinecraftUSkinEditor/Forms/Additional-Popups/Audio/pleaseWait.resx diff --git a/MinecraftUSkinEditor/Forms/Additional-Popups/Grf/AddParameter.Designer.cs b/MinecraftUSkinEditor/Forms/Additional-Popups/Grf/AddParameter.Designer.cs index 5f33767f..0e4fac52 100644 --- a/MinecraftUSkinEditor/Forms/Additional-Popups/Grf/AddParameter.Designer.cs +++ b/MinecraftUSkinEditor/Forms/Additional-Popups/Grf/AddParameter.Designer.cs @@ -1,4 +1,4 @@ -namespace PckStudio.Forms.Utilities.Grf +namespace PckStudio.Forms.Additional_Popups.Grf { partial class AddParameter { diff --git a/MinecraftUSkinEditor/Forms/Additional-Popups/Grf/AddParameter.cs b/MinecraftUSkinEditor/Forms/Additional-Popups/Grf/AddParameter.cs index 322fdf44..6a7c2252 100644 --- a/MinecraftUSkinEditor/Forms/Additional-Popups/Grf/AddParameter.cs +++ b/MinecraftUSkinEditor/Forms/Additional-Popups/Grf/AddParameter.cs @@ -8,7 +8,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -namespace PckStudio.Forms.Utilities.Grf +namespace PckStudio.Forms.Additional_Popups.Grf { public partial class AddParameter : MetroFramework.Forms.MetroForm { diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/AudioEditor.Designer.cs b/MinecraftUSkinEditor/Forms/Editor/AudioEditor.Designer.cs similarity index 98% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/AudioEditor.Designer.cs rename to MinecraftUSkinEditor/Forms/Editor/AudioEditor.Designer.cs index 024a9c19..6d84aeb7 100644 --- a/MinecraftUSkinEditor/Forms/Utilities/Audio/AudioEditor.Designer.cs +++ b/MinecraftUSkinEditor/Forms/Editor/AudioEditor.Designer.cs @@ -1,5 +1,5 @@  -namespace PckStudio.Forms.Utilities +namespace PckStudio.Forms.Editor { partial class AudioEditor { @@ -63,6 +63,7 @@ namespace PckStudio.Forms.Utilities this.treeView1.LabelEdit = true; this.treeView1.Name = "treeView1"; this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect); + this.treeView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeView1_KeyDown); // // contextMenuStrip1 // @@ -121,7 +122,6 @@ namespace PckStudio.Forms.Utilities // resources.ApplyResources(this.saveToolStripMenuItem1, "saveToolStripMenuItem1"); this.saveToolStripMenuItem1.Name = "saveToolStripMenuItem1"; - this.saveToolStripMenuItem1.Click += new System.EventHandler(this.saveToolStripMenuItem1_Click); // // toolsToolStripMenuItem // diff --git a/MinecraftUSkinEditor/Forms/Editor/AudioEditor.cs b/MinecraftUSkinEditor/Forms/Editor/AudioEditor.cs new file mode 100644 index 00000000..cbf8e8bd --- /dev/null +++ b/MinecraftUSkinEditor/Forms/Editor/AudioEditor.cs @@ -0,0 +1,428 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Diagnostics; +using MetroFramework.Forms; +using System.Collections; +using PckStudio.Classes.FileTypes; +using PckStudio.Classes.IO.PCK; +using PckStudio.Forms.Additional_Popups.Audio; + +// Audio Editor by MattNL +// additional work and optimization by Miku-666 + +namespace PckStudio.Forms.Editor +{ + public partial class AudioEditor : MetroForm + { + public bool saved = false; + public string defaultType = "yes"; + string tempDir = ""; + PCKAudioFile audioFile = null; + PCKFile.FileData audioPCK; + LOCFile loc; + bool _isLittleEndian = false; + + public static readonly List Categories = new List + { + "Overworld", + "Nether", + "End", + "Creative", + "Menu/Loading", + "Battle", + "Tumble", + "Glide", + "Unused?" + }; + + private string GetCategoryFromId(PCKAudioFile.AudioCategory.EAudioType categoryId) + => categoryId >= PCKAudioFile.AudioCategory.EAudioType.Overworld && + categoryId <= PCKAudioFile.AudioCategory.EAudioType.Unused + ? Categories[(int)categoryId] + : "Not valid"; + + private PCKAudioFile.AudioCategory.EAudioType GetCategoryId(string category) + { + return (PCKAudioFile.AudioCategory.EAudioType)Categories.IndexOf(category); + } + + public static PCKFile.FileData CreateAudioPck(bool isLittle) + { + // create actual valid pck file structure + PCKAudioFile audioPck = new PCKAudioFile(); + audioPck.AddCategory(PCKAudioFile.AudioCategory.EAudioType.Overworld); + audioPck.AddCategory(PCKAudioFile.AudioCategory.EAudioType.Nether); + audioPck.AddCategory(PCKAudioFile.AudioCategory.EAudioType.End); + PCKFile.FileData pckFileData = new PCKFile.FileData("audio.pck", 8); + using (var stream = new MemoryStream()) + { + PCKAudioFileWriter.Write(stream, audioPck, isLittle); + pckFileData.SetData(stream.ToArray()); + } + return pckFileData; + } + + /// + /// Overload that creates a new audio.pck file + /// + public AudioEditor(LOCFile locFile, bool isLittleEndian) : this(CreateAudioPck(isLittleEndian), locFile, isLittleEndian) + { + } + + public AudioEditor(PCKFile.FileData file, LOCFile locFile, bool isLittleEndian) + { + InitializeComponent(); + // so the Creative songs aren't combined until after the forms are closed. + // this will prevent potential problems with editing the categories after merging. + this.saveToolStripMenuItem1.Click += (sender, e) => saveToolStripMenuItem1_Click(sender, e, false); + loc = locFile; + tempDir = Path.Combine(Directory.GetCurrentDirectory(), "temp"); + _isLittleEndian = isLittleEndian; + try + { + handleUtilFiles(); + //library = LoadLibrary(Path.Combine(tempDir, "mss32.dll")); + } + catch (IOException ex) + { + MessageBox.Show("Failed to get Binka conversion files", "Exception thrown"); + Close(); + } + + audioPCK = file; + using (var stream = new MemoryStream(file.data)) + { + audioFile = PCKAudioFileReader.Read(stream, isLittleEndian); + } + + foreach (var category in audioFile.Categories) + { + if (category.Name == "include_overworld" && + category.audioType == PCKAudioFile.AudioCategory.EAudioType.Creative && + audioFile.TryGetCategory(PCKAudioFile.AudioCategory.EAudioType.Overworld, out PCKAudioFile.AudioCategory overworldCategory)) + { + foreach(var name in category.SongNames.ToList()) + { + if (overworldCategory.SongNames.Contains(name)) + category.SongNames.Remove(name); + } + playOverworldInCreative.Checked = true; + } + + TreeNode treeNode = new TreeNode(GetCategoryFromId(category.audioType), (int)category.audioType, (int)category.audioType); + treeNode.Tag = category; + treeView1.Nodes.Add(treeNode); + } + + playOverworldInCreative.Enabled = audioFile.HasCategory(PCKAudioFile.AudioCategory.EAudioType.Creative); + } + + // https://stackoverflow.com/a/25064568 by Alik Khilazhev -MattNL + private void ExtractResource(string resName, string fName) + { + object ob = Properties.Resources.ResourceManager.GetObject(resName); + byte[] myResBytes = (byte[])ob; + using (FileStream fsDst = new FileStream(fName, FileMode.CreateNew, FileAccess.Write)) + { + byte[] bytes = myResBytes; + fsDst.Write(bytes, 0, bytes.Length); + fsDst.Close(); + fsDst.Dispose(); + } + } + + private void handleUtilFiles(bool extractFiles = true) + { + //string asiPath = Path.Combine(tempDir, "binkawin.asi"); + //string mssPath = Path.Combine(tempDir, "mss32.dll"); + string encoderPath = Path.Combine(tempDir, "binka_encode.exe"); + + // Deletes files so that System.IO exceptions are avoided + //if (File.Exists(asiPath)) File.Delete(asiPath); + //if (File.Exists(mssPath)) File.Delete(mssPath); + if (File.Exists(encoderPath)) File.Delete(encoderPath); + if (Directory.Exists(tempDir)) Directory.Delete(tempDir); + + if (extractFiles) + { + Directory.CreateDirectory(tempDir); + ExtractResource("binka_encode", encoderPath); + //ExtractResource("mss32", mssPath); + //ExtractResource("binkawin", asiPath); + } + } + + private void AudioEditor_FormClosed(object sender, FormClosedEventArgs e) + { + //FreeLibrary(library); + handleUtilFiles(false); + } + + private void verifyFileLocationToolStripMenuItem_Click(object sender, EventArgs e) + { + if (treeView1.SelectedNode.Tag == null || treeView2.SelectedNode.Tag == null) return; + var entry = treeView2.SelectedNode; + + MainForm parent = Owner.Owner as MainForm; // Gets the MainForm so we can access the Save Location + string DataDirectory = Path.Combine(Path.GetDirectoryName(parent.saveLocation), "Data"); + string FileName = Path.Combine(DataDirectory, entry.Text + ".binka"); + Console.WriteLine(FileName); + if (!Directory.Exists(DataDirectory)) + { + MessageBox.Show("There is not a \"Data\" folder present in the pack folder", "Folder missing"); + return; + } + if (File.Exists(FileName)) MessageBox.Show("\"" + entry.Text + ".binka\" exists in the \"Data\" folder", "File found"); + else MessageBox.Show("\"" + entry.Text + ".binka\" does not exist in the \"Data\" folder", "File missing"); + } + + private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) + { + treeView2.Nodes.Clear(); + if (e.Node.Tag is PCKAudioFile.AudioCategory category) + foreach (var name in category.SongNames) + { + treeView2.Nodes.Add(name); + } + if (treeView2.Nodes.Count > 0) treeView2.SelectedNode = treeView2.Nodes[0]; + } + + private void addCategoryStripMenuItem_Click(object sender, EventArgs e) + { + string[] avalible = Categories.FindAll(str => !audioFile.HasCategory(GetCategoryId(str)) ).ToArray(); + if (avalible.Length > 0) + { + using addCategory add = new addCategory(avalible); + if (add.ShowDialog() == DialogResult.OK) + audioFile.AddCategory(GetCategoryId(add.Category)); + else return; + + var category = audioFile.GetCategory(GetCategoryId(add.Category)); + TreeNode treeNode = new TreeNode(GetCategoryFromId(category.audioType), (int)category.audioType, (int)category.audioType); + treeNode.Tag = category; + treeView1.Nodes.Add(treeNode); + } + else + { + MessageBox.Show("All possible categories are used", "There are no more categories that could be added"); + } + } + + private void addEntryMenuItem_Click(object sender, EventArgs e) + { + if (treeView1.SelectedNode is TreeNode t && t.Tag is PCKAudioFile.AudioCategory && + // Gets the MainForm so we can access the Save Location + Owner.Owner is MainForm parent) + { + string DataDirectory = Path.Combine(Path.GetDirectoryName(parent.saveLocation), "Data"); + if (!Directory.Exists(DataDirectory)) + { + MessageBox.Show("There is not a \"Data\" folder present in the pack folder", "Folder missing"); + return; + } + + OpenFileDialog ofn = new OpenFileDialog(); + ofn.Multiselect = true; + ofn.Filter = "BINKA files (*.binka)|*.binka|WAV files (*.wav)|*.wav"; + ofn.Title = "Please choose WAV or BINKA files to add to your pack"; + ofn.ShowDialog(); + ofn.Dispose(); + if (string.IsNullOrEmpty(ofn.FileName)) return; // Return if name is null or if the user cancels + + ProcessEntries(ofn.FileNames, DataDirectory); + } + } + + private void removeCategoryStripMenuItem_Click(object sender, EventArgs e) + { + if (treeView1.SelectedNode is TreeNode main && + audioFile.RemoveCategory(GetCategoryId(treeView1.SelectedNode.Text))) + { + treeView2.Nodes.Clear(); + main.Remove(); + } + } + + private void treeView1_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Delete) + removeCategoryStripMenuItem_Click(sender, e); + } + + public void treeView2_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Delete) + removeEntryMenuItem_Click(sender, e); + } + + private void removeEntryMenuItem_Click(object sender, EventArgs e) + { + if (treeView2.SelectedNode != null && treeView1.SelectedNode.Tag is PCKAudioFile.AudioCategory category) + { + category.SongNames.Remove(treeView2.SelectedNode.Text); + treeView2.SelectedNode.Remove(); + } + } + + async void ProcessEntries(string[] FileList, string DataDirectory) + { + foreach (string file in FileList) + { + if (Path.GetExtension(file) == ".binka" || Path.GetExtension(file) == ".wav") + { + string new_loc = Path.Combine(DataDirectory, Path.GetFileNameWithoutExtension(file) + ".binka"); + bool duplicate_song = false; // To handle if a file already in the pack is dropped back in + if (File.Exists(new_loc)) + { + duplicate_song = File.ReadAllBytes(file) == File.ReadAllBytes(new_loc); + if (duplicate_song) + { + DialogResult user_prompt = MessageBox.Show("\"" + Path.GetFileNameWithoutExtension(file) + ".binka\" already exists. Continuing will replace the existing file. Are you sure you want to continue moving the file? By pressing no, the song entry will be added without moving the file. You can also cancel this operation and all files in queue.", "File already exists", MessageBoxButtons.YesNoCancel); + while (user_prompt == DialogResult.None) ; // Stops the editor from adding or processing the file until the user had made their choice + if (user_prompt == DialogResult.Cancel) + { + break; + } + else if (user_prompt == DialogResult.No) continue; + } + } + + if (Path.GetExtension(file) == ".wav") // Convert Wave to BINKA + { + Cursor.Current = Cursors.WaitCursor; + pleaseWait waitDiag = new pleaseWait(); + waitDiag.Show(this); + + int error_code = 0; + await Task.Run(() => + { + var process = Process.Start(new ProcessStartInfo + { + FileName = Path.Combine(tempDir, "binka_encode.exe"), + Arguments = $"\"{file}\" \"{new_loc}\"", + UseShellExecute = true, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden + }); + process.Start(); + process.WaitForExit(); + }); + + waitDiag.Close(); + waitDiag.Dispose(); + Cursor.Current = Cursors.Default; + + if (error_code != 0) continue; + } + else if (!duplicate_song) + { + Console.WriteLine(Path.GetFileName(file)); + File.Delete(Path.Combine(DataDirectory, Path.GetFileName(file))); + File.Copy(file, Path.Combine(DataDirectory, Path.GetFileName(file))); + } + + var songName = Path.GetFileNameWithoutExtension(file); + if (treeView1.SelectedNode is TreeNode t && t.Tag is PCKAudioFile.AudioCategory category) + { + category.SongNames.Add(songName); + treeView2.Nodes.Add(songName); + } + } + } + } + + private void Binka_DragDrop(object sender, DragEventArgs e) + { + //MessageBox.Show((Owner.Owner as MainForm).saveLocation); + // Gets the MainForm so we can access the Save Location + if (treeView1.SelectedNode != null && Owner.Owner is MainForm parent) + { + string DataDirectory = Path.Combine(Path.GetDirectoryName(parent.saveLocation), "Data"); + if (!Directory.Exists(DataDirectory)) + { + MessageBox.Show("There is not a \"Data\" folder present in the pack folder", "Folder missing"); + return; + } + + ProcessEntries((string[])e.Data.GetData(DataFormats.FileDrop, false), DataDirectory); + } + } + + private void saveToolStripMenuItem1_Click(object sender, EventArgs e, bool combineCreative) + { + if(!audioFile.HasCategory(PCKAudioFile.AudioCategory.EAudioType.Overworld) || + !audioFile.HasCategory(PCKAudioFile.AudioCategory.EAudioType.Nether) || + !audioFile.HasCategory(PCKAudioFile.AudioCategory.EAudioType.End)) + { + MessageBox.Show("Your changes were not saved. The game will crash when loading your pack if the Overworld, Nether and End categories don't all exist with at least one valid song.", "Mandatory Categories Missing"); + return; + } + + PCKAudioFile.AudioCategory overworldCategory = audioFile.GetCategory(PCKAudioFile.AudioCategory.EAudioType.Overworld); + foreach (var category in audioFile.Categories) + { + category.Name = ""; + if (combineCreative && category.audioType == PCKAudioFile.AudioCategory.EAudioType.Creative) + { + foreach (var name in overworldCategory.SongNames) + { + if (!category.SongNames.Contains(name)) + { + category.SongNames.Add(name); + Console.WriteLine(name); + } + } + category.Name = "include_overworld"; + } + } + + bool emptyCat = false; + + if (emptyCat) + { + MessageBox.Show("The game will crash upon loading your pack if a category is empty", "Empty Category"); + return; + } + + using (var stream = new MemoryStream()) + { + PCKAudioFileWriter.Write(stream, audioFile, _isLittleEndian); + audioPCK.SetData(stream.ToArray()); + } + saved = true; + } + + private void treeView2_DragEnter(object sender, DragEventArgs e) + { + e.Effect = DragDropEffects.All; + } + + private void helpToolStripMenuItem_Click(object sender, EventArgs e) + { + MessageBox.Show("Simply drag and drop BINKA or WAV audio files into the right tree to add them to the category selected on the left tree.\n\n" + + "The \"Menu\" category will only play once when loading the pack, and never again.\n\n" + + "The \"Creative\" category will only play songs listed in that category, and unlike other editions of Minecraft, will NOT play songs from the Overworld category. You can fix this by clicking the checkbox found at the top of the form.\n\n" + + "The mini game categories will only play if you have your pack loaded in those mini games.\n\n" + + "You can edit the credits for the PCK in the Credits editor! No more managing credit IDs!\n\n" + + "You can modify and create PSVita and PS4 audio pcks by clicking \"PS4/Vita\" in the \"Create -> Audio.pck\" context menu", "Help"); + } + + private void creditsEditorToolStripMenuItem_Click(object sender, EventArgs e) + { + var credits = audioFile.GetCreditsString(); + using (creditsEditor prompt = new creditsEditor(credits)) + if (prompt.ShowDialog() == DialogResult.OK) + audioFile.SetCredits(prompt.Credits.Split('\n')); + } + + private void AudioEditor_FormClosing(object sender, FormClosingEventArgs e) + { + if (saved) saveToolStripMenuItem1_Click(sender, e, playOverworldInCreative.Checked); + } + } +} diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/AudioEditor.resx b/MinecraftUSkinEditor/Forms/Editor/AudioEditor.resx similarity index 99% rename from MinecraftUSkinEditor/Forms/Utilities/Audio/AudioEditor.resx rename to MinecraftUSkinEditor/Forms/Editor/AudioEditor.resx index 37e149c3..838a1802 100644 --- a/MinecraftUSkinEditor/Forms/Utilities/Audio/AudioEditor.resx +++ b/MinecraftUSkinEditor/Forms/Editor/AudioEditor.resx @@ -166,7 +166,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADk - MAAAAk1TRnQBSQFMAgEBCQEAATgBAAE4AQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + MAAAAk1TRnQBSQFMAgEBCQEAAUABAAFAAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABMAMAAQEBAAEgBgABMBIAAzgB/wM1Af8DNQH/AzMB/wMwAf8DLwH/Ay0B/wMtAf8DJAH/AzsB/wM4 Af8DNQH/Ay0B/wMnAf8DNgH/AzIB/8AAAzgB/wN/Af8DeQH/A3kB/wN5Af8DcQH/A3EB/wN5Af8DeQH/ A3EB/wNxAf8DcQH/A3kB/wN5Af8DfwH/AzIB/8AAAzIB/wN2Af8DsAH/A7AB/wOvAf8DrwH/A68B/wOo diff --git a/MinecraftUSkinEditor/Forms/Editor/GRFEditor.cs b/MinecraftUSkinEditor/Forms/Editor/GRFEditor.cs index 230694fa..30f29a9b 100644 --- a/MinecraftUSkinEditor/Forms/Editor/GRFEditor.cs +++ b/MinecraftUSkinEditor/Forms/Editor/GRFEditor.cs @@ -1,6 +1,6 @@ using PckStudio.Classes.FileTypes; using PckStudio.Classes.IO.GRF; -using PckStudio.Forms.Utilities.Grf; +using PckStudio.Forms.Additional_Popups.Grf; using RichPresenceClient; using System; using System.Collections.Generic; diff --git a/MinecraftUSkinEditor/Forms/Utilities/Audio/AudioEditor.cs b/MinecraftUSkinEditor/Forms/Utilities/Audio/AudioEditor.cs deleted file mode 100644 index 10b1b1fc..00000000 --- a/MinecraftUSkinEditor/Forms/Utilities/Audio/AudioEditor.cs +++ /dev/null @@ -1,515 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; -using MetroFramework.Forms; -using PckStudio; -using PckStudio.Classes.FileTypes; -using PckStudio.Classes.IO; - -// Audio Editor by MattNL -// additional work and optimization by Miku-666 - -namespace PckStudio.Forms.Utilities -{ - public partial class AudioEditor : MetroForm - { - public bool saved = false; - public string credits = ""; - public string defaultType = "yes"; - string WorkingDir = ""; - string tempDir = ""; - PCKFile audioPCK = null; - PCKFile.FileData audioPCKFile; - bool _isLittleEndian; - public List cats = new List(); - public class NodeSorter : System.Collections.IComparer - { - public int Compare(object x, object y) - { - if (x == null || y == null) return -1; - return ((x as TreeNode).Tag as PCKFile.FileData).type.CompareTo(((y as TreeNode).Tag as PCKFile.FileData).type); - } - } - - public static readonly List Categories = new List - { - "Overworld", // 0 - "Nether", // 1 - "End", // 2 - "Creative", // 3 - "Menu/Loading", // 4 - "Battle", // 5 - "Tumble", // 6 - "Glide", // 7 - "Unused?" // 8 - }; - - internal string GetCategoryFromId(int categoryId) - { - return categoryId > -1 && categoryId < Categories.Count ? Categories[categoryId] : "Not valid"; - } - - internal int GetCategoryId(string category) - { - return Categories.IndexOf(category); - } - - public static PCKFile.FileData CreateAudioPck(bool isLittle) - { - // create actual valid pck file structure - PCKFile audioPck = new PCKFile(1); // 1 = audio.pck - //audioPck.meta_data.Add("CUENAME"); - //audioPck.meta_data.Add("CREDIT"); - //audioPck.meta_data.Add("CREDITID"); - audioPck.Files.Add(new PCKFile.FileData("", 0)); - audioPck.Files.Add(new PCKFile.FileData("", 1)); - audioPck.Files.Add(new PCKFile.FileData("", 2)); - - // create a file data entry for current open pck file - PCKFile.FileData audioFileData = new PCKFile.FileData("audio.pck", 8); - using (var stream = new MemoryStream()) - { - PCKFileWriter.Write(stream, audioPck, isLittle); - audioFileData.SetData(stream.ToArray()); - } - return audioFileData; - } - - /// - /// Overload that creates a new audio.pck file - /// - /// - /// - public AudioEditor(LOCFile locFile, bool isLittleEndian) : this(CreateAudioPck(isLittleEndian), locFile, isLittleEndian) - { - - } - - // https://stackoverflow.com/a/25064568 by Alik Khilazhev -MattNL - private void ExtractResource(string resName, string fName) - { - object ob = Properties.Resources.ResourceManager.GetObject(resName); - byte[] myResBytes = (byte[])ob; - using (FileStream fsDst = new FileStream(fName, FileMode.CreateNew, FileAccess.Write)) - { - byte[] bytes = myResBytes; - fsDst.Write(bytes, 0, bytes.Length); - fsDst.Close(); - fsDst.Dispose(); - } - } - - private void handleUtilFiles(bool extractFiles = true) - { - string asiPath = Path.Combine(tempDir, "binkawin.asi"); - string mssPath = Path.Combine(tempDir, "mss32.dll"); - string encoderPath = Path.Combine(tempDir, "binka_encode.exe"); - - // Deletes files so that System.IO exceptions are avoided - if (File.Exists(asiPath)) File.Delete(asiPath); - if (File.Exists(mssPath)) File.Delete(mssPath); - if (File.Exists(encoderPath)) File.Delete(encoderPath); - if (Directory.Exists(tempDir)) Directory.Delete(tempDir); - - if (extractFiles) - { - Directory.CreateDirectory(tempDir); - ExtractResource("binka_encode", encoderPath); - //ExtractResource("mss32", mssPath); - //ExtractResource("binkawin", asiPath); - } - } - - private void AudioEditor_FormClosed(object sender, FormClosedEventArgs e) - { - //FreeLibrary(library); - handleUtilFiles(false); - } - - private void verifyFileLocationToolStripMenuItem_Click(object sender, EventArgs e) - { - if (treeView1.SelectedNode.Tag == null || !(treeView1.SelectedNode.Tag is PCKFile.FileData) || !(treeView2.SelectedNode.Tag is ValueTuple)) return; - var entry = treeView2.SelectedNode; - - MainForm parent = Owner.Owner as MainForm; // Gets the MainForm so we can access the Save Location - string DataDirectory = Path.Combine(Path.GetDirectoryName(parent.saveLocation), "Data"); - string FileName = Path.Combine(DataDirectory, entry.Text + ".binka"); - Console.WriteLine(FileName); - if (!Directory.Exists(DataDirectory)) - { - MessageBox.Show("There is not a \"Data\" folder present in the pack folder", "Folder missing"); - return; - } - if (File.Exists(FileName)) MessageBox.Show("\"" + entry.Text + ".binka\" exists in the \"Data\" folder", "File found"); - else MessageBox.Show("\"" + entry.Text + ".binka\" does not exist in the \"Data\" folder", "File missing"); - } - - LOCFile loc; - public AudioEditor(PCKFile.FileData MineFile, LOCFile locFile, bool isLittleEndian) - { - loc = locFile; - WorkingDir = Directory.GetCurrentDirectory(); - tempDir = Path.Combine(WorkingDir, "temp"); - try - { - handleUtilFiles(); - //library = LoadLibrary(Path.Combine(tempDir, "mss32.dll")); - } - catch (IOException ex) - { - MessageBox.Show("Failed to get Binka conversion files", "Exception thrown"); - this.Close(); - } - - _isLittleEndian = isLittleEndian; - if (isLittleEndian) Text += " (PS4/Vita)"; - InitializeComponent(); - audioPCKFile = MineFile; - using (var stream = new MemoryStream(audioPCKFile.data)) - { - audioPCK = PCKFileReader.Read(stream, isLittleEndian); - } - - //if (!audioPCK.meta_data.Contains("CUENAME") || audioPCK.type != 1) - //{ - // throw new Exception("This is not a valid audio.pck file"); - //} - foreach (PCKFile.FileData categoryFile in audioPCK.Files) - { - string CatString = GetCategoryFromId(categoryFile.type); - Console.WriteLine($"Category Found: {CatString} ({categoryFile.type})."); - foreach (var property in categoryFile.properties.ToArray()) - { - if (property.Item1 == "CREDITID") - { - loc.RemoveLocKey(property.Item2); - categoryFile.properties.Remove(property); - } - else if (property.Item1 == "CREDIT") - { - credits += property.Item2 + "\n"; - categoryFile.properties.Remove(property); - } - } - if (cats.Contains(GetCategoryFromId(categoryFile.type))) - { - Console.WriteLine("Duplicate category found, " + CatString + ". Combining..."); - audioPCK.Files.Remove(categoryFile); - audioPCK.Files.Find(category => category.filepath == GetCategoryFromId(categoryFile.type)).properties = categoryFile.properties; - } - else - { - if (categoryFile.filepath == "include_overworld" && categoryFile.type == 3) - { - PCKFile.FileData overworldMF = audioPCK.Files.Find(file => file.type == 0); - - foreach(ValueTuple property in categoryFile.properties.ToList()) - { - if (overworldMF.properties.Contains(property)) categoryFile.properties.Remove(property); - } - - playOverworldInCreative.Checked = true; - } - - TreeNode treeNode = new TreeNode(CatString); - treeNode.Tag = categoryFile; - treeNode.ImageIndex = categoryFile.type; - treeNode.SelectedImageIndex = categoryFile.type; - treeView1.Nodes.Add(treeNode); - cats.Add(GetCategoryFromId(categoryFile.type)); - } - } - - playOverworldInCreative.Enabled = cats.Contains(GetCategoryFromId(3)); - - treeView1.TreeViewNodeSorter = new NodeSorter(); - treeView1.Sort(); - } - - private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) - { - treeView2.Nodes.Clear(); - PCKFile.FileData mineFile = (PCKFile.FileData)e.Node.Tag; - foreach (var entry in mineFile.properties) - { - var property = (ValueTuple)entry; - TreeNode meta = new TreeNode(); - meta.Text = property.Item2; - meta.Tag = entry; - treeView2.Nodes.Add(meta); - } - credits = credits.TrimEnd('\n'); - if (treeView2.Nodes.Count > 0) treeView2.SelectedNode = treeView2.Nodes[0]; - } - - private void addCategoryStripMenuItem_Click(object sender, EventArgs e) - { - try - { - string[] avalible = Categories.FindAll(str => - { - return !cats.Contains(str); - }).ToArray(); - addCategory add = new addCategory(avalible); //sets category adding dialog - if (add.ShowDialog() == DialogResult.OK) - cats.Add(add.Category); - PCKFile.FileData file = new PCKFile.FileData(add.Category, GetCategoryId(add.Category)); - TreeNode addNode = new TreeNode(file.filepath) { Tag = file }; - audioPCK.Files.Add(file); - addNode.ImageIndex = GetCategoryId(add.Category); - addNode.SelectedImageIndex = GetCategoryId(add.Category); - treeView1.Nodes.Add(addNode); - treeView1.Sort(); - add.Dispose(); // diposes generated metadata adding dialog data - playOverworldInCreative.Enabled = cats.Contains(GetCategoryFromId(3)); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - MessageBox.Show("All possible categories are used", "There are no more categories that could be added"); - } - } - - private void addEntryMenuItem_Click(object sender, EventArgs e) - { - if (treeView1.SelectedNode == null && !(treeView1.SelectedNode.Tag is PCKFile.FileData)) return; - - MainForm parent = Owner.Owner as MainForm; // Gets the MainForm so we can access the Save Location - string DataDirectory = Path.Combine(Path.GetDirectoryName(parent.saveLocation), "Data"); - if (!Directory.Exists(DataDirectory)) - { - MessageBox.Show("There is not a \"Data\" folder present in the pack folder", "Folder missing"); - return; - } - - OpenFileDialog ofn = new OpenFileDialog(); - ofn.Multiselect = true; - ofn.Filter = "BINKA files (*.binka)|*.binka|WAV files (*.wav)|*.wav"; - ofn.Title = "Please choose WAV or BINKA files to add to your pack"; - ofn.ShowDialog(); - ofn.Dispose(); - if (String.IsNullOrEmpty(ofn.FileName)) return; // Return if name is null or if the user cancels - - ProcessEntries(ofn.FileNames, DataDirectory); - } - - private void removeCategoryStripMenuItem_Click(object sender, EventArgs e) - { - if (treeView1.SelectedNode == null) return; // makes sure you don't run this if there is nothing to delete - cats.Remove(treeView1.SelectedNode.Text); - if (audioPCK.Files.Remove((PCKFile.FileData)treeView1.SelectedNode.Tag)) - { - treeView2.Nodes.Clear(); - treeView1.SelectedNode.Remove(); - } - playOverworldInCreative.Enabled = cats.Contains(GetCategoryFromId(3)); - } - - public void treeView2_KeyDown(object sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Delete) - removeEntryMenuItem_Click(sender, e); - } - - private void removeEntryMenuItem_Click(object sender, EventArgs e) - { - var mainNode = treeView1.SelectedNode; - var subNode = treeView2.SelectedNode; - if (subNode != null && - subNode.Tag is ValueTuple && - mainNode.Tag is PCKFile.FileData) - { - var file = mainNode.Tag as PCKFile.FileData; - var property = (ValueTuple)subNode.Tag; - if (file.properties.Remove(property)) - subNode.Remove(); - } - } - - async void ProcessEntries(string[] FileList, string DataDirectory) - { - foreach (string file in FileList) - { - if (Path.GetExtension(file) == ".binka" || Path.GetExtension(file) == ".wav") - { - string new_loc = Path.Combine(DataDirectory, Path.GetFileNameWithoutExtension(file) + ".binka"); - bool duplicate_song = false; // To handle if a file already in the pack is dropped back in - if (File.Exists(new_loc)) - { - duplicate_song = File.ReadAllBytes(file).Length == File.ReadAllBytes(new_loc).Length; - if (!duplicate_song) - { - DialogResult user_prompt = MessageBox.Show("\"" + Path.GetFileNameWithoutExtension(file) + ".binka\" already exists. Continuing will replace the existing file. Are you sure you want to continue moving the file? By pressing no, you will skip this file. You can also cancel all pending file operations.", "File already exists", MessageBoxButtons.YesNoCancel); - if (user_prompt == DialogResult.Cancel) break; - else if (user_prompt == DialogResult.No) continue; - } - } - - if (Path.GetExtension(file) == ".wav") // Convert Wave to BINKA - { - Cursor.Current = Cursors.WaitCursor; - Audio.pleaseWait waitDiag = new Audio.pleaseWait(); - waitDiag.Show(this); - - int error_code = 0; - await Task.Run(() => - { - var process = new System.Diagnostics.Process(); - process.StartInfo.FileName = Path.Combine(tempDir, "binka_encode.exe"); - process.StartInfo.Arguments = "\"" + file + "\" \"" + new_loc + "\""; - process.StartInfo.UseShellExecute = true; - process.StartInfo.CreateNoWindow = true; - process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; - process.Start(); - process.WaitForExit(); - }); - - waitDiag.Close(); - waitDiag.Dispose(); - Cursor.Current = Cursors.Default; - - if (error_code != 0) continue; - } - else if (!duplicate_song) - { - Console.WriteLine(Path.GetFileName(file)); - File.Delete(Path.Combine(DataDirectory, Path.GetFileName(file))); - File.Copy(file, Path.Combine(DataDirectory, Path.GetFileName(file))); - } - - TreeNode meta = new TreeNode(Path.GetFileNameWithoutExtension(file)); - var property = new ValueTuple("CUENAME", Path.GetFileNameWithoutExtension(file)); - meta.Tag = property; - treeView2.Nodes.Add(meta); - (treeView1.SelectedNode.Tag as PCKFile.FileData).properties.Add(property); - } - } - } - - private void Binka_DragDrop(object sender, DragEventArgs e) - { - if (treeView1.SelectedNode == null && !(treeView1.SelectedNode.Tag is PCKFile.FileData)) return; - - MainForm parent = Owner.Owner as MainForm; // Gets the MainForm so we can access the Save Location - string DataDirectory = Path.Combine(Path.GetDirectoryName(parent.saveLocation), "Data"); - if (!Directory.Exists(DataDirectory)) - { - MessageBox.Show("There is not a \"Data\" folder present in the pack folder", "Folder missing"); - return; - } - - ProcessEntries((string[])e.Data.GetData(DataFormats.FileDrop, false), DataDirectory); - } - - private void saveToolStripMenuItem1_Click(object sender, EventArgs e) - { - if(!cats.Contains(GetCategoryFromId(0)) || - !cats.Contains(GetCategoryFromId(1)) || - !cats.Contains(GetCategoryFromId(2))) - { - MessageBox.Show("The game will crash upon loading your pack if the Overworld, Nether and End categories don't all exist.", "Mandatory Categories Missing"); - return; - } - - bool emptyCat = false; - - List new_order = audioPCK.Files.OrderBy(fd => fd.type).ToList(); - - audioPCK.Files.Clear(); - - foreach (PCKFile.FileData mf in new_order) - { - audioPCK.Files.Add(mf); - if (mf.properties.Count == 0) emptyCat = true; - } - - if (emptyCat) - { - MessageBox.Show("The game will crash upon loading your pack if a category is empty", "Empty Category"); - return; - } - - using (StringReader reader = new StringReader(credits)) - { - string line; - int creditCount = 1; - while ((line = reader.ReadLine()) != null) - { - var credit = ("CREDIT", line); - string credit_id = "IDS_CREDIT" + (creditCount > 1 ? creditCount.ToString() : ""); - var creditid = ("CREDITID", credit_id); - audioPCK.Files[0].properties.Add(credit); - audioPCK.Files[0].properties.Add(creditid); - loc.AddLocKey(credit_id, line); - creditCount++; - Console.WriteLine(line); - } - } - using (var stream = new MemoryStream()) - { - PCKFileWriter.Write(stream, audioPCK, _isLittleEndian); - audioPCKFile.SetData(stream.ToArray()); - } - saved = true; - } - - private void treeView2_DragEnter(object sender, DragEventArgs e) - { - e.Effect = DragDropEffects.All; - } - - private void helpToolStripMenuItem_Click(object sender, EventArgs e) - { - MessageBox.Show("Simply drag and drop BINKA or WAV audio files into the right tree to add them to the category selected on the left tree.\n\n" + - "The \"Menu\" category will only play once when loading the pack, and never again.\n\n" + - "The \"Creative\" category will only play songs listed in that category, and unlike other editions of Minecraft, will NOT play songs from the Overworld category. You can fix this by clicking the checkbox found at the top of the form.\n\n" + - "The mini game categories will only play if you have your pack loaded in those mini games.\n\n" + - "You can edit the credits for the PCK in the Credits editor! No more managing credit IDs!\n\n" + - "You can modify and create PSVita and PS4 audio pcks by clicking \"PS4/Vita\" in the \"Create -> Audio.pck\" context menu", "Help"); - } - - private void creditsEditorToolStripMenuItem_Click(object sender, EventArgs e) - { - creditsEditor prompt = new creditsEditor(credits); - prompt.ShowDialog(); - credits = prompt.Credits; - } - - private void AudioEditor_FormClosing(object sender, FormClosingEventArgs e) - { - if (saved != true) return; - PCKFile.FileData overworldMF = new PCKFile.FileData("", -1); - - foreach (PCKFile.FileData mf in audioPCK.Files) - { - mf.filepath = ""; - if (playOverworldInCreative.Checked && mf.type == 0) overworldMF = mf; - if (playOverworldInCreative.Checked && mf.type == 3 && overworldMF.type != -1) - { - foreach (ValueTuple property in overworldMF.properties) - { - if (property.Item1 == "CUENAME" && !mf.properties.Contains(property)) - { - mf.properties.Add(property); - Console.WriteLine(property.Item2); - } - } - mf.filepath = "include_overworld"; - } - } - - using (var stream = new MemoryStream()) - { - PCKFileWriter.Write(stream, audioPCK, _isLittleEndian); - audioPCKFile.SetData(stream.ToArray()); - } - } - } -} diff --git a/MinecraftUSkinEditor/MainForm.cs b/MinecraftUSkinEditor/MainForm.cs index 8aaf0945..d37ff36f 100644 --- a/MinecraftUSkinEditor/MainForm.cs +++ b/MinecraftUSkinEditor/MainForm.cs @@ -8,15 +8,14 @@ using System.Drawing.Drawing2D; using System.Diagnostics; using PckStudio.Properties; using Ohana3DS_Rebirth.Ohana; -using PckStudio.Forms; using System.Drawing.Imaging; using RichPresenceClient; using PckStudio.Classes.FileTypes; using PckStudio.Classes.IO; using PckStudio.Classes.IO.LOC; -using PckStudio.Forms.Utilities; using PckStudio.Classes.IO.GRF; -using PckStudio.Classes.Utils; +using PckStudio.Forms; +using PckStudio.Forms.Utilities; using PckStudio.Forms.Editor; namespace PckStudio @@ -600,20 +599,12 @@ namespace PckStudio break; case 8 when file.filepath == "audio.pck": - try - { - if (!TryGetLocFile(out LOCFile locFile)) - throw new Exception("No .loc File found."); - AudioEditor audioEditor = new AudioEditor(file, locFile, LittleEndianCheckBox.Checked); - audioEditor.ShowDialog(this); - if (audioEditor.saved) TrySetLocFile(locFile); - audioEditor.Dispose(); - } - catch (Exception ex) - { - MessageBox.Show("Error", ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } + if (!TryGetLocFile(out LOCFile locFile)) + throw new Exception("No .loc File found."); + AudioEditor audioEditor = new AudioEditor(file, locFile, LittleEndianCheckBox.Checked); + audioEditor.ShowDialog(this); + if (audioEditor.saved) TrySetLocFile(locFile); + audioEditor.Dispose(); break; case 9 when file.filepath == "colours.col": diff --git a/MinecraftUSkinEditor/PckStudio.csproj b/MinecraftUSkinEditor/PckStudio.csproj index 1a5b8732..0188da44 100644 --- a/MinecraftUSkinEditor/PckStudio.csproj +++ b/MinecraftUSkinEditor/PckStudio.csproj @@ -140,12 +140,17 @@ + + + + + @@ -232,16 +237,16 @@ SetBulkSpeed.cs - + Form - + creditsEditor.cs - + Form - + addCategory.cs @@ -280,10 +285,10 @@ AddParameter.cs - + Form - + pleaseWait.cs @@ -328,10 +333,10 @@ FrameEditor.cs - + Form - + AudioEditor.cs @@ -457,11 +462,11 @@ SetBulkSpeed.cs - + creditsEditor.cs Designer - + addCategory.cs @@ -493,7 +498,7 @@ AddParameter.cs - + pleaseWait.cs @@ -528,7 +533,7 @@ FrameEditor.cs - + AudioEditor.cs Designer