From e36ebe5878b39033711f582f330b81495db2f9eb Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sun, 31 Mar 2024 17:26:25 +0200 Subject: [PATCH] Add IPckSerializer and IPckDeserializer and Update Animation/AnimationEditor --- .../Extensions/PckFileDataExtensions.cs | 17 +++ .../Additional-Popups/Animation/ChangeTile.cs | 26 ++--- .../Forms/Editor/AnimationEditor.Designer.cs | 13 +-- PCK-Studio/Forms/Editor/AnimationEditor.cs | 75 +++---------- PCK-Studio/Forms/Editor/GameRuleFileEditor.cs | 102 +++--------------- PCK-Studio/Forms/Editor/TextureAtlasEditor.cs | 7 +- PCK-Studio/Interfaces/IPckDeserializer.cs | 14 +++ PCK-Studio/Interfaces/IPckFileSerializer.cs | 14 +++ PCK-Studio/Internal/Animation.cs | 37 ++----- .../AnimationDeserializer.cs} | 36 +++---- PCK-Studio/Internal/AnimationSerializer.cs | 28 +++++ ...imationCategory.cs => ResourceCategory.cs} | 7 +- PCK-Studio/Internal/ResourceLocation.cs | 35 ++++++ PCK-Studio/MainForm.cs | 77 +++++++++---- PCK-Studio/PckStudio.csproj | 8 +- 15 files changed, 245 insertions(+), 251 deletions(-) create mode 100644 PCK-Studio/Interfaces/IPckDeserializer.cs create mode 100644 PCK-Studio/Interfaces/IPckFileSerializer.cs rename PCK-Studio/{Helper/AnimationHelper.cs => Internal/AnimationDeserializer.cs} (69%) create mode 100644 PCK-Studio/Internal/AnimationSerializer.cs rename PCK-Studio/Internal/{AnimationCategory.cs => ResourceCategory.cs} (90%) create mode 100644 PCK-Studio/Internal/ResourceLocation.cs diff --git a/PCK-Studio/Extensions/PckFileDataExtensions.cs b/PCK-Studio/Extensions/PckFileDataExtensions.cs index 7427a0d6..44d9ccad 100644 --- a/PCK-Studio/Extensions/PckFileDataExtensions.cs +++ b/PCK-Studio/Extensions/PckFileDataExtensions.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading.Tasks; using OMI.Formats.Pck; using OMI.Workers; +using PckStudio.Interfaces; using PckStudio.IO.TGA; namespace PckStudio.Extensions @@ -45,6 +46,22 @@ namespace PckStudio.Extensions } } + internal static T Get(this PckFileData file, IPckDeserializer deserializer) + { + return deserializer.Deserialize(file); + } + + internal static T Get(this PckFileData file, IDataFormatReader deserializer) where T : class + { + using var ms = new MemoryStream(file.Data); + return deserializer.FromStream(ms); + } + + internal static void SetData(this PckFileData file, T obj, IPckFileSerializer serializer) + { + serializer.Serialize(obj, ref file); + } + internal static void SetData(this PckFileData file, IDataFormatWriter writer) { using (var stream = new MemoryStream()) diff --git a/PCK-Studio/Forms/Additional-Popups/Animation/ChangeTile.cs b/PCK-Studio/Forms/Additional-Popups/Animation/ChangeTile.cs index 2fe99dca..9c73ce19 100644 --- a/PCK-Studio/Forms/Additional-Popups/Animation/ChangeTile.cs +++ b/PCK-Studio/Forms/Additional-Popups/Animation/ChangeTile.cs @@ -11,11 +11,11 @@ namespace PckStudio.Forms.Additional_Popups.Animation { internal partial class ChangeTile : MetroForm { - string selectedTile = ""; - AnimationCategory category = AnimationCategory.Blocks; + private JsonTileInfo selectedTile; + private ResourceCategory category = ResourceCategory.BlockAnimation; - public string SelectedTile => selectedTile; - public AnimationCategory Category => category; + public JsonTileInfo SelectedTile => selectedTile; + public ResourceCategory Category => category; List treeViewBlockCache = new List(); List treeViewItemCache = new List(); @@ -31,8 +31,8 @@ namespace PckStudio.Forms.Additional_Popups.Animation private void InitializeTreeviews() { Profiler.Start(); - GetTileDataToView(AnimationCategory.Blocks, treeViewBlocks.Nodes, treeViewBlockCache.Add); - GetTileDataToView(AnimationCategory.Items, treeViewItems.Nodes, treeViewItemCache.Add); + GetTileDataToView(ResourceCategory.BlockAnimation, treeViewBlocks.Nodes, treeViewBlockCache.Add); + GetTileDataToView(ResourceCategory.ItemAnimation, treeViewItems.Nodes, treeViewItemCache.Add); Profiler.Stop(); } @@ -40,19 +40,19 @@ namespace PckStudio.Forms.Additional_Popups.Animation { if (e.Node.Tag is JsonTileInfo tileData) { - selectedTile = tileData.InternalName; + selectedTile = tileData; category = e.Node.TreeView == treeViewItems - ? AnimationCategory.Items - : AnimationCategory.Blocks; + ? ResourceCategory.ItemAnimation + : ResourceCategory.BlockAnimation; } } - private void GetTileDataToView(AnimationCategory key, TreeNodeCollection collection, Action additionalAction) + private void GetTileDataToView(ResourceCategory key, TreeNodeCollection collection, Action additionalAction) { List textureInfos = key switch { - AnimationCategory.Blocks => Tiles.BlockTileInfos, - AnimationCategory.Items => Tiles.ItemTileInfos, + ResourceCategory.BlockAnimation => Tiles.BlockTileInfos, + ResourceCategory.ItemAnimation => Tiles.ItemTileInfos, _ => throw new InvalidOperationException(nameof(key)) }; Profiler.Start(); @@ -126,7 +126,7 @@ namespace PckStudio.Forms.Additional_Popups.Animation private void AcceptBtn_Click(object sender, EventArgs e) { - if (string.IsNullOrEmpty(selectedTile)) + if (string.IsNullOrEmpty(selectedTile.InternalName)) { DialogResult = DialogResult.Cancel; return; diff --git a/PCK-Studio/Forms/Editor/AnimationEditor.Designer.cs b/PCK-Studio/Forms/Editor/AnimationEditor.Designer.cs index dfe5cdfa..4fed8d2a 100644 --- a/PCK-Studio/Forms/Editor/AnimationEditor.Designer.cs +++ b/PCK-Studio/Forms/Editor/AnimationEditor.Designer.cs @@ -48,7 +48,6 @@ this.gifToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.bulkAnimationSpeedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.changeTileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.frameTimeandTicksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.howToInterpolation = new System.Windows.Forms.ToolStripMenuItem(); @@ -215,8 +214,7 @@ // editToolStripMenuItem // this.editToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.bulkAnimationSpeedToolStripMenuItem, - this.changeTileToolStripMenuItem}); + this.bulkAnimationSpeedToolStripMenuItem}); this.editToolStripMenuItem.ForeColor = System.Drawing.Color.White; this.editToolStripMenuItem.Name = "editToolStripMenuItem"; this.editToolStripMenuItem.Size = new System.Drawing.Size(46, 20); @@ -229,13 +227,6 @@ this.bulkAnimationSpeedToolStripMenuItem.Text = "Set Bulk Animation Speed"; this.bulkAnimationSpeedToolStripMenuItem.Click += new System.EventHandler(this.bulkAnimationSpeedToolStripMenuItem_Click); // - // changeTileToolStripMenuItem - // - this.changeTileToolStripMenuItem.Name = "changeTileToolStripMenuItem"; - this.changeTileToolStripMenuItem.Size = new System.Drawing.Size(210, 22); - this.changeTileToolStripMenuItem.Text = "Change Tile"; - this.changeTileToolStripMenuItem.Click += new System.EventHandler(this.changeTileToolStripMenuItem_Click); - // // helpToolStripMenuItem // this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -337,7 +328,6 @@ this.animationPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; this.animationPictureBox.TabIndex = 16; this.animationPictureBox.TabStop = false; - this.animationPictureBox.UseBlendColor = false; // // AnimationEditor // @@ -382,7 +372,6 @@ private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem bulkAnimationSpeedToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem changeTileToolStripMenuItem; private MetroFramework.Controls.MetroLabel tileLabel; private System.Windows.Forms.ToolStripMenuItem howToInterpolation; private System.Windows.Forms.ToolStripMenuItem editorControlsToolStripMenuItem; diff --git a/PCK-Studio/Forms/Editor/AnimationEditor.cs b/PCK-Studio/Forms/Editor/AnimationEditor.cs index 456c5b32..5428df94 100644 --- a/PCK-Studio/Forms/Editor/AnimationEditor.cs +++ b/PCK-Studio/Forms/Editor/AnimationEditor.cs @@ -40,35 +40,27 @@ namespace PckStudio.Forms.Editor { public partial class AnimationEditor : MetroForm { + public Animation Result => _animation; + private Animation _animation; - - private string _tileName = string.Empty; - - public string FinalPath => $"res/textures/{_animation.CategoryString}/{_tileName}.png"; - - private static readonly string[] specialTileNames = { "clock", "compass" }; - - private static bool IsSpecialTile(string name) - { - return name.ToLower().EqualsAny(specialTileNames); - } - + private bool _isSpecialTile; private AnimationEditor() { InitializeComponent(); toolStripSeparator1.Visible = saveToolStripMenuItem1.Visible = !Settings.Default.AutoSaveChanges; } - internal AnimationEditor(Animation animation, string name) + internal AnimationEditor(Animation animation, string displayName, bool isSpecialTile = false) : this() { _ = animation ?? throw new ArgumentNullException(nameof(animation)); _animation = animation; - _tileName = name; + tileLabel.Text = displayName; + _isSpecialTile = isSpecialTile; } - internal AnimationEditor(Animation animation, string name, Color blendColor) - : this(animation, name) + internal AnimationEditor(Animation animation, string displayName, Color blendColor) + : this(animation, displayName) { animationPictureBox.UseBlendColor = true; animationPictureBox.BlendColor = blendColor; @@ -79,15 +71,12 @@ namespace PckStudio.Forms.Editor bulkAnimationSpeedToolStripMenuItem.Enabled = importToolStripMenuItem.Enabled = exportAsToolStripMenuItem.Enabled = - changeTileToolStripMenuItem.Enabled = - InterpolationCheckbox.Visible = !IsSpecialTile(_tileName); + InterpolationCheckbox.Visible = !_isSpecialTile; } private void AnimationEditor_Load(object sender, EventArgs e) { ValidateToolStrip(); - - SetTileLabel(); LoadAnimationTreeView(); } @@ -170,7 +159,7 @@ namespace PckStudio.Forms.Editor private void saveToolStripMenuItem1_Click(object sender, EventArgs e) { - if (!IsSpecialTile(_tileName) && _animation is not null && _animation.FrameCount > 0) + if (!_isSpecialTile && _animation is not null && _animation.FrameCount > 0) { DialogResult = DialogResult.OK; return; @@ -279,7 +268,7 @@ namespace PckStudio.Forms.Editor diag.SaveBtn.Text = "Add"; if (diag.ShowDialog(this) == DialogResult.OK) { - _animation.AddFrame(diag.FrameTextureIndex, IsSpecialTile(_tileName) ? Animation.MinimumFrameTime : diag.FrameTime); + _animation.AddFrame(diag.FrameTextureIndex, _isSpecialTile ? Animation.MinimumFrameTime : diag.FrameTime); UpdateTreeView(); } } @@ -336,8 +325,8 @@ namespace PckStudio.Forms.Editor { var img = Image.FromFile(textureFile); JObject mcmeta = JObject.Parse(File.ReadAllText(fileDialog.FileName)); - Animation javaAnimation = AnimationHelper.GetAnimationFromJavaAnimation(mcmeta, img); - javaAnimation.Category = _animation.Category; + Animation javaAnimation = AnimationDeserializer.DefaultDeserializer.DeserializeJavaAnimation(mcmeta, img); + //javaAnimation.Category = _animation.Category; _animation = javaAnimation; LoadAnimationTreeView(); } @@ -348,36 +337,7 @@ namespace PckStudio.Forms.Editor } } - private void changeTileToolStripMenuItem_Click(object sender, EventArgs e) - { - StopAnimation(); - using (ChangeTile diag = new ChangeTile()) - { - if (diag.ShowDialog(this) != DialogResult.OK) - return; - - Debug.WriteLine($"{diag.SelectedTile}"); - _animation.Category = diag.Category; - _tileName = diag.SelectedTile; - - ValidateToolStrip(); - - SetTileLabel(); - } - } - - private void SetTileLabel() - { - var textureInfos = _animation.Category switch - { - AnimationCategory.Blocks => Tiles.BlockTileInfos, - AnimationCategory.Items => Tiles.ItemTileInfos, - _ => throw new ArgumentOutOfRangeException(_animation.Category.ToString()) - }; - tileLabel.Text = textureInfos.FirstOrDefault(p => p.InternalName == _tileName)?.DisplayName ?? _tileName; - } - - private void exportJavaAnimationToolStripMenuItem_Click(object sender, EventArgs e) + private void exportJavaAnimationToolStripMenuItem_Click(object sender, EventArgs e) { SaveFileDialog fileDialog = new SaveFileDialog(); fileDialog.Title = "Please choose where you want to save your new animation"; @@ -466,11 +426,8 @@ namespace PckStudio.Forms.Editor textures.Add(new Bitmap(gif, oldResolution, oldResolution)); } - var animCat = _animation.Category; - - _animation = new Animation(textures, string.Empty); + _animation = new Animation(textures); _animation.Interpolate = InterpolationCheckbox.Checked; - _animation.Category = animCat; LoadAnimationTreeView(); } @@ -493,7 +450,7 @@ namespace PckStudio.Forms.Editor { var fileDialog = new SaveFileDialog() { - FileName = _tileName, + FileName = tileLabel.Text, Filter = "GIF file|*.gif" }; if (fileDialog.ShowDialog(this) != DialogResult.OK) diff --git a/PCK-Studio/Forms/Editor/GameRuleFileEditor.cs b/PCK-Studio/Forms/Editor/GameRuleFileEditor.cs index 1a820646..c8640a9c 100644 --- a/PCK-Studio/Forms/Editor/GameRuleFileEditor.cs +++ b/PCK-Studio/Forms/Editor/GameRuleFileEditor.cs @@ -35,71 +35,19 @@ namespace PckStudio.Forms.Editor { public partial class GameRuleFileEditor : MetroFramework.Forms.MetroForm { - private PckFileData _pckfile; private GameRuleFile _file; - private GameRuleFile.CompressionType compressionType; - private GameRuleFile.CompressionLevel compressionLevel; - private const string use_zlib = "Wii U, PS Vita"; - private const string use_deflate = "PS3"; - private const string use_xmem = "Xbox 360"; + public GameRuleFile Result => _file; - public GameRuleFileEditor() + private GameRuleFileEditor() { InitializeComponent(); - PromptForCompressionType(); saveToolStripMenuItem.Visible = !Settings.Default.AutoSaveChanges; } - private void PromptForCompressionType() + public GameRuleFileEditor(GameRuleFile gameRuleFile) : this() { - ItemSelectionPopUp dialog = new ItemSelectionPopUp(use_zlib, use_deflate, use_xmem); - dialog.LabelText = "Type"; - dialog.ButtonText = "Ok"; - if (dialog.ShowDialog() == DialogResult.OK) - { - switch(dialog.SelectedItem) - { - case use_zlib: - wiiUPSVitaToolStripMenuItem.Checked = true; - break; - case use_deflate: - pS3ToolStripMenuItem.Checked = true; - break; - case use_xmem: - xbox360ToolStripMenuItem.Checked = true; - break; - } - } - } - - public GameRuleFileEditor(PckFileData file) : this() - { - _pckfile = file; - using (var stream = new MemoryStream(file.Data)) - { - _file = OpenGameRuleFile(stream); - } - } - - public GameRuleFileEditor(Stream stream) : this() - { - _file = OpenGameRuleFile(stream); - } - - private GameRuleFile OpenGameRuleFile(Stream stream) - { - try - { - var reader = new GameRuleFileReader(compressionType); - return reader.FromStream(stream); - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - MessageBox.Show("Faild to open .grf/.grh file"); - } - return default!; + _file = gameRuleFile; } private void OnLoad(object sender, EventArgs e) @@ -267,77 +215,55 @@ namespace PckStudio.Forms.Editor MessageBox.Show("World grf saving is currently unsupported"); return; } - using (var stream = new MemoryStream()) - { - try - { - _pckfile?.SetData(new GameRuleFileWriter(_file)); - DialogResult = DialogResult.OK; - MessageBox.Show("Saved!"); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - MessageBox.Show($"Failed to save grf file\n{ex.Message}", "Save Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } + DialogResult = DialogResult.OK; + MessageBox.Show("Saved!"); } private void openToolStripMenuItem_Click(object sender, EventArgs e) { - OpenFileDialog dialog = new OpenFileDialog(); - dialog.Filter = "Game Rule File|*.grf"; - PromptForCompressionType(); - if (dialog.ShowDialog(this) == DialogResult.OK) - { - using (var fs = File.OpenRead(dialog.FileName)) - { - _file = OpenGameRuleFile(fs); - ReloadGameRuleTree(); - } - } + } private void noneToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - compressionLevel = GameRuleFile.CompressionLevel.None; + _file.Header.CompressionLevel = GameRuleFile.CompressionLevel.None; } private void compressedToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - compressionLevel = GameRuleFile.CompressionLevel.Compressed; + _file.Header.CompressionLevel = GameRuleFile.CompressionLevel.Compressed; } private void compressedRLEToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - compressionLevel = GameRuleFile.CompressionLevel.CompressedRle; + _file.Header.CompressionLevel = GameRuleFile.CompressionLevel.CompressedRle; } private void compressedRLECRCToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - compressionLevel = GameRuleFile.CompressionLevel.CompressedRleCrc; + _file.Header.CompressionLevel = GameRuleFile.CompressionLevel.CompressedRleCrc; } private void wiiUPSVitaToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - compressionType = GameRuleFile.CompressionType.Zlib; + _file.Header.CompressionType = GameRuleFile.CompressionType.Zlib; } private void pS3ToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - compressionType = GameRuleFile.CompressionType.Deflate; + _file.Header.CompressionType = GameRuleFile.CompressionType.Deflate; } private void xbox360ToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - compressionType = GameRuleFile.CompressionType.XMem; + _file.Header.CompressionType = GameRuleFile.CompressionType.XMem; } private void GameRuleFileEditor_FormClosing(object sender, FormClosingEventArgs e) diff --git a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs index 2f93d182..8c04414a 100644 --- a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs +++ b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs @@ -31,6 +31,7 @@ using OMI.Workers.Color; using PckStudio.Extensions; using PckStudio.Helper; +using PckStudio.Internal; using PckStudio.Internal.Json; namespace PckStudio.Forms.Editor @@ -248,7 +249,7 @@ namespace PckStudio.Forms.Editor hasAnimation && animationFile.Size > 0) { - var animation = AnimationHelper.GetAnimationFromFile(animationFile); + var animation = animationFile.Get(AnimationDeserializer.DefaultDeserializer); selectTilePictureBox.Start(animation); } } @@ -532,7 +533,7 @@ namespace PckStudio.Forms.Editor PckFileType.TextureFile ); - var animation = AnimationHelper.GetAnimationFromFile(file); + var animation = file.Get(AnimationDeserializer.DefaultDeserializer); var animationEditor = new AnimationEditor(animation, _selectedTile.Tile.InternalName, GetBlendColor()); if (animationEditor.ShowDialog() != DialogResult.OK) @@ -540,7 +541,7 @@ namespace PckStudio.Forms.Editor return; } - AnimationHelper.SaveAnimationToFile(file, animation); + file.SetData(animationEditor.Result, AnimationSerializer.DefaultSerializer); // so animations can automatically update upon saving SelectedIndex = _selectedTile.Index; } diff --git a/PCK-Studio/Interfaces/IPckDeserializer.cs b/PCK-Studio/Interfaces/IPckDeserializer.cs new file mode 100644 index 00000000..611acb82 --- /dev/null +++ b/PCK-Studio/Interfaces/IPckDeserializer.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OMI.Formats.Pck; + +namespace PckStudio.Interfaces +{ + internal interface IPckDeserializer + { + public T Deserialize(PckFileData file); + } +} \ No newline at end of file diff --git a/PCK-Studio/Interfaces/IPckFileSerializer.cs b/PCK-Studio/Interfaces/IPckFileSerializer.cs new file mode 100644 index 00000000..1d7d2335 --- /dev/null +++ b/PCK-Studio/Interfaces/IPckFileSerializer.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OMI.Formats.Pck; + +namespace PckStudio.Interfaces +{ + internal interface IPckFileSerializer + { + public void Serialize(T obj, ref PckFileData file); + } +} diff --git a/PCK-Studio/Internal/Animation.cs b/PCK-Studio/Internal/Animation.cs index 2b877380..66f8f6a5 100644 --- a/PCK-Studio/Internal/Animation.cs +++ b/PCK-Studio/Internal/Animation.cs @@ -25,44 +25,24 @@ using System.Linq; namespace PckStudio.Internal { - internal sealed class Animation + public sealed class Animation { public const int MinimumFrameTime = 1; public const int GameTickInMilliseconds = 50; - public static Animation Empty(AnimationCategory category) - { - var animation = new Animation(Array.Empty(), string.Empty); - animation.Category = category; - return animation; - } - public int FrameCount => frames.Count; public int TextureCount => textures.Count; public bool Interpolate { get; set; } = false; - - public AnimationCategory Category { get; set; } - - public string CategoryString => GetCategoryName(Category); - - public static string GetCategoryName(AnimationCategory category) - { - return category switch - { - AnimationCategory.Items => "items", - AnimationCategory.Blocks => "blocks", - _ => throw new ArgumentOutOfRangeException(category.ToString()) - }; - } - private readonly List textures; private readonly IList frames = new List(); + private object _syncLock = new object(); + public Animation(IEnumerable textures) { this.textures = new List(textures); @@ -215,7 +195,7 @@ namespace PckStudio.Internal public void SetFrame(int frameIndex, Frame frame) { - lock(frames) + lock(_syncLock) { frames[frameIndex] = frame; } @@ -245,7 +225,7 @@ namespace PckStudio.Internal internal void SetFrameTicks(int ticks) { - lock(frames) + lock(_syncLock) { foreach (var frame in frames) { @@ -256,10 +236,15 @@ namespace PckStudio.Internal internal void SwapFrames(int sourceIndex, int destinationIndex) { - lock(frames) + lock(_syncLock) { frames.Swap(sourceIndex, destinationIndex); } } + + internal static Animation CreateEmpty() + { + return new Animation(Array.Empty()); + } } } diff --git a/PCK-Studio/Helper/AnimationHelper.cs b/PCK-Studio/Internal/AnimationDeserializer.cs similarity index 69% rename from PCK-Studio/Helper/AnimationHelper.cs rename to PCK-Studio/Internal/AnimationDeserializer.cs index 0312624a..62eac630 100644 --- a/PCK-Studio/Helper/AnimationHelper.cs +++ b/PCK-Studio/Internal/AnimationDeserializer.cs @@ -2,28 +2,21 @@ using System.Collections.Generic; using System.Diagnostics; using System.Drawing; -using System.Drawing.Imaging; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json.Linq; using OMI.Formats.Pck; using PckStudio.Extensions; -using PckStudio.Internal; +using PckStudio.Interfaces; -namespace PckStudio.Helper +namespace PckStudio.Internal { - internal static class AnimationHelper + internal sealed class AnimationDeserializer : IPckDeserializer { - internal static void SaveAnimationToFile(PckFileData file, Animation animation) - { - string anim = animation.BuildAnim(); - file.SetProperty("ANIM", anim); - var texture = animation.BuildTexture(); - file.SetData(texture, ImageFormat.Png); - } - - internal static Animation GetAnimationFromFile(PckFileData file) + public static readonly AnimationDeserializer DefaultDeserializer = new AnimationDeserializer(); + + public Animation Deserialize(PckFileData file) { _ = file ?? throw new ArgumentNullException(nameof(file)); if (file.Size > 0) @@ -31,25 +24,20 @@ namespace PckStudio.Helper var texture = file.GetTexture(); var frameTextures = texture.Split(ImageLayoutDirection.Vertical); var _animation = new Animation(frameTextures, file.GetProperty("ANIM")); - _animation.Category = file.Filename.Split('/').Contains("items") - ? AnimationCategory.Items - : AnimationCategory.Blocks; return _animation; } - return Animation.Empty(file.Filename.Split('/').Contains("items") - ? AnimationCategory.Items - : AnimationCategory.Blocks); + return Animation.CreateEmpty(); } - internal static Animation GetAnimationFromJavaAnimation(JObject jsonObject, Image texture) + public Animation DeserializeJavaAnimation(JObject jsonObject, Image texture) { var textures = texture.Split(ImageLayoutDirection.Vertical); Animation result = new Animation(textures); if (jsonObject["animation"] is not JToken animation) return result; - + int frameTime = Animation.MinimumFrameTime; - + if (animation["frametime"] is JToken frametime_token && frametime_token.Type == JTokenType.Integer) frameTime = (int)frametime_token; @@ -60,12 +48,12 @@ namespace PckStudio.Helper { foreach (JToken frame in frames_token.Children()) { - if (frame.Type == JTokenType.Object && + if (frame.Type == JTokenType.Object && frame["index"] is JToken frame_index && frame_index.Type == JTokenType.Integer && frame["time"] is JToken frame_time && frame_time.Type == JTokenType.Integer) - { + { Debug.WriteLine("Index: {0}, Time: {1}", frame_index, frame_time); result.AddFrame((int)frame_index, (int)frame_time); } diff --git a/PCK-Studio/Internal/AnimationSerializer.cs b/PCK-Studio/Internal/AnimationSerializer.cs new file mode 100644 index 00000000..426f4f00 --- /dev/null +++ b/PCK-Studio/Internal/AnimationSerializer.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using OMI.Formats.Pck; +using PckStudio.Extensions; +using PckStudio.Interfaces; + +namespace PckStudio.Internal +{ + internal sealed class AnimationSerializer : IPckFileSerializer + { + public static readonly AnimationSerializer DefaultSerializer = new AnimationSerializer(); + + public void Serialize(Animation animation, ref PckFileData file) + { + string anim = animation.BuildAnim(); + file.SetProperty("ANIM", anim); + var texture = animation.BuildTexture(); + file.SetData(texture, ImageFormat.Png); + } + } +} diff --git a/PCK-Studio/Internal/AnimationCategory.cs b/PCK-Studio/Internal/ResourceCategory.cs similarity index 90% rename from PCK-Studio/Internal/AnimationCategory.cs rename to PCK-Studio/Internal/ResourceCategory.cs index 8cae76b2..0233ef62 100644 --- a/PCK-Studio/Internal/AnimationCategory.cs +++ b/PCK-Studio/Internal/ResourceCategory.cs @@ -18,9 +18,10 @@ namespace PckStudio.Internal { - internal enum AnimationCategory + internal enum ResourceCategory { - Items, - Blocks + Unknown = -1, + ItemAnimation, + BlockAnimation } } diff --git a/PCK-Studio/Internal/ResourceLocation.cs b/PCK-Studio/Internal/ResourceLocation.cs new file mode 100644 index 00000000..e9984d86 --- /dev/null +++ b/PCK-Studio/Internal/ResourceLocation.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Internal +{ + internal class ResourceLocation + { + public static string GetPathFromCategory(ResourceCategory category) + { + return category switch + { + ResourceCategory.ItemAnimation => "res/textures/items", + ResourceCategory.BlockAnimation => "res/textures/blocks", + _ => string.Empty + }; + } + + public static ResourceCategory GetCategoryFromPath(string path) + { + if (string.IsNullOrWhiteSpace(path) || !path.StartsWith("res/")) + return ResourceCategory.Unknown; + + if (path.StartsWith("res/textures/items")) + return ResourceCategory.ItemAnimation; + + if (path.StartsWith("res/textures/blocks")) + return ResourceCategory.BlockAnimation; + + return ResourceCategory.Unknown; + } + } +} diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 3557770e..8757b0e4 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -31,6 +31,7 @@ using PckStudio.Popups; using PckStudio.Classes.Utils; using PckStudio.Helper; using System.Text.RegularExpressions; +using PckStudio.Internal.Json; namespace PckStudio { @@ -511,16 +512,29 @@ namespace PckStudio return; } - if (!file.Filename.StartsWith("res/textures/blocks/") && !file.Filename.StartsWith("res/textures/items/")) + if (!file.Filename.StartsWith(ResourceLocation.GetPathFromCategory(ResourceCategory.ItemAnimation)) && + !file.Filename.StartsWith(ResourceLocation.GetPathFromCategory(ResourceCategory.BlockAnimation))) return; - Animation animation = AnimationHelper.GetAnimationFromFile(file); - using (AnimationEditor animationEditor = new AnimationEditor(animation, Path.GetFileNameWithoutExtension(file.Filename))) + + Animation animation = file.Get(AnimationDeserializer.DefaultDeserializer); + string filename = Path.GetFileNameWithoutExtension(file.Filename); + + var textureInfos = ResourceLocation.GetCategoryFromPath(file.Filename) switch + { + ResourceCategory.BlockAnimation => Tiles.BlockTileInfos, + ResourceCategory.ItemAnimation => Tiles.ItemTileInfos, + _ => Array.Empty().ToList() + }; + string displayname = textureInfos.FirstOrDefault(p => p.InternalName == filename)?.DisplayName ?? filename; + + string[] specialTileNames = { "clock", "compass" }; + + using (AnimationEditor animationEditor = new AnimationEditor(animation, displayname, filename.ToLower().EqualsAny(specialTileNames))) { if (animationEditor.ShowDialog(this) == DialogResult.OK) { wasModified = true; - file.Filename = animationEditor.FinalPath; - AnimationHelper.SaveAnimationToFile(file, animation); + file.SetData(animationEditor.Result, AnimationSerializer.DefaultSerializer); BuildMainTreeView(); } } @@ -528,9 +542,33 @@ namespace PckStudio private void HandleGameRuleFile(PckFileData file) { - using GameRuleFileEditor grfEditor = new GameRuleFileEditor(file); - wasModified = grfEditor.ShowDialog(this) == DialogResult.OK; - UpdateRichPresence(); + const string use_deflate = "PS3"; + const string use_xmem = "Xbox 360"; + const string use_zlib = "Wii U, PS Vita"; + + ItemSelectionPopUp dialog = new ItemSelectionPopUp(use_zlib, use_deflate, use_xmem); + dialog.LabelText = "Type"; + dialog.ButtonText = "Ok"; + if (dialog.ShowDialog() != DialogResult.OK) + return; + + var compressiontype = dialog.SelectedItem switch + { + use_deflate => GameRuleFile.CompressionType.Deflate, + use_xmem => GameRuleFile.CompressionType.XMem, + use_zlib => GameRuleFile.CompressionType.Zlib, + _ => GameRuleFile.CompressionType.Unknown + }; + + GameRuleFile grf = file.Get(new GameRuleFileReader(compressiontype)); + + using GameRuleFileEditor grfEditor = new GameRuleFileEditor(grf); + if (grfEditor.ShowDialog(this) == DialogResult.OK) + { + file.SetData(new GameRuleFileWriter(grfEditor.Result)); + wasModified = true; + UpdateRichPresence(); + } } private void HandleAudioFile(PckFileData file) @@ -636,7 +674,8 @@ namespace PckStudio Debug.WriteLine(string.Format("An error occured of type: {0} with message: {1}", ex.GetType(), ex.Message), "Exception"); } - if ((file.Filename.StartsWith("res/textures/blocks/") || file.Filename.StartsWith("res/textures/items/")) && + if ((file.Filename.StartsWith(ResourceLocation.GetPathFromCategory(ResourceCategory.ItemAnimation)) || + file.Filename.StartsWith(ResourceLocation.GetPathFromCategory(ResourceCategory.BlockAnimation))) && file.Filetype == PckFileType.TextureFile && !file.IsMipmappedFile()) { @@ -832,11 +871,11 @@ namespace PckStudio /// True if the remove should be canceled, otherwise False private bool BeforeFileRemove(PckFileData file) { - string itemPath = "res/textures/items/"; + string itemPath = ResourceLocation.GetPathFromCategory(ResourceCategory.ItemAnimation); // warn the user about deleting compass.png and clock.png if (file.Filetype == PckFileType.TextureFile && - (file.Filename == itemPath + "compass.png" || file.Filename == itemPath + "clock.png")) + (file.Filename == itemPath + "/compass.png" || file.Filename == itemPath + "/clock.png")) { if (MessageBox.Show("Are you sure want to delete this file? If \"compass.png\" or \"clock.png\" are missing, your game will crash upon loading this pack.", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) @@ -1013,24 +1052,20 @@ namespace PckStudio if (diag.ShowDialog(this) != DialogResult.OK) return; - if (currentPCK.Contains($"res/textures/{Animation.GetCategoryName(diag.Category)}/{diag.SelectedTile}.png", PckFileType.TextureFile)) + string animationFilepath = $"{ResourceLocation.GetPathFromCategory(diag.Category)}/{diag.SelectedTile}.png"; + + if (currentPCK.Contains(animationFilepath, PckFileType.TextureFile)) { MessageBox.Show($"{diag.SelectedTile} is already present.", "File already present"); return; } - var file = new PckFileData( - $"res/textures/{Animation.GetCategoryName(diag.Category)}/{diag.SelectedTile}.png", - PckFileType.TextureFile); - - Animation animation = AnimationHelper.GetAnimationFromFile(file); - - using AnimationEditor animationEditor = new AnimationEditor(animation, diag.SelectedTile); + using AnimationEditor animationEditor = new AnimationEditor(Animation.CreateEmpty(), diag.SelectedTile.DisplayName, diag.SelectedTile.InternalName.EqualsAny("clock", "compass")); if (animationEditor.ShowDialog() == DialogResult.OK) { wasModified = true; - AnimationHelper.SaveAnimationToFile(file, animation); - currentPCK.AddFile(file); + PckFileData file = currentPCK.CreateNewFile(animationFilepath, PckFileType.TextureFile); + file.SetData(animationEditor.Result, AnimationSerializer.DefaultSerializer); BuildMainTreeView(); ReloadMetaTreeView(); } diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index a4399559..dbb02640 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -138,9 +138,13 @@ - - + + + + + +