mirror of
https://github.com/BlackMATov/unity-flash-tools.git
synced 2025-12-13 03:30:14 +07:00
530 lines
15 KiB
C#
530 lines
15 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using System.Security.Cryptography;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
|
|
using Ionic.Zlib;
|
|
using IZ = Ionic.Zlib;
|
|
|
|
using FTRuntime;
|
|
|
|
namespace FTEditor {
|
|
static class SwfEditorUtils {
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// Compatibility
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
public static T FindObjectOfType<T>() where T : Object {
|
|
#if UNITY_2021_3_OR_NEWER
|
|
return Object.FindAnyObjectByType<T>();
|
|
#else
|
|
return Object.FindObjectOfType<T>();
|
|
#endif
|
|
}
|
|
|
|
public static T[] FindObjectsOfType<T>() where T : Object {
|
|
#if UNITY_2021_3_OR_NEWER
|
|
return Object.FindObjectsByType<T>(FindObjectsSortMode.None);
|
|
#else
|
|
return Object.FindObjectsOfType<T>();
|
|
#endif
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// Packing
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
const ushort UShortMax = ushort.MaxValue;
|
|
const float FColorPrecision = 1.0f / 512.0f;
|
|
|
|
public static uint PackUV(float u, float v) {
|
|
var uu = (uint)(Mathf.Clamp01(u) * UShortMax);
|
|
var vv = (uint)(Mathf.Clamp01(v) * UShortMax);
|
|
return (uu << 16) + vv;
|
|
}
|
|
|
|
public static ushort PackFloatColorToUShort(float v) {
|
|
return (ushort)Mathf.Clamp(
|
|
v * (1.0f / FColorPrecision),
|
|
short.MinValue,
|
|
short.MaxValue);
|
|
}
|
|
|
|
public static uint PackUShortsToUInt(ushort x, ushort y) {
|
|
var xx = (uint)x;
|
|
var yy = (uint)y;
|
|
return (xx << 16) + yy;
|
|
}
|
|
|
|
public static void PackFColorToUInts(
|
|
Color v,
|
|
out uint pack0, out uint pack1)
|
|
{
|
|
PackFColorToUInts(v.r, v.g, v.b, v.a, out pack0, out pack1);
|
|
}
|
|
|
|
public static void PackFColorToUInts(
|
|
Vector4 v,
|
|
out uint pack0, out uint pack1)
|
|
{
|
|
PackFColorToUInts(v.x, v.y, v.z, v.w, out pack0, out pack1);
|
|
}
|
|
|
|
public static void PackFColorToUInts(
|
|
float v0, float v1, float v2, float v3,
|
|
out uint pack0, out uint pack1)
|
|
{
|
|
pack0 = PackUShortsToUInt(
|
|
PackFloatColorToUShort(v0),
|
|
PackFloatColorToUShort(v1));
|
|
pack1 = PackUShortsToUInt(
|
|
PackFloatColorToUShort(v2),
|
|
PackFloatColorToUShort(v3));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// Inspector
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
public static void DoWithMixedValue(bool mixed, System.Action act) {
|
|
var last_show_mixed_value = EditorGUI.showMixedValue;
|
|
EditorGUI.showMixedValue = mixed;
|
|
try {
|
|
act();
|
|
} finally {
|
|
EditorGUI.showMixedValue = last_show_mixed_value;
|
|
}
|
|
}
|
|
|
|
public static void DoWithEnabledGUI(bool enabled, System.Action act) {
|
|
EditorGUI.BeginDisabledGroup(!enabled);
|
|
try {
|
|
act();
|
|
} finally {
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
}
|
|
|
|
public static void DoHorizontalGUI(System.Action act) {
|
|
GUILayout.BeginHorizontal();
|
|
try {
|
|
act();
|
|
} finally {
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
}
|
|
|
|
public static void DoRightHorizontalGUI(System.Action act) {
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.FlexibleSpace();
|
|
try {
|
|
act();
|
|
} finally {
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
}
|
|
|
|
public static void DoCenterHorizontalGUI(System.Action act) {
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.FlexibleSpace();
|
|
try {
|
|
act();
|
|
} finally {
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
}
|
|
|
|
public static SerializedProperty GetPropertyByName(SerializedObject obj, string name) {
|
|
var prop = obj.FindProperty(name);
|
|
if ( prop == null ) {
|
|
throw new UnityException(string.Format(
|
|
"SwfEditorUtils. Not found property: {0}",
|
|
name));
|
|
}
|
|
return prop;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// Assets
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
public static SwfSettings GetSettingsHolder() {
|
|
var holder = LoadFirstAssetDBByFilter<SwfSettings>("t:SwfSettings");
|
|
if ( !holder ) {
|
|
throw new UnityException(
|
|
"SwfEditorUtils. SwfSettings asset not found");
|
|
}
|
|
return holder;
|
|
}
|
|
|
|
public static T LoadOrCreateAsset<T>(string asset_path, System.Func<T, bool, bool> act) where T : ScriptableObject {
|
|
var asset = AssetDatabase.LoadAssetAtPath<T>(asset_path);
|
|
if ( asset ) {
|
|
if ( act(asset, false) ) {
|
|
EditorUtility.SetDirty(asset);
|
|
}
|
|
} else {
|
|
asset = ScriptableObject.CreateInstance<T>();
|
|
if ( act(asset, true) ) {
|
|
AssetDatabase.CreateAsset(asset, asset_path);
|
|
} else {
|
|
ScriptableObject.DestroyImmediate(asset);
|
|
}
|
|
}
|
|
return asset;
|
|
}
|
|
|
|
public static T LoadFirstAssetDBByFilter<T>(string filter) where T : UnityEngine.Object {
|
|
var guids = AssetDatabase.FindAssets(filter);
|
|
foreach ( var guid in guids ) {
|
|
var path = AssetDatabase.GUIDToAssetPath(guid);
|
|
var asset = AssetDatabase.LoadAssetAtPath<T>(path);
|
|
if ( asset ) {
|
|
return asset;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static T[] LoadAllAssetsDBByFilter<T>(string filter) where T : UnityEngine.Object {
|
|
return AssetDatabase.FindAssets(filter)
|
|
.Select (p => AssetDatabase.GUIDToAssetPath(p))
|
|
.Select (p => AssetDatabase.LoadAssetAtPath<T>(p))
|
|
.Where (p => !!p)
|
|
.ToArray();
|
|
}
|
|
|
|
public static byte[] CompressAsset<T>(T asset, System.Action<float> progress_act) {
|
|
var bytes = AssetToBytes(asset);
|
|
var result = CompressBuffer(bytes, progress_act);
|
|
return result;
|
|
}
|
|
|
|
public static T DecompressAsset<T>(byte[] data, System.Action<float> progress_act) {
|
|
var bytes = DecompressBuffer(data, progress_act);
|
|
var result = BytesToAsset<T>(bytes);
|
|
return result;
|
|
}
|
|
|
|
static byte[] AssetToBytes<T>(T asset) {
|
|
var formatter = new BinaryFormatter();
|
|
using ( var stream = new MemoryStream() ) {
|
|
formatter.Serialize(stream, asset);
|
|
return stream.ToArray();
|
|
}
|
|
}
|
|
|
|
static T BytesToAsset<T>(byte[] bytes) {
|
|
var formatter = new BinaryFormatter();
|
|
using ( var stream = new MemoryStream(bytes) ) {
|
|
return (T)formatter.Deserialize(stream);
|
|
}
|
|
}
|
|
|
|
static byte[] CompressBuffer(byte[] bytes, System.Action<float> progress_act) {
|
|
using ( var output = new MemoryStream() ) {
|
|
using ( var compressor = new ZlibStream(output, IZ.CompressionMode.Compress, IZ.CompressionLevel.Default) ) {
|
|
var n = 0;
|
|
while ( n < bytes.Length ) {
|
|
var count = Mathf.Min(4 * 1024, bytes.Length - n);
|
|
compressor.Write(bytes, n, count);
|
|
n += count;
|
|
if ( progress_act != null ) {
|
|
progress_act((float)n / bytes.Length);
|
|
}
|
|
}
|
|
}
|
|
return output.ToArray();
|
|
}
|
|
}
|
|
|
|
static byte[] DecompressBuffer(byte[] compressed_bytes, System.Action<float> progress_act) {
|
|
using ( var input = new MemoryStream(compressed_bytes) ) {
|
|
using ( var decompressor = new ZlibStream(input, CompressionMode.Decompress) ) {
|
|
using ( var output = new MemoryStream() ) {
|
|
int n;
|
|
var buffer = new byte[4 * 1024];
|
|
while ( (n = decompressor.Read(buffer, 0, buffer.Length)) != 0 ) {
|
|
output.Write(buffer, 0, n);
|
|
if ( progress_act != null ) {
|
|
progress_act((float)decompressor.Position / input.Length);
|
|
}
|
|
}
|
|
return output.ToArray();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// Demo
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
#if FT_VERSION_DEMO
|
|
public static bool IsDemoEnded {
|
|
get {
|
|
var guids = AssetDatabase.FindAssets("t:SwfAsset");
|
|
return guids.Length >= 5;
|
|
}
|
|
}
|
|
#else
|
|
public static bool IsDemoEnded {
|
|
get {
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// ProgressBar
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
public class ProgressBar {
|
|
string _title = string.Empty;
|
|
|
|
public void UpdateTitle(string title) {
|
|
_title = title;
|
|
}
|
|
|
|
public void UpdateProgress(string info, float progress) {
|
|
var bar_title = string.IsNullOrEmpty(_title)
|
|
? "Flash Tools Process"
|
|
: string.Format("Flash Tools Process: {0}", _title);
|
|
var bar_info = string.Format("{0}...", info);
|
|
var bar_progress = Mathf.Clamp01(progress);
|
|
EditorUtility.DisplayProgressBar(bar_title, bar_info, bar_progress);
|
|
}
|
|
|
|
public void HideProgress() {
|
|
EditorUtility.ClearProgressBar();
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// FileHash
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
public static string GetFileHashWithVersion(string path) {
|
|
return string.Format(
|
|
"{0}={1}",
|
|
GetFileHash(path), SwfVersion.AsString);
|
|
}
|
|
|
|
static string GetVersionFromFileHashWithVersion(string hash) {
|
|
var index = hash.LastIndexOf('=');
|
|
return index != -1
|
|
? hash.Substring(index + 1)
|
|
: string.Empty;
|
|
}
|
|
|
|
static string GetFileHash(string path) {
|
|
try {
|
|
using ( var sha256 = SHA256.Create() ) {
|
|
var file_bytes = File.ReadAllBytes(path);
|
|
var hash_bytes = sha256.ComputeHash(file_bytes);
|
|
return
|
|
System.Convert.ToBase64String(hash_bytes) +
|
|
file_bytes.LongLength.ToString();
|
|
}
|
|
} catch ( System.Exception ) {
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// Outdated assets
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
public static bool CheckForOutdatedAsset(SwfClip clip) {
|
|
return clip
|
|
&& CheckForOutdatedAsset(clip.clip);
|
|
}
|
|
|
|
public static bool CheckForOutdatedAsset(SwfClipAsset clip_asset) {
|
|
return clip_asset
|
|
&& CheckForOutdatedAsset(AssetDatabase.LoadAssetAtPath<SwfAsset>(
|
|
AssetDatabase.GUIDToAssetPath(clip_asset.AssetGUID)));
|
|
}
|
|
|
|
public static bool CheckForOutdatedAsset(SwfAsset asset) {
|
|
return asset
|
|
&& GetVersionFromFileHashWithVersion(asset.Hash) != SwfVersion.AsString;
|
|
}
|
|
|
|
public static bool CheckForOutdatedAsset(IEnumerable<SwfClip> clips) {
|
|
var iter = clips.GetEnumerator();
|
|
while ( iter.MoveNext() ) {
|
|
if ( CheckForOutdatedAsset(iter.Current) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool CheckForOutdatedAsset(IEnumerable<SwfClipAsset> clip_assets) {
|
|
var iter = clip_assets.GetEnumerator();
|
|
while ( iter.MoveNext() ) {
|
|
if ( CheckForOutdatedAsset(iter.Current) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool CheckForOutdatedAsset(IEnumerable<SwfAsset> assets) {
|
|
var iter = assets.GetEnumerator();
|
|
while ( iter.MoveNext() ) {
|
|
if ( CheckForOutdatedAsset(iter.Current) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// GUI notes
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
public static void DrawMasksGUINotes() {
|
|
EditorGUILayout.Separator();
|
|
EditorGUILayout.HelpBox(
|
|
"Masks and blends of animation may not be displayed correctly in the preview window. " +
|
|
"Instance animation to the scene, to see how it will look like the animation in the game.",
|
|
MessageType.Info);
|
|
}
|
|
|
|
public static void DrawOutdatedGUINotes(string target, IEnumerable<SwfClip> clips) {
|
|
DrawOutdatedGUINotes(target, clips
|
|
.Select(p => p ? p.clip : null));
|
|
}
|
|
|
|
public static void DrawOutdatedGUINotes(string target, IEnumerable<SwfClipAsset> clips) {
|
|
DrawOutdatedGUINotes(target, clips
|
|
.Select(p => {
|
|
return p
|
|
? AssetDatabase.LoadAssetAtPath<SwfAsset>(AssetDatabase.GUIDToAssetPath(p.AssetGUID))
|
|
: null;
|
|
}));
|
|
}
|
|
|
|
public static void DrawOutdatedGUINotes(string target, IEnumerable<SwfAsset> assets) {
|
|
var asset_count = assets.Count(p => p);
|
|
if ( asset_count == 1 ) {
|
|
var asset = assets.FirstOrDefault(p => p);
|
|
if ( asset ) {
|
|
var asset_version = GetVersionFromFileHashWithVersion(asset.Hash);
|
|
if ( asset_version != SwfVersion.AsString ) {
|
|
EditorGUILayout.Separator();
|
|
EditorGUILayout.HelpBox(string.Format(
|
|
"The {0} was created in the {1} version of Flash Animation Toolset, and it's outdated.\n" +
|
|
"Please, reimport the source .swf file. It's may be essential to correctness working.\n" +
|
|
"You can do it in Tools/FlashTools menu.",
|
|
target, asset_version),
|
|
MessageType.Error);
|
|
}
|
|
}
|
|
} else if ( asset_count > 1 ) {
|
|
var any_outdated = assets
|
|
.Any(p => GetVersionFromFileHashWithVersion(p.Hash) != SwfVersion.AsString);
|
|
if ( any_outdated ) {
|
|
EditorGUILayout.Separator();
|
|
EditorGUILayout.HelpBox(string.Format(
|
|
"Some {0} is outdated.\n" +
|
|
"Please, reimport the source .swf files. It's may be essential to correctness working.\n" +
|
|
"You can do it in Tools/FlashTools menu.",
|
|
target),
|
|
MessageType.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// Menu
|
|
//
|
|
// ---------------------------------------------------------------------
|
|
|
|
[MenuItem("Tools/FlashTools/Open settings...")]
|
|
static void Tools_FlashTools_OpenSettings() {
|
|
var settings_holder = SwfEditorUtils.GetSettingsHolder();
|
|
Selection.objects = new Object[]{settings_holder};
|
|
EditorGUIUtility.PingObject(settings_holder);
|
|
}
|
|
|
|
[MenuItem("Tools/FlashTools/Reimport all swf files")]
|
|
static void Tools_FlashTools_ReimportAllSwfFiles() {
|
|
var swf_paths = GetAllSwfFilePaths();
|
|
var title = "Reimport";
|
|
var message = string.Format(
|
|
"Do you really want to reimport all ({0}) swf files?",
|
|
swf_paths.Length);
|
|
if ( EditorUtility.DisplayDialog(title, message, "Ok", "Cancel") ) {
|
|
foreach ( var swf_path in swf_paths ) {
|
|
AssetDatabase.ImportAsset(swf_path);
|
|
}
|
|
}
|
|
}
|
|
|
|
[MenuItem("Tools/FlashTools/Reconvert all swf assets")]
|
|
static void Tools_FlashTools_ReconvertAllSwfAssets() {
|
|
Tools_FlashTools_ReimportAllSwfFiles();
|
|
var swf_assets = GetAllSwfAssets();
|
|
foreach ( var swf_asset in swf_assets ) {
|
|
if ( swf_asset.Atlas ) {
|
|
AssetDatabase.DeleteAsset(
|
|
AssetDatabase.GetAssetPath(swf_asset.Atlas));
|
|
swf_asset.Atlas = null;
|
|
}
|
|
EditorUtility.SetDirty(swf_asset);
|
|
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(swf_asset));
|
|
}
|
|
}
|
|
|
|
[MenuItem("Tools/FlashTools/Pregenerate all materials")]
|
|
static void PregenerateAllMaterials() {
|
|
var blend_modes = System.Enum.GetValues(typeof(SwfBlendModeData.Types));
|
|
foreach ( SwfBlendModeData.Types blend_mode in blend_modes ) {
|
|
SwfMaterialCache.GetSimpleMaterial(blend_mode);
|
|
for ( var i = 0; i < 10; ++i ) {
|
|
SwfMaterialCache.GetMaskedMaterial(blend_mode, i);
|
|
}
|
|
}
|
|
SwfMaterialCache.GetIncrMaskMaterial();
|
|
SwfMaterialCache.GetDecrMaskMaterial();
|
|
}
|
|
|
|
static SwfAsset[] GetAllSwfAssets() {
|
|
return SwfEditorUtils.LoadAllAssetsDBByFilter<SwfAsset>("t:SwfAsset");
|
|
}
|
|
|
|
static string[] GetAllSwfFilePaths() {
|
|
return AssetDatabase.GetAllAssetPaths()
|
|
.Where(p => Path.GetExtension(p).ToLower().Equals(".swf"))
|
|
.ToArray();
|
|
}
|
|
}
|
|
} |