using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Collections.Generic;
using OMI.Formats.Languages;
using OMI.Formats.Pck;
using OMI.Workers;
using PckStudio.Interfaces;
using PckStudio.Core.Deserializer;
using PckStudio.Core.Serializer;
using PckStudio.Core.Skin;
namespace PckStudio.Core.Extensions
{
public static class PckAssetExtensions
{
private const string MipMap = "MipMapLevel";
public static PckAsset CreateNewAssetIf(this PckFile pck, bool condition, string filename, PckAssetType filetype, IDataFormatWriter writer)
{
if (condition)
{
return pck.CreateNewAsset(filename, filetype, writer);
}
return default;
}
public static PckAsset CreateNewAsset(this PckFile pck, string filename, PckAssetType filetype, IDataFormatWriter writer)
{
PckAsset asset = pck.CreateNewAsset(filename, filetype);
asset.SetData(writer);
return asset;
}
public static Image GetTexture(this PckAsset asset)
{
if (asset.Type != PckAssetType.SkinFile &&
asset.Type != PckAssetType.CapeFile &&
asset.Type != PckAssetType.TextureFile)
{
throw new Exception("Asset is not suitable to contain image data.");
}
return asset.GetDeserializedData(ImageDeserializer.DefaultDeserializer);
}
///
/// Tries to get the skin id of the skin
///
///
/// Non-zero base number on success, otherwise 0
///
public static int GetSkinId(this PckAsset asset)
{
if (asset.Type != PckAssetType.SkinFile)
throw new InvalidOperationException("Asset is not a skin.");
const string skinAssetnamePrefix = "dlcskin";
string assetPath = Path.GetFileNameWithoutExtension(asset.Filename);
if (!assetPath.StartsWith(skinAssetnamePrefix))
{
Trace.TraceWarning($"[{nameof(GetSkinId)}] Asset name does not start with '{skinAssetnamePrefix}'");
return 0;
}
int skinId = 0;
if (!int.TryParse(assetPath.Substring(skinAssetnamePrefix.Length), out skinId))
{
Trace.TraceWarning($"[{nameof(GetSkinId)}] Failed to parse Skin Id");
}
return skinId;
}
public static Skin.Skin GetSkin(this PckAsset asset)
{
if (asset.Type != PckAssetType.SkinFile)
throw new InvalidOperationException("Asset is not a skin.");
int skinId = asset.GetSkinId();
string name = asset.GetParameter("DISPLAYNAME");
Image texture = asset.GetTexture();
SkinANIM anim = asset.GetParameter("ANIM", SkinANIM.FromString);
SkinGameFlags gameFlags = asset.GetParameter("GAME_FLAGS", SkinGameFlags.FromString);
IEnumerable boxes = asset.GetMultipleParameters("BOX").Select(kv => SkinBOX.FromString(kv.Value));
IEnumerable offsets = asset.GetMultipleParameters("OFFSET").Select(kv => SkinPartOffset.FromString(kv.Value));
return new Skin.Skin(name, skinId, texture, anim, gameFlags, boxes, offsets);
}
public static void SetSkin(this PckAsset asset, Skin.Skin skin, LOCFile localizationFile)
{
if (asset.Type != PckAssetType.SkinFile)
throw new InvalidOperationException("Asset is not a skin file");
asset.SetTexture(skin.Texture);
string skinId = skin.Identifier.ToString("d08");
// TODO: keep filepath
asset.Filename = $"dlcskin{skinId}.png";
asset.SetParameter("DISPLAYNAME", skin.MetaData.Name);
if (localizationFile is not null)
{
string skinLocKey = $"IDS_dlcskin{skinId}_DISPLAYNAME";
asset.SetParameter("DISPLAYNAMEID", skinLocKey);
localizationFile.SetLocEntry(skinLocKey, skin.MetaData.Name);
}
if (!string.IsNullOrEmpty(skin.MetaData.Theme))
{
asset.SetParameter("THEMENAME", skin.MetaData.Theme);
if (localizationFile is not null)
{
string skinThemeLocKey = $"IDS_dlcskin{skinId}_THEMENAME";
asset.SetParameter("THEMENAMEID", skinThemeLocKey);
localizationFile.SetLocEntry(skinThemeLocKey, skin.MetaData.Theme);
}
}
if (skin.HasCape)
{
asset.SetParameter("CAPEPATH", $"dlccape{skinId}.png");
}
asset.SetParameter("ANIM", skin.Anim.ToString());
asset.SetParameter("GAME_FLAGS", skin.GameFlags.ToString());
asset.SetParameter("FREE", "1");
asset.RemoveParameters("BOX");
asset.RemoveParameters("OFFSET");
foreach (SkinBOX box in skin.Model.AdditionalBoxes)
{
asset.AddParameter(box.ToParameter());
}
foreach (SkinPartOffset offset in skin.Model.PartOffsets)
{
asset.AddParameter(offset.ToParameter());
}
}
public static T GetDeserializedData(this PckAsset asset, IPckAssetDeserializer deserializer)
{
return deserializer.Deserialize(asset);
}
public static T GetData(this PckAsset asset, IDataFormatReader formatReader) where T : class
{
using var ms = new MemoryStream(asset.Data);
return formatReader.FromStream(ms);
}
public static void SetSerializedData(this PckAsset asset, T obj, IPckAssetSerializer serializer)
{
serializer.Serialize(obj, ref asset);
}
public static void SetData(this PckAsset asset, IDataFormatWriter formatWriter)
{
using (var stream = new MemoryStream())
{
formatWriter.WriteToStream(stream);
asset.SetData(stream.ToArray());
}
}
public static void SetTexture(this PckAsset asset, Image image)
{
if (asset.Type != PckAssetType.SkinFile &&
asset.Type != PckAssetType.CapeFile &&
asset.Type != PckAssetType.TextureFile)
{
throw new Exception("Asset is not suitable to contain image data.");
}
asset.SetSerializedData(image, ImageSerializer.DefaultSerializer);
}
public static bool IsMipmappedFile(this PckAsset asset)
{
// We only want to test the file name itself. ex: "terrainMipMapLevel2"
string name = Path.GetFileNameWithoutExtension(asset.Filename);
// check if last character is a digit (0-9). If not return false
if (!char.IsDigit(name[name.Length - 1]))
return false;
// If string does not end with MipMapLevel, then it's not MipMapped
if (!name.Remove(name.Length - 1, 1).EndsWith(MipMap))
return false;
return true;
}
public static string GetNormalPath(this PckAsset asset)
{
if (!asset.IsMipmappedFile())
return asset.Filename;
string ext = Path.GetExtension(asset.Filename);
return asset.Filename.Remove(asset.Filename.Length - (MipMap.Length + 1) - ext.Length) + ext;
}
public static void DeserializeParameters(this PckAsset asset, IEnumerable serializedData)
{
IEnumerable> lines = serializedData
.Select(line => line.Split([' '], 2))
.Where (keyValue => keyValue.Length == 2)
.Select(keyValue => new KeyValuePair(keyValue[0].Replace(":", ""), keyValue[1]));
foreach (KeyValuePair kv in lines)
{
asset.AddParameter(kv);
}
}
public static IEnumerable SerializeParameters(this PckAsset asset, string separator = ":")
{
IReadOnlyList> parameters = asset.GetParameters();
return parameters.Select(parameter => parameter.Key + separator + parameter.Value);
}
}
}