Add IPckSerializer and IPckDeserializer and Update Animation/AnimationEditor

This commit is contained in:
miku-666
2024-03-31 17:26:25 +02:00
parent 1f359ce8a7
commit e36ebe5878
15 changed files with 245 additions and 251 deletions

View File

@@ -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<T>(this PckFileData file, IPckDeserializer<T> deserializer)
{
return deserializer.Deserialize(file);
}
internal static T Get<T>(this PckFileData file, IDataFormatReader<T> deserializer) where T : class
{
using var ms = new MemoryStream(file.Data);
return deserializer.FromStream(ms);
}
internal static void SetData<T>(this PckFileData file, T obj, IPckFileSerializer<T> serializer)
{
serializer.Serialize(obj, ref file);
}
internal static void SetData(this PckFileData file, IDataFormatWriter writer)
{
using (var stream = new MemoryStream())

View File

@@ -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<TreeNode> treeViewBlockCache = new List<TreeNode>();
List<TreeNode> treeViewItemCache = new List<TreeNode>();
@@ -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<TreeNode> additionalAction)
private void GetTileDataToView(ResourceCategory key, TreeNodeCollection collection, Action<TreeNode> additionalAction)
{
List<JsonTileInfo> 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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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<T>
{
public T Deserialize(PckFileData file);
}
}

View File

@@ -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<T>
{
public void Serialize(T obj, ref PckFileData file);
}
}

View File

@@ -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<Image>(), 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<Image> textures;
private readonly IList<Frame> frames = new List<Frame>();
private object _syncLock = new object();
public Animation(IEnumerable<Image> textures)
{
this.textures = new List<Image>(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<Image>());
}
}
}

View File

@@ -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<Animation>
{
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);
}

View File

@@ -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<Animation>
{
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);
}
}
}

View File

@@ -18,9 +18,10 @@
namespace PckStudio.Internal
{
internal enum AnimationCategory
internal enum ResourceCategory
{
Items,
Blocks
Unknown = -1,
ItemAnimation,
BlockAnimation
}
}

View File

@@ -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;
}
}
}

View File

@@ -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<JsonTileInfo>().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
/// <returns>True if the remove should be canceled, otherwise False</returns>
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();
}

View File

@@ -138,9 +138,13 @@
<Compile Include="Extensions\LocFileExtensions.cs" />
<Compile Include="Extensions\PckFileDataExtensions.cs" />
<Compile Include="Extensions\TreeNodeExtensions.cs" />
<Compile Include="Helper\AnimationHelper.cs" />
<Compile Include="Internal\AnimationCategory.cs" />
<Compile Include="Internal\AnimationSerializer.cs" />
<Compile Include="Internal\AnimationDeserializer.cs" />
<Compile Include="Interfaces\IPckDeserializer.cs" />
<Compile Include="Interfaces\IPckFileSerializer.cs" />
<Compile Include="Internal\ResourceCategory.cs" />
<Compile Include="Internal\CommitInfo.cs" />
<Compile Include="Internal\ResourceLocation.cs" />
<Compile Include="Internal\SkinAnimFlag.cs" />
<Compile Include="Internal\SkinAnimMask.cs" />
<Compile Include="Properties\Resources.Designer.cs">