Files
PCK-Studio/PckStudio.Core/Deserializer/AnimationDeserializer.cs

116 lines
4.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using OMI.Formats.Pck;
using PckStudio.Core;
using PckStudio.Core.Extensions;
using PckStudio.Interfaces;
namespace PckStudio.Core.Deserializer
{
public sealed class AnimationDeserializer : IPckAssetDeserializer<Animation>
{
public static readonly AnimationDeserializer DefaultDeserializer = new AnimationDeserializer();
public Animation Deserialize(PckAsset asset)
{
_ = asset ?? throw new ArgumentNullException(nameof(asset));
if (asset.Size > 0)
{
Image texture = asset.GetTexture();
IEnumerable<Image> frameTextures = texture.Split(ImageLayoutDirection.Vertical);
string animString = asset.GetProperty("ANIM");
bool animStringIsEmpty = string.IsNullOrEmpty(animString);
Animation animation = new Animation(frameTextures, animStringIsEmpty);
if (!animStringIsEmpty)
DeserializeAnimationAnim(ref animation, animString);
return animation;
}
return Animation.CreateEmpty();
}
private static bool DeserializeAnimationAnim(ref Animation animation, string animString)
{
animString = animString.Trim();
animation.Interpolate = animString.StartsWith("#");
animString = animation.Interpolate ? animString.Substring(1) : animString;
string[] animData = animString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (animData.Length <= 0)
{
Trace.TraceError($"[{nameof(AnimationExtensions)}:{nameof(DeserializeAnimationAnim)}] Failed to parse anim. animData was empty.");
return false;
}
int lastFrameTime = Animation.MinimumFrameTime;
foreach (string frameInfo in animData)
{
string[] frameData = frameInfo.Split('*');
int currentFrameIndex = 0;
int.TryParse(frameData[0], out currentFrameIndex);
// Some textures like the Halloween 2015's Lava texture don't have a
// frame time parameter for certain frames.
// This will detect that and place the last frame time in its place.
// This is accurate to console edition behavior.
// - MattNL
int currentFrameTime = frameData.Length < 2 || string.IsNullOrEmpty(frameData[1]) ? lastFrameTime : int.Parse(frameData[1]);
animation.AddFrame(currentFrameIndex, currentFrameTime);
lastFrameTime = currentFrameTime;
}
return true;
}
public Animation DeserializeJavaAnimation(JObject jsonObject, Image texture)
{
IEnumerable<Image> 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;
if (animation["interpolate"] is JToken interpolate_token && interpolate_token.Type == JTokenType.Boolean)
result.Interpolate = (bool)interpolate_token;
if (animation["frames"] is JToken frames_token && frames_token.Type == JTokenType.Array)
{
foreach (JToken frame in frames_token.Children())
{
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);
}
else if (frame.Type == JTokenType.Integer)
{
Debug.WriteLine("Index: {0}, Time: {1}", frame, frameTime);
result.AddFrame((int)frame, frameTime);
}
}
return result;
}
for (int i = 0; i < result.TextureCount; i++)
{
result.AddFrame(i, frameTime);
}
return result;
}
}
}