mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -04:00
Merge branch 'AssetStudioMod' into ArknightsStudio
This commit is contained in:
commit
d44ed315e3
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>1.0.1</Version>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<Version>1.0.1</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
|
@ -42,6 +42,7 @@ namespace AssetStudio
|
||||
filteredAssetTypesList.UnionWith(new HashSet<ClassIDType>
|
||||
{
|
||||
ClassIDType.Texture2D,
|
||||
ClassIDType.SpriteAtlas,
|
||||
ClassIDType.MonoBehaviour,
|
||||
ClassIDType.MonoScript
|
||||
});
|
||||
@ -87,7 +88,7 @@ namespace AssetStudio
|
||||
MergeSplitAssets(fullPath, true);
|
||||
fileList.AddRange(Directory.GetFiles(fullPath, "*.*", SearchOption.AllDirectories));
|
||||
}
|
||||
else
|
||||
else if (File.Exists(fullPath))
|
||||
{
|
||||
parentPath = Path.GetDirectoryName(fullPath);
|
||||
fileList.Add(fullPath);
|
||||
@ -138,7 +139,7 @@ namespace AssetStudio
|
||||
|
||||
private void LoadFile(FileReader reader)
|
||||
{
|
||||
switch (reader.FileType)
|
||||
switch (reader?.FileType)
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
LoadAssetsFile(reader);
|
||||
@ -537,6 +538,9 @@ namespace AssetStudio
|
||||
case ClassIDType.PlayerSettings:
|
||||
obj = new PlayerSettings(objectReader);
|
||||
break;
|
||||
case ClassIDType.PreloadData:
|
||||
obj = new PreloadData(objectReader);
|
||||
break;
|
||||
case ClassIDType.RectTransform:
|
||||
obj = new RectTransform(objectReader);
|
||||
break;
|
||||
@ -640,14 +644,17 @@ namespace AssetStudio
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||
}
|
||||
else
|
||||
else if (m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlaOld))
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlaOld);
|
||||
if (m_SpriteAtlaOld.m_IsVariant)
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning($"\"{m_Sprite.m_Name}\": Sprite loading error. SpriteAtlas with PathID: \"{m_Sprite.m_SpriteAtlas.m_PathID}\" was not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ namespace AssetStudio
|
||||
public T inWeight;
|
||||
public T outWeight;
|
||||
|
||||
|
||||
public Keyframe(ObjectReader reader, Func<T> readerFunc)
|
||||
{
|
||||
time = reader.ReadSingle();
|
||||
@ -294,15 +293,20 @@ namespace AssetStudio
|
||||
public string path;
|
||||
public ClassIDType classID;
|
||||
public PPtr<MonoScript> script;
|
||||
|
||||
public int flags;
|
||||
|
||||
public FloatCurve(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
curve = new AnimationCurve<float>(reader, reader.ReadSingle);
|
||||
attribute = reader.ReadAlignedString();
|
||||
path = reader.ReadAlignedString();
|
||||
classID = (ClassIDType)reader.ReadInt32();
|
||||
script = new PPtr<MonoScript>(reader);
|
||||
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 2)) //2022.2 and up
|
||||
{
|
||||
flags = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,7 +315,6 @@ namespace AssetStudio
|
||||
public float time;
|
||||
public PPtr<Object> value;
|
||||
|
||||
|
||||
public PPtrKeyframe(ObjectReader reader)
|
||||
{
|
||||
time = reader.ReadSingle();
|
||||
@ -326,10 +329,11 @@ namespace AssetStudio
|
||||
public string path;
|
||||
public int classID;
|
||||
public PPtr<MonoScript> script;
|
||||
|
||||
public int flags;
|
||||
|
||||
public PPtrCurve(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
int numCurves = reader.ReadInt32();
|
||||
curve = new PPtrKeyframe[numCurves];
|
||||
for (int i = 0; i < numCurves; i++)
|
||||
@ -341,6 +345,10 @@ namespace AssetStudio
|
||||
path = reader.ReadAlignedString();
|
||||
classID = reader.ReadInt32();
|
||||
script = new PPtr<MonoScript>(reader);
|
||||
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 2)) //2022.2 and up
|
||||
{
|
||||
flags = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -940,7 +948,6 @@ namespace AssetStudio
|
||||
public AnimationClipBindingConstant m_ClipBindingConstant;
|
||||
public AnimationEvent[] m_Events;
|
||||
|
||||
|
||||
public AnimationClip(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (version[0] >= 5)//5.0 and up
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
@ -23,22 +20,47 @@ namespace AssetStudio
|
||||
{
|
||||
public PPtr<Object>[] m_PreloadTable;
|
||||
public KeyValuePair<string, AssetInfo>[] m_Container;
|
||||
public string m_AssetBundleName;
|
||||
public string[] m_Dependencies;
|
||||
public bool m_IsStreamedSceneAssetBundle;
|
||||
|
||||
public AssetBundle(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_PreloadTableSize = reader.ReadInt32();
|
||||
m_PreloadTable = new PPtr<Object>[m_PreloadTableSize];
|
||||
for (int i = 0; i < m_PreloadTableSize; i++)
|
||||
for (var i = 0; i < m_PreloadTableSize; i++)
|
||||
{
|
||||
m_PreloadTable[i] = new PPtr<Object>(reader);
|
||||
}
|
||||
|
||||
var m_ContainerSize = reader.ReadInt32();
|
||||
m_Container = new KeyValuePair<string, AssetInfo>[m_ContainerSize];
|
||||
for (int i = 0; i < m_ContainerSize; i++)
|
||||
for (var i = 0; i < m_ContainerSize; i++)
|
||||
{
|
||||
m_Container[i] = new KeyValuePair<string, AssetInfo>(reader.ReadAlignedString(), new AssetInfo(reader));
|
||||
}
|
||||
|
||||
var m_MainAsset = new AssetInfo(reader);
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 2)) //4.2 and up
|
||||
{
|
||||
var m_RuntimeCompatibility = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
m_AssetBundleName = reader.ReadAlignedString();
|
||||
|
||||
var m_DependenciesSize = reader.ReadInt32();
|
||||
m_Dependencies = new string[m_DependenciesSize];
|
||||
|
||||
for (var i = 0; i < m_DependenciesSize; i++)
|
||||
{
|
||||
m_Dependencies[i] = reader.ReadAlignedString();
|
||||
}
|
||||
|
||||
m_IsStreamedSceneAssetBundle = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
35
AssetStudio/Classes/PreloadData.cs
Normal file
35
AssetStudio/Classes/PreloadData.cs
Normal file
@ -0,0 +1,35 @@
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class PreloadData : NamedObject
|
||||
{
|
||||
public PPtr<Object>[] m_Assets;
|
||||
|
||||
public PreloadData(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_PreloadTableSize = reader.ReadInt32();
|
||||
m_Assets = new PPtr<Object>[m_PreloadTableSize];
|
||||
for (var i = 0; i < m_PreloadTableSize; i++)
|
||||
{
|
||||
m_Assets[i] = new PPtr<Object>(reader);
|
||||
}
|
||||
|
||||
/*
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
var m_DependenciesSize = reader.ReadInt32();
|
||||
var m_Dependencies = new string[m_DependenciesSize];
|
||||
|
||||
for (var i = 0; i < m_DependenciesSize; i++)
|
||||
{
|
||||
m_Dependencies[i] = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
|
||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
||||
{
|
||||
var m_ExplicitDataLayout = reader.ReadBoolean();
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ namespace AssetStudio
|
||||
public SecondarySpriteTexture(ObjectReader reader)
|
||||
{
|
||||
texture = new PPtr<Texture2D>(reader);
|
||||
name = reader.ReadStringToNull();
|
||||
name = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
namespace AssetStudio
|
||||
{
|
||||
// Represents set with 16 base colors using ANSI escape codes, which should be supported in most terminals
|
||||
// (well, except for windows editions before windows 10)
|
||||
public static class CLIAnsiColors
|
||||
public static class ColorConsole
|
||||
{
|
||||
public static readonly string
|
||||
Black = "\u001b[30m",
|
||||
@ -27,7 +27,7 @@ namespace AssetStudioCLI
|
||||
|
||||
public static string Color(this string str, string ansiColor)
|
||||
{
|
||||
if (!CLIWinAnsiFix.isAnsiSupported)
|
||||
if (!ColorConsoleHelper.isAnsiCodesSupported)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
@ -35,10 +35,10 @@ namespace AssetStudioCLI
|
||||
return $"{ansiColor}{str}{Reset}";
|
||||
}
|
||||
|
||||
public static void ANSICodesTest()
|
||||
public static void AnsiCodesTest()
|
||||
{
|
||||
Console.WriteLine("ANSI escape codes test");
|
||||
Console.WriteLine($"Supported: {CLIWinAnsiFix.isAnsiSupported}");
|
||||
Console.WriteLine($"Supported: {ColorConsoleHelper.isAnsiCodesSupported}");
|
||||
Console.WriteLine("\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m");
|
||||
Console.WriteLine("\u001b[34m E \u001b[35m F \u001b[36m G \u001b[37m H \u001b[0m");
|
||||
Console.WriteLine("\u001b[30;1m A \u001b[31;1m B \u001b[32;1m C \u001b[33;1m D \u001b[0m");
|
@ -2,11 +2,11 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
namespace AssetStudio
|
||||
{
|
||||
static class CLIWinAnsiFix
|
||||
internal static class ColorConsoleHelper
|
||||
{
|
||||
public static readonly bool isAnsiSupported;
|
||||
public static readonly bool isAnsiCodesSupported;
|
||||
private const int STD_OUTPUT_HANDLE = -11;
|
||||
private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
|
||||
|
||||
@ -19,21 +19,21 @@ namespace AssetStudioCLI
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr GetStdHandle(int nStdHandle);
|
||||
|
||||
static CLIWinAnsiFix()
|
||||
static ColorConsoleHelper()
|
||||
{
|
||||
bool isWin = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
var isWin = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
if (isWin)
|
||||
{
|
||||
isAnsiSupported = TryEnableVTMode();
|
||||
if (!isAnsiSupported)
|
||||
isAnsiCodesSupported = TryEnableVTMode();
|
||||
if (!isAnsiCodesSupported)
|
||||
{
|
||||
//Check for bash terminal emulator. E.g., Git Bash, Cmder
|
||||
isAnsiSupported = Environment.GetEnvironmentVariable("TERM") != null;
|
||||
isAnsiCodesSupported = Environment.GetEnvironmentVariable("TERM") != null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isAnsiSupported = true;
|
||||
isAnsiCodesSupported = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,12 +51,7 @@ namespace AssetStudioCLI
|
||||
|
||||
outConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
|
||||
if (!SetConsoleMode(iStdOut, outConsoleMode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return SetConsoleMode(iStdOut, outConsoleMode);
|
||||
}
|
||||
}
|
||||
}
|
@ -35,10 +35,13 @@ namespace AssetStudio
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string ReadStringToNull(this BinaryReader reader, int maxLength = 32767)
|
||||
public static string ReadStringToNull(this BinaryReader reader, int maxLength = 32767, Encoding encoding = null)
|
||||
{
|
||||
if (encoding?.CodePage == 1200) //Unicode (UTF-16LE)
|
||||
return reader.ReadUnicodeStringToNull(maxLength * 2);
|
||||
|
||||
var bytes = new List<byte>();
|
||||
int count = 0;
|
||||
var count = 0;
|
||||
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
|
||||
{
|
||||
var b = reader.ReadByte();
|
||||
@ -49,7 +52,24 @@ namespace AssetStudio
|
||||
bytes.Add(b);
|
||||
count++;
|
||||
}
|
||||
return Encoding.UTF8.GetString(bytes.ToArray());
|
||||
return encoding?.GetString(bytes.ToArray()) ?? Encoding.UTF8.GetString(bytes.ToArray());
|
||||
}
|
||||
|
||||
private static string ReadUnicodeStringToNull(this BinaryReader reader, int maxLength)
|
||||
{
|
||||
var bytes = new List<byte>();
|
||||
var count = 0;
|
||||
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
|
||||
{
|
||||
var b = reader.ReadBytes(2);
|
||||
if (b.Length < 2 || (b[0] == 0 && b[1] == 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
bytes.AddRange(b);
|
||||
count += 2;
|
||||
}
|
||||
return Encoding.Unicode.GetString(bytes.ToArray());
|
||||
}
|
||||
|
||||
public static Quaternion ReadQuaternion(this BinaryReader reader)
|
||||
|
@ -53,15 +53,24 @@ namespace AssetStudio
|
||||
|
||||
public static FileReader DecompressGZip(FileReader reader)
|
||||
{
|
||||
using (reader)
|
||||
try
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
|
||||
using (reader)
|
||||
{
|
||||
gs.CopyTo(stream);
|
||||
var stream = new MemoryStream();
|
||||
using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
|
||||
{
|
||||
gs.CopyTo(stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
return new FileReader(reader.FullPath, stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
return new FileReader(reader.FullPath, stream);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Warning($"Error while decompressing gzip file {reader.FullPath}\r\n{e}");
|
||||
reader.Dispose();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net472;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<AssemblyTitle>ArknightsStudio by aelurum</AssemblyTitle>
|
||||
<AssemblyName>ArknightsStudioCLI</AssemblyName>
|
||||
<Version>1.0.1</Version>
|
||||
|
@ -29,6 +29,7 @@ namespace AssetStudioCLI
|
||||
LogName = $"{appAssembly.Name}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log";
|
||||
LogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogName);
|
||||
var arch = Environment.Is64BitProcess ? "x64" : "x32";
|
||||
Console.OutputEncoding = System.Text.Encoding.UTF8;
|
||||
|
||||
LogToFile(LoggerEvent.Verbose, $"---{appAssembly.Name} v{appAssembly.Version} [{arch}] | Logger launched---\n" +
|
||||
$"CMD Args: {string.Join(" ", CLIOptions.cliArgs)}");
|
||||
@ -36,15 +37,15 @@ namespace AssetStudioCLI
|
||||
|
||||
private static string ColorLogLevel(LoggerEvent logLevel)
|
||||
{
|
||||
string formattedLevel = $"[{logLevel}]";
|
||||
var formattedLevel = $"[{logLevel}]";
|
||||
switch (logLevel)
|
||||
{
|
||||
case LoggerEvent.Info:
|
||||
return $"{formattedLevel.Color(CLIAnsiColors.BrightCyan)}";
|
||||
return $"{formattedLevel.Color(ColorConsole.BrightCyan)}";
|
||||
case LoggerEvent.Warning:
|
||||
return $"{formattedLevel.Color(CLIAnsiColors.BrightYellow)}";
|
||||
return $"{formattedLevel.Color(ColorConsole.BrightYellow)}";
|
||||
case LoggerEvent.Error:
|
||||
return $"{formattedLevel.Color(CLIAnsiColors.BrightRed)}";
|
||||
return $"{formattedLevel.Color(ColorConsole.BrightRed)}";
|
||||
default:
|
||||
return formattedLevel;
|
||||
}
|
||||
@ -59,7 +60,7 @@ namespace AssetStudioCLI
|
||||
string formattedMessage;
|
||||
if (consoleMode)
|
||||
{
|
||||
string colorLogLevel = ColorLogLevel(logMsgLevel);
|
||||
var colorLogLevel = ColorLogLevel(logMsgLevel);
|
||||
formattedMessage = $"{colorLogLevel} {message}";
|
||||
if (multiLine)
|
||||
{
|
||||
|
@ -56,14 +56,14 @@ namespace Arknights
|
||||
{
|
||||
var faceImage = m_Texture2D.ConvertToImage(true);
|
||||
var faceAlpha = avgSprite.FaceSpriteAlphaTexture.ConvertToImage(true);
|
||||
if (faceImage.Size() != avgSprite.FaceSize)
|
||||
if (new Size(faceImage.Width, faceImage.Height) != avgSprite.FaceSize)
|
||||
{
|
||||
faceImage.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
faceAlpha.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
}
|
||||
tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
tex.Mutate(x => x.DrawImage(faceImage, location: avgSprite.FacePos, opacity: 1f));
|
||||
alphaTex.Mutate(x => x.DrawImage(faceAlpha, location: avgSprite.FacePos, opacity: 1f));
|
||||
tex.Mutate(x => x.DrawImage(faceImage, avgSprite.FacePos, opacity: 1f));
|
||||
alphaTex.Mutate(x => x.DrawImage(faceAlpha, avgSprite.FacePos, opacity: 1f));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -87,11 +87,11 @@ namespace Arknights
|
||||
|
||||
var faceImage = m_Texture2D.ConvertToImage(true);
|
||||
var tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
if (faceImage.Size() != avgSprite.FaceSize)
|
||||
if (new Size(faceImage.Width, faceImage.Height) != avgSprite.FaceSize)
|
||||
{
|
||||
faceImage.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
}
|
||||
tex.Mutate(x => x.DrawImage(faceImage, location: avgSprite.FacePos, opacity: 1f));
|
||||
tex.Mutate(x => x.DrawImage(faceImage, avgSprite.FacePos, opacity: 1f));
|
||||
|
||||
return tex;
|
||||
}
|
||||
@ -201,7 +201,7 @@ namespace Arknights
|
||||
{
|
||||
if (downscaleMultiplier > 0f && downscaleMultiplier != 1f)
|
||||
{
|
||||
var newSize = (Size)(originalImage.Size() / downscaleMultiplier);
|
||||
var newSize = (Size)(new Size(originalImage.Width, originalImage.Height) / downscaleMultiplier);
|
||||
originalImage.Mutate(x => x.Resize(newSize, KnownResamplers.Lanczos3, compand: true));
|
||||
}
|
||||
var rectX = (int)Math.Floor(textureRect.x);
|
||||
|
@ -409,7 +409,7 @@ namespace AssetStudioCLI
|
||||
Directory.CreateDirectory(dir);
|
||||
return true;
|
||||
}
|
||||
Logger.Error($"Export error. File \"{fullPath.Color(CLIAnsiColors.BrightRed)}\" already exist");
|
||||
Logger.Error($"Export error. File \"{fullPath.Color(ColorConsole.BrightRed)}\" already exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ namespace AssetStudioCLI.Options
|
||||
General,
|
||||
Convert,
|
||||
Logger,
|
||||
Live2D,
|
||||
FBX,
|
||||
Filter,
|
||||
Arknights,
|
||||
@ -93,6 +94,9 @@ namespace AssetStudioCLI.Options
|
||||
public static bool convertTexture;
|
||||
public static Option<ImageFormat> o_imageFormat;
|
||||
public static Option<AudioFormat> o_audioFormat;
|
||||
//live2d
|
||||
public static Option<CubismLive2DExtractor.Live2DMotionMode> o_l2dMotionMode;
|
||||
public static Option<bool> f_l2dForceBezier;
|
||||
//fbx
|
||||
public static Option<float> o_fbxScaleFactor;
|
||||
public static Option<int> o_fbxBoneSize;
|
||||
@ -222,7 +226,7 @@ namespace AssetStudioCLI.Options
|
||||
optionDefaultValue: "ASExport",
|
||||
optionName: "-o, --output <path>",
|
||||
optionDescription: "Specify path to the output folder\n" +
|
||||
"If path isn't specifyed, 'ASExport' folder will be created in the program's work folder\n",
|
||||
"If path isn't specified, 'ASExport' folder will be created in the program's work folder\n",
|
||||
optionHelpGroup: HelpGroups.General
|
||||
);
|
||||
o_displayHelp = new GroupedOption<bool>
|
||||
@ -279,6 +283,30 @@ namespace AssetStudioCLI.Options
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Init Cubism Live2D Options
|
||||
o_l2dMotionMode = new GroupedOption<CubismLive2DExtractor.Live2DMotionMode>
|
||||
(
|
||||
optionDefaultValue: CubismLive2DExtractor.Live2DMotionMode.MonoBehaviour,
|
||||
optionName: "--l2d-motion-mode <value>",
|
||||
optionDescription: "Specify Live2D motion export mode\n" +
|
||||
"<Value: monoBehaviour(default) | animationClip>\n" +
|
||||
"MonoBehaviour - Try to export motions from MonoBehaviour Fade motions\n" +
|
||||
"If no Fade motions are found, the AnimationClip method will be used\n" +
|
||||
"AnimationClip - Try to export motions using AnimationClip assets\n" +
|
||||
"Example: \"--l2d-motion-mode animationClip\"\n",
|
||||
optionHelpGroup: HelpGroups.Live2D
|
||||
);
|
||||
f_l2dForceBezier = new GroupedOption<bool>
|
||||
(
|
||||
optionDefaultValue: false,
|
||||
optionName: "--l2d-force-bezier",
|
||||
optionDescription: "(Flag) If specified, Linear motion segments will be calculated as Bezier segments\n" +
|
||||
"(May help if the exported motions look jerky/not smooth enough)",
|
||||
optionHelpGroup: HelpGroups.Live2D,
|
||||
isFlag: true
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Init FBX Options
|
||||
o_fbxScaleFactor = new GroupedOption<float>
|
||||
(
|
||||
@ -340,7 +368,7 @@ namespace AssetStudioCLI.Options
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Arknights Options
|
||||
#region Init Arknights Options
|
||||
akResizedOnly = true;
|
||||
o_akSpriteAlphaMode = new GroupedOption<AkSpriteAlphaMode>
|
||||
(
|
||||
@ -385,7 +413,7 @@ namespace AssetStudioCLI.Options
|
||||
(
|
||||
optionDefaultValue: false,
|
||||
optionName: "--original-avg-names",
|
||||
optionDescription: "(Flag) If specified, names of avg character sprites will not be fixed\n",
|
||||
optionDescription: "(Flag) If specified, names of avg character sprites will not be restored\n",
|
||||
optionHelpGroup: HelpGroups.Arknights,
|
||||
isFlag: true
|
||||
);
|
||||
@ -447,8 +475,8 @@ namespace AssetStudioCLI.Options
|
||||
{
|
||||
cliArgs = args;
|
||||
|
||||
var brightYellow = CLIAnsiColors.BrightYellow;
|
||||
var brightRed = CLIAnsiColors.BrightRed;
|
||||
var brightYellow = ColorConsole.BrightYellow;
|
||||
var brightRed = ColorConsole.BrightRed;
|
||||
|
||||
if (args.Length == 0 || args.Any(x => x.ToLower() == "-h" || x.ToLower() == "--help" || x.ToLower() == "-?"))
|
||||
{
|
||||
@ -489,6 +517,7 @@ namespace AssetStudioCLI.Options
|
||||
}
|
||||
};
|
||||
|
||||
#region Parse "Working Mode" Option
|
||||
var workModeOptionIndex = resplittedArgs.FindIndex(x => x.ToLower() == "-m" || x.ToLower() == "--mode");
|
||||
if (workModeOptionIndex >= 0)
|
||||
{
|
||||
@ -515,6 +544,7 @@ namespace AssetStudioCLI.Options
|
||||
case "info":
|
||||
o_workMode.Value = WorkMode.Info;
|
||||
break;
|
||||
case "l2d":
|
||||
case "live2d":
|
||||
o_workMode.Value = WorkMode.ExportLive2D;
|
||||
o_exportAssetTypes.Value = new List<ClassIDType>()
|
||||
@ -546,6 +576,7 @@ namespace AssetStudioCLI.Options
|
||||
}
|
||||
resplittedArgs.RemoveRange(workModeOptionIndex, 2);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Parse Flags
|
||||
for (int i = 0; i < resplittedArgs.Count; i++)
|
||||
@ -581,6 +612,16 @@ namespace AssetStudioCLI.Options
|
||||
f_akAddAliases.Value = true;
|
||||
resplittedArgs.RemoveAt(i);
|
||||
break;
|
||||
case "--l2d-force-bezier":
|
||||
if (o_workMode.Value != WorkMode.ExportLive2D)
|
||||
{
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{flag}] flag. This flag is not suitable for the current working mode [{o_workMode.Value}].\n");
|
||||
ShowOptionDescription(o_workMode.Description);
|
||||
return;
|
||||
}
|
||||
f_l2dForceBezier.Value = true;
|
||||
resplittedArgs.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@ -782,6 +823,28 @@ namespace AssetStudioCLI.Options
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "--l2d-motion-mode":
|
||||
if (o_workMode.Value != WorkMode.ExportLive2D)
|
||||
{
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. This option is not suitable for the current working mode [{o_workMode.Value}].\n");
|
||||
ShowOptionDescription(o_workMode.Description);
|
||||
return;
|
||||
}
|
||||
switch (value.ToLower())
|
||||
{
|
||||
case "fade":
|
||||
case "monobehaviour":
|
||||
o_l2dMotionMode.Value = CubismLive2DExtractor.Live2DMotionMode.MonoBehaviour;
|
||||
break;
|
||||
case "animationclip":
|
||||
o_l2dMotionMode.Value = CubismLive2DExtractor.Live2DMotionMode.AnimationClip;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported Live2D motion mode: [{value.Color(brightRed)}].\n");
|
||||
ShowOptionDescription(o_l2dMotionMode.Description);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "--fbx-scale-factor":
|
||||
{
|
||||
var isFloat = float.TryParse(value, out float floatValue);
|
||||
@ -949,7 +1012,7 @@ namespace AssetStudioCLI.Options
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Unknown Error.".Color(CLIAnsiColors.Red));
|
||||
Console.WriteLine("Unknown Error.".Color(ColorConsole.Red));
|
||||
Console.WriteLine(ex);
|
||||
return;
|
||||
}
|
||||
@ -986,13 +1049,13 @@ namespace AssetStudioCLI.Options
|
||||
|
||||
private static bool TryFindOptionDescription(string option, Dictionary<string, string> dict, bool isFlag = false)
|
||||
{
|
||||
var optionDesc = dict.Where(x => x.Key.Contains(option));
|
||||
var optionDesc = dict.Where(x => x.Key.Contains(option)).ToArray();
|
||||
if (optionDesc.Any())
|
||||
{
|
||||
var arg = isFlag ? "flag" : "option";
|
||||
var rand = new Random();
|
||||
var rndOption = optionDesc.ElementAt(rand.Next(0, optionDesc.Count()));
|
||||
Console.WriteLine($"Did you mean [{ $"{rndOption.Key}".Color(CLIAnsiColors.BrightYellow) }] {arg}?");
|
||||
var rndOption = optionDesc.ElementAt(rand.Next(0, optionDesc.Length));
|
||||
Console.WriteLine($"Did you mean [{$"{rndOption.Key}".Color(ColorConsole.BrightYellow)}] {arg}?");
|
||||
Console.WriteLine($"Here's a description of it: \n\n{rndOption.Value}");
|
||||
|
||||
return true;
|
||||
@ -1034,7 +1097,7 @@ namespace AssetStudioCLI.Options
|
||||
else
|
||||
{
|
||||
var arch = Environment.Is64BitProcess ? "x64" : "x32";
|
||||
Console.WriteLine($"# {appAssembly.Name} [{arch}]\n# v{appAssembly.Version}\n# Based on AssetStudioMod v0.17.3\n");
|
||||
Console.WriteLine($"# {appAssembly.Name} [{arch}]\n# v{appAssembly.Version}\n# Based on AssetStudioMod v0.17.4\n");
|
||||
Console.WriteLine($"{usage}\n\n{helpMessage}");
|
||||
}
|
||||
}
|
||||
@ -1105,7 +1168,7 @@ namespace AssetStudioCLI.Options
|
||||
sb.AppendLine($"# Log Output: {o_logOutput}");
|
||||
sb.AppendLine($"# Export Asset List: {o_exportAssetList}");
|
||||
sb.AppendLine(ShowCurrentFilter());
|
||||
sb.AppendLine($"# Assebmly Path: \"{o_assemblyPath}\"");
|
||||
sb.AppendLine($"# Assembly Path: \"{o_assemblyPath}\"");
|
||||
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
|
||||
if (o_workMode.Value == WorkMode.Export)
|
||||
{
|
||||
@ -1134,7 +1197,9 @@ namespace AssetStudioCLI.Options
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine($"# Assebmly Path: \"{o_assemblyPath}\"");
|
||||
sb.AppendLine($"# Live2D Motion Export Method: {o_l2dMotionMode}");
|
||||
sb.AppendLine($"# Force Bezier: {f_l2dForceBezier }");
|
||||
sb.AppendLine($"# Assembly Path: \"{o_assemblyPath}\"");
|
||||
}
|
||||
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
|
||||
break;
|
||||
|
@ -10,6 +10,7 @@ ArknightsStudioCLI <input path to asset file/folder> [-m, --mode <value>]
|
||||
[-o, --output <path>] [-h, --help]
|
||||
[--log-level <value>] [--log-output <value>]
|
||||
[--image-format <value>] [--audio-format <value>]
|
||||
[--l2d-motion-mode <value>] [--l2d-force-bezier]
|
||||
[--fbx-scale-factor <value>] [--fbx-bone-size <value>]
|
||||
[--filter-by-name <text>] [--filter-by-container <text>]
|
||||
[--filter-by-pathid <text>] [--filter-by-text <text>]
|
||||
@ -48,7 +49,7 @@ General Options:
|
||||
Example: "-g container"
|
||||
|
||||
-o, --output <path> Specify path to the output folder
|
||||
If path isn't specifyed, 'ASExport' folder will be created in the program's work folder
|
||||
If path isn't specified, 'ASExport' folder will be created in the program's work folder
|
||||
|
||||
-h, --help Display help and exit
|
||||
|
||||
@ -72,6 +73,17 @@ Convert Options:
|
||||
None - Do not convert audios and export them in their own format
|
||||
Example: "--audio-format wav"
|
||||
|
||||
Live2D Options:
|
||||
--l2d-motion-mode <value> Specify Live2D motion export mode
|
||||
<Value: monoBehaviour(default) | animationClip>
|
||||
MonoBehaviour - Try to export motions from MonoBehaviour Fade motions
|
||||
If no Fade motions are found, the AnimationClip method will be used
|
||||
AnimationClip - Try to export motions using AnimationClip assets
|
||||
Example: "--l2d-motion-mode animationClip"
|
||||
|
||||
--l2d-force-bezier (Flag) If specified, Linear motion segments will be calculated as Bezier segments
|
||||
(May help if the exported motions look jerky/not smooth enough)
|
||||
|
||||
FBX Options:
|
||||
--fbx-scale-factor <value> Specify the FBX Scale Factor
|
||||
<Value: float number from 0 to 100 (default=1)
|
||||
@ -124,7 +136,7 @@ Arknights Options:
|
||||
>0 - Make the shadow lighter
|
||||
Example: "--shadow-gamma 0"
|
||||
|
||||
--original-avg-names (Flag) If specified, names of avg character sprites will not be fixed
|
||||
--original-avg-names (Flag) If specified, names of avg character sprites will not be restored
|
||||
|
||||
--add-aliases (Flag) If specified, aliases will be added to avg character sprite names (if exist)
|
||||
|
||||
|
@ -7,7 +7,7 @@ using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using static AssetStudioCLI.Exporter;
|
||||
using static CubismLive2DExtractor.Live2DExtractor;
|
||||
using Ansi = AssetStudioCLI.CLIAnsiColors;
|
||||
using Ansi = AssetStudio.ColorConsole;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
@ -62,6 +62,7 @@ namespace AssetStudioCLI
|
||||
var i = 0;
|
||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||
{
|
||||
var preloadTable = Array.Empty<PPtr<AssetStudio.Object>>();
|
||||
foreach (var asset in assetsFile.Objects)
|
||||
{
|
||||
var assetItem = new AssetItem(asset);
|
||||
@ -70,22 +71,31 @@ namespace AssetStudioCLI
|
||||
var isExportable = false;
|
||||
switch (asset)
|
||||
{
|
||||
case PreloadData m_PreloadData:
|
||||
preloadTable = m_PreloadData.m_Assets;
|
||||
break;
|
||||
case AssetBundle m_AssetBundle:
|
||||
var isStreamedSceneAssetBundle = m_AssetBundle.m_IsStreamedSceneAssetBundle;
|
||||
if (!isStreamedSceneAssetBundle)
|
||||
{
|
||||
preloadTable = m_AssetBundle.m_PreloadTable;
|
||||
}
|
||||
assetItem.Text = string.IsNullOrEmpty(m_AssetBundle.m_AssetBundleName) ? m_AssetBundle.m_Name : m_AssetBundle.m_AssetBundleName;
|
||||
|
||||
foreach (var m_Container in m_AssetBundle.m_Container)
|
||||
{
|
||||
var preloadIndex = m_Container.Value.preloadIndex;
|
||||
var preloadSize = m_Container.Value.preloadSize;
|
||||
var preloadSize = isStreamedSceneAssetBundle ? preloadTable.Length : m_Container.Value.preloadSize;
|
||||
var preloadEnd = preloadIndex + preloadSize;
|
||||
for (int k = preloadIndex; k < preloadEnd; k++)
|
||||
for (var k = preloadIndex; k < preloadEnd; k++)
|
||||
{
|
||||
var pptr = m_AssetBundle.m_PreloadTable[k];
|
||||
var pptr = preloadTable[k];
|
||||
if (pptr.TryGet(out var obj))
|
||||
{
|
||||
containers[obj] = m_Container.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
assetItem.Text = m_AssetBundle.m_Name;
|
||||
break;
|
||||
case ResourceManager m_ResourceManager:
|
||||
foreach (var m_Container in m_ResourceManager.m_Container)
|
||||
@ -110,7 +120,7 @@ namespace AssetStudioCLI
|
||||
if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath))
|
||||
assetItem.FullSize = asset.byteSize + m_VideoClip.m_ExternalResources.m_Size;
|
||||
assetItem.Text = m_VideoClip.m_Name;
|
||||
break;
|
||||
break;
|
||||
case Shader m_Shader:
|
||||
assetItem.Text = m_Shader.m_ParsedForm?.m_Name ?? m_Shader.m_Name;
|
||||
break;
|
||||
@ -153,11 +163,11 @@ namespace AssetStudioCLI
|
||||
}
|
||||
foreach (var asset in loadedAssetsList)
|
||||
{
|
||||
if (containers.ContainsKey(asset.Asset))
|
||||
if (containers.TryGetValue(asset.Asset, out var container))
|
||||
{
|
||||
asset.Container = containers[asset.Asset];
|
||||
asset.Container = container;
|
||||
|
||||
if (asset.Type == ClassIDType.MonoBehaviour && asset.Container.Contains("/arts/charportraits/portraits"))
|
||||
if (asset.Type == ClassIDType.MonoBehaviour && container.Contains("/arts/charportraits/portraits"))
|
||||
{
|
||||
var portraitsList = Arknights.AkSpriteHelper.GeneratePortraits(asset);
|
||||
foreach (var portrait in portraitsList)
|
||||
@ -618,6 +628,8 @@ namespace AssetStudioCLI
|
||||
{
|
||||
var baseDestPath = Path.Combine(CLIOptions.o_outputFolder.Value, "Live2DOutput");
|
||||
var useFullContainerPath = false;
|
||||
var motionMode = CLIOptions.o_l2dMotionMode.Value;
|
||||
var forceBezier = CLIOptions.f_l2dForceBezier.Value;
|
||||
|
||||
Progress.Reset();
|
||||
Logger.Info($"Searching for Live2D files...");
|
||||
@ -631,6 +643,7 @@ namespace AssetStudioCLI
|
||||
}
|
||||
return false;
|
||||
}).Select(x => x.Asset).ToArray();
|
||||
|
||||
if (cubismMocs.Length == 0)
|
||||
{
|
||||
Logger.Default.Log(LoggerEvent.Info, "Live2D Cubism models were not found.", ignoreLevel: true);
|
||||
@ -638,7 +651,18 @@ namespace AssetStudioCLI
|
||||
}
|
||||
if (cubismMocs.Length > 1)
|
||||
{
|
||||
var basePathSet = cubismMocs.Select(x => containers[x].Substring(0, containers[x].LastIndexOf("/"))).ToHashSet();
|
||||
var basePathSet = cubismMocs.Select(x =>
|
||||
{
|
||||
var pathLen = containers.TryGetValue(x, out var itemContainer) ? itemContainer.LastIndexOf("/") : 0;
|
||||
pathLen = pathLen < 0 ? containers[x].Length : pathLen;
|
||||
return itemContainer?.Substring(0, pathLen);
|
||||
}).ToHashSet();
|
||||
|
||||
if (basePathSet.All(x => x == null))
|
||||
{
|
||||
Logger.Error($"Live2D Cubism export error: Cannot find any model related files.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (basePathSet.Count != cubismMocs.Length)
|
||||
{
|
||||
@ -646,9 +670,16 @@ namespace AssetStudioCLI
|
||||
Logger.Debug($"useFullContainerPath: {useFullContainerPath}");
|
||||
}
|
||||
}
|
||||
var basePathList = useFullContainerPath ?
|
||||
cubismMocs.Select(x => containers[x]).ToList() :
|
||||
cubismMocs.Select(x => containers[x].Substring(0, containers[x].LastIndexOf("/"))).ToList();
|
||||
|
||||
var basePathList = cubismMocs.Select(x =>
|
||||
{
|
||||
containers.TryGetValue(x, out var container);
|
||||
container = useFullContainerPath
|
||||
? container
|
||||
: container?.Substring(0, container.LastIndexOf("/"));
|
||||
return container;
|
||||
}).Where(x => x != null).ToList();
|
||||
|
||||
var lookup = containers.ToLookup(
|
||||
x => basePathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
||||
x => x.Key
|
||||
@ -656,31 +687,31 @@ namespace AssetStudioCLI
|
||||
|
||||
var totalModelCount = lookup.LongCount(x => x.Key != null);
|
||||
Logger.Info($"Found {totalModelCount} model(s).");
|
||||
var name = "";
|
||||
var modelCounter = 0;
|
||||
foreach (var assets in lookup)
|
||||
{
|
||||
var container = assets.Key;
|
||||
if (container == null)
|
||||
var srcContainer = assets.Key;
|
||||
if (srcContainer == null)
|
||||
continue;
|
||||
name = container;
|
||||
var container = srcContainer;
|
||||
|
||||
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{container.Color(Ansi.BrightCyan)}\"");
|
||||
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{srcContainer.Color(Ansi.BrightCyan)}\"");
|
||||
try
|
||||
{
|
||||
var modelName = useFullContainerPath ? Path.GetFileNameWithoutExtension(container) : container.Substring(container.LastIndexOf('/') + 1);
|
||||
container = Path.HasExtension(container) ? container.Replace(Path.GetExtension(container), "") : container;
|
||||
var destPath = Path.Combine(baseDestPath, container) + Path.DirectorySeparatorChar;
|
||||
|
||||
ExtractLive2D(assets, destPath, modelName, assemblyLoader);
|
||||
ExtractLive2D(assets, destPath, modelName, assemblyLoader, motionMode, forceBezier);
|
||||
modelCounter++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"Live2D model export error: \"{name}\"", ex);
|
||||
Logger.Error($"Live2D model export error: \"{srcContainer}\"", ex);
|
||||
}
|
||||
Progress.Report(modelCounter, (int)totalModelCount);
|
||||
}
|
||||
|
||||
var status = modelCounter > 0 ?
|
||||
$"Finished exporting [{modelCounter}/{totalModelCount}] Live2D model(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightCyan)}\"" :
|
||||
"Nothing exported.";
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>1.0.1</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
|
||||
|
@ -10,14 +10,16 @@ namespace AssetStudioGUI
|
||||
public AboutForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
var productName = Application.ProductName;
|
||||
var arch = Environment.Is64BitProcess ? "x64" : "x32";
|
||||
var appAssembly = typeof(Program).Assembly.GetName();
|
||||
var productName = appAssembly.Name;
|
||||
var productVer = appAssembly.Version.ToString();
|
||||
Text += " " + productName;
|
||||
productTitleLabel.Text = productName;
|
||||
productVersionLabel.Text = $"v{Application.ProductVersion} [{arch}]";
|
||||
productVersionLabel.Text = $"v{productVer} [{arch}]";
|
||||
productNamelabel.Text = productName;
|
||||
modVersionLabel.Text = Application.ProductVersion;
|
||||
basedOnLabel.Text = "AssetStudioMod v0.17.3";
|
||||
modVersionLabel.Text = productVer;
|
||||
basedOnLabel.Text = "AssetStudioMod v0.17.4";
|
||||
|
||||
licenseRichTextBox.Text = GetLicenseText();
|
||||
}
|
||||
|
@ -54,14 +54,14 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Core-6.0" Version="1.1.6-preview.2.24bd88f" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell-6.0" Version="1.1.6-preview.2.24bd88f" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Core-6.0" Version="1.1.6" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell-6.0" Version="1.1.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
|
||||
<PackageReference Include="OpenTK.Graphics" Version="4.8.0" />
|
||||
<PackageReference Include="OpenTK.Windowing.Desktop" Version="4.8.0" />
|
||||
<PackageReference Include="OpenTK.Graphics" Version="4.8.2" />
|
||||
<PackageReference Include="OpenTK.Windowing.Desktop" Version="4.8.2" />
|
||||
<Reference Include="OpenTK.WinForms">
|
||||
<HintPath>Libraries\OpenTK.WinForms.dll</HintPath>
|
||||
</Reference>
|
||||
|
61
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
61
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
@ -46,6 +46,7 @@
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.akUseExternalAlphaToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.akSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.buildTreeStructureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem14 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.specifyUnityVersion = new System.Windows.Forms.ToolStripTextBox();
|
||||
this.showExpOpt = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@ -82,6 +83,8 @@
|
||||
this.allToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.debugMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem15 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.showConsoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.writeLogToFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.exportClassStructuresMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
@ -241,6 +244,7 @@
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem,
|
||||
this.akUseExternalAlphaToolStripMenuItem,
|
||||
this.akSeparator2,
|
||||
this.buildTreeStructureToolStripMenuItem,
|
||||
this.toolStripMenuItem14,
|
||||
this.showExpOpt});
|
||||
this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem";
|
||||
@ -251,7 +255,7 @@
|
||||
//
|
||||
this.displayAll.CheckOnClick = true;
|
||||
this.displayAll.Name = "displayAll";
|
||||
this.displayAll.Size = new System.Drawing.Size(252, 22);
|
||||
this.displayAll.Size = new System.Drawing.Size(276, 22);
|
||||
this.displayAll.Text = "Display all assets";
|
||||
this.displayAll.ToolTipText = "Check this option will display all types assets. Not extractable assets can expor" +
|
||||
"t the RAW file.";
|
||||
@ -263,7 +267,7 @@
|
||||
this.enablePreview.CheckOnClick = true;
|
||||
this.enablePreview.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.enablePreview.Name = "enablePreview";
|
||||
this.enablePreview.Size = new System.Drawing.Size(252, 22);
|
||||
this.enablePreview.Size = new System.Drawing.Size(276, 22);
|
||||
this.enablePreview.Text = "Enable preview";
|
||||
this.enablePreview.ToolTipText = "Toggle the loading and preview of readable assets, such as images, sounds, text, " +
|
||||
"etc.\r\nDisable preview if you have performance or compatibility issues.";
|
||||
@ -275,7 +279,7 @@
|
||||
this.displayInfo.CheckOnClick = true;
|
||||
this.displayInfo.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.displayInfo.Name = "displayInfo";
|
||||
this.displayInfo.Size = new System.Drawing.Size(252, 22);
|
||||
this.displayInfo.Size = new System.Drawing.Size(276, 22);
|
||||
this.displayInfo.Text = "Display asset information";
|
||||
this.displayInfo.ToolTipText = "Toggle the overlay that shows information about each asset, eg. image size, forma" +
|
||||
"t, audio bitrate, etc.";
|
||||
@ -284,7 +288,7 @@
|
||||
// akSeparator1
|
||||
//
|
||||
this.akSeparator1.Name = "akSeparator1";
|
||||
this.akSeparator1.Size = new System.Drawing.Size(249, 6);
|
||||
this.akSeparator1.Size = new System.Drawing.Size(273, 6);
|
||||
//
|
||||
// akTitleMenuItem
|
||||
//
|
||||
@ -292,7 +296,7 @@
|
||||
this.akTitleMenuItem.Enabled = false;
|
||||
this.akTitleMenuItem.Name = "akTitleMenuItem";
|
||||
this.akTitleMenuItem.ShowShortcutKeys = false;
|
||||
this.akTitleMenuItem.Size = new System.Drawing.Size(252, 22);
|
||||
this.akTitleMenuItem.Size = new System.Drawing.Size(276, 22);
|
||||
this.akTitleMenuItem.Text = "Arknights";
|
||||
//
|
||||
// akFixFaceSpriteNamesToolStripMenuItem
|
||||
@ -301,8 +305,8 @@
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.CheckOnClick = true;
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.Name = "akFixFaceSpriteNamesToolStripMenuItem";
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.Size = new System.Drawing.Size(252, 22);
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.Text = "Fix names of avg character sprites";
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.Size = new System.Drawing.Size(276, 22);
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.Text = "Restore names of avg character sprites";
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.ToolTipText = "Rename face sprites with numeric names to correct ones";
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.CheckedChanged += new System.EventHandler(this.akFixFaceSpriteNamesToolStripMenuItem_Check);
|
||||
//
|
||||
@ -312,7 +316,7 @@
|
||||
this.akUseExternalAlphaToolStripMenuItem.CheckOnClick = true;
|
||||
this.akUseExternalAlphaToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.akUseExternalAlphaToolStripMenuItem.Name = "akUseExternalAlphaToolStripMenuItem";
|
||||
this.akUseExternalAlphaToolStripMenuItem.Size = new System.Drawing.Size(265, 22);
|
||||
this.akUseExternalAlphaToolStripMenuItem.Size = new System.Drawing.Size(276, 22);
|
||||
this.akUseExternalAlphaToolStripMenuItem.Text = "Use external alpha texture for sprites";
|
||||
this.akUseExternalAlphaToolStripMenuItem.ToolTipText = "Trying to find an external alpha texture for preview/export sprite assets (Skins," +
|
||||
" Char arts, Avg char arts, etc.)";
|
||||
@ -321,14 +325,25 @@
|
||||
// akSeparator2
|
||||
//
|
||||
this.akSeparator2.Name = "akSeparator2";
|
||||
this.akSeparator2.Size = new System.Drawing.Size(249, 6);
|
||||
this.akSeparator2.Size = new System.Drawing.Size(273, 6);
|
||||
//
|
||||
// buildTreeStructureToolStripMenuItem
|
||||
//
|
||||
this.buildTreeStructureToolStripMenuItem.Checked = true;
|
||||
this.buildTreeStructureToolStripMenuItem.CheckOnClick = true;
|
||||
this.buildTreeStructureToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.buildTreeStructureToolStripMenuItem.Name = "buildTreeStructureToolStripMenuItem";
|
||||
this.buildTreeStructureToolStripMenuItem.Size = new System.Drawing.Size(276, 22);
|
||||
this.buildTreeStructureToolStripMenuItem.Text = "Build tree structure";
|
||||
this.buildTreeStructureToolStripMenuItem.ToolTipText = "You can disable tree structure building if you don\'t use the Scene Hierarchy tab";
|
||||
this.buildTreeStructureToolStripMenuItem.CheckedChanged += new System.EventHandler(this.buildTreeStructureToolStripMenuItem_CheckedChanged);
|
||||
//
|
||||
// toolStripMenuItem14
|
||||
//
|
||||
this.toolStripMenuItem14.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.specifyUnityVersion});
|
||||
this.toolStripMenuItem14.Name = "toolStripMenuItem14";
|
||||
this.toolStripMenuItem14.Size = new System.Drawing.Size(252, 22);
|
||||
this.toolStripMenuItem14.Size = new System.Drawing.Size(276, 22);
|
||||
this.toolStripMenuItem14.Text = "Specify Unity version";
|
||||
//
|
||||
// specifyUnityVersion
|
||||
@ -342,7 +357,7 @@
|
||||
// showExpOpt
|
||||
//
|
||||
this.showExpOpt.Name = "showExpOpt";
|
||||
this.showExpOpt.Size = new System.Drawing.Size(252, 22);
|
||||
this.showExpOpt.Size = new System.Drawing.Size(276, 22);
|
||||
this.showExpOpt.Text = "Export options";
|
||||
this.showExpOpt.Click += new System.EventHandler(this.showExpOpt_Click);
|
||||
//
|
||||
@ -588,6 +603,8 @@
|
||||
//
|
||||
this.debugMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.toolStripMenuItem15,
|
||||
this.showConsoleToolStripMenuItem,
|
||||
this.writeLogToFileToolStripMenuItem,
|
||||
this.exportClassStructuresMenuItem});
|
||||
this.debugMenuItem.Name = "debugMenuItem";
|
||||
this.debugMenuItem.Size = new System.Drawing.Size(54, 20);
|
||||
@ -601,6 +618,24 @@
|
||||
this.toolStripMenuItem15.Text = "Show all error messages";
|
||||
this.toolStripMenuItem15.Click += new System.EventHandler(this.toolStripMenuItem15_Click);
|
||||
//
|
||||
// showConsoleToolStripMenuItem
|
||||
//
|
||||
this.showConsoleToolStripMenuItem.Checked = true;
|
||||
this.showConsoleToolStripMenuItem.CheckOnClick = true;
|
||||
this.showConsoleToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.showConsoleToolStripMenuItem.Name = "showConsoleToolStripMenuItem";
|
||||
this.showConsoleToolStripMenuItem.Size = new System.Drawing.Size(200, 22);
|
||||
this.showConsoleToolStripMenuItem.Text = "Show console logger";
|
||||
this.showConsoleToolStripMenuItem.Click += new System.EventHandler(this.showConsoleToolStripMenuItem_Click);
|
||||
//
|
||||
// writeLogToFileToolStripMenuItem
|
||||
//
|
||||
this.writeLogToFileToolStripMenuItem.CheckOnClick = true;
|
||||
this.writeLogToFileToolStripMenuItem.Name = "writeLogToFileToolStripMenuItem";
|
||||
this.writeLogToFileToolStripMenuItem.Size = new System.Drawing.Size(200, 22);
|
||||
this.writeLogToFileToolStripMenuItem.Text = "Write log to file";
|
||||
this.writeLogToFileToolStripMenuItem.CheckedChanged += new System.EventHandler(this.writeLogToFileToolStripMenuItem_CheckedChanged);
|
||||
//
|
||||
// exportClassStructuresMenuItem
|
||||
//
|
||||
this.exportClassStructuresMenuItem.Name = "exportClassStructuresMenuItem";
|
||||
@ -1308,6 +1343,7 @@
|
||||
this.Name = "AssetStudioGUIForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "AssetStudioModGUI";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.AssetStudioGUIForm_FormClosing);
|
||||
this.DragDrop += new System.Windows.Forms.DragEventHandler(this.AssetStudioGUIForm_DragDrop);
|
||||
this.DragEnter += new System.Windows.Forms.DragEventHandler(this.AssetStudioGUIForm_DragEnter);
|
||||
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.AssetStudioForm_KeyDown);
|
||||
@ -1462,6 +1498,9 @@
|
||||
private System.Windows.Forms.ToolStripSeparator akSeparator1;
|
||||
private System.Windows.Forms.ToolStripMenuItem akTitleMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator akSeparator2;
|
||||
private System.Windows.Forms.ToolStripMenuItem showConsoleToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem writeLogToFileToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem buildTreeStructureToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,23 +116,34 @@ namespace AssetStudioGUI
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts);
|
||||
|
||||
private string guiTitle = string.Empty;
|
||||
|
||||
public AssetStudioGUIForm()
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
|
||||
ConsoleWindow.RunConsole(Properties.Settings.Default.showConsole);
|
||||
InitializeComponent();
|
||||
Text = $"{Application.ProductName} v{Application.ProductVersion}";
|
||||
|
||||
var appAssembly = typeof(Program).Assembly.GetName();
|
||||
guiTitle = $"{appAssembly.Name} v{appAssembly.Version}";
|
||||
Text = guiTitle;
|
||||
|
||||
delayTimer = new System.Timers.Timer(800);
|
||||
delayTimer.Elapsed += new ElapsedEventHandler(delayTimer_Elapsed);
|
||||
delayTimer.Elapsed += delayTimer_Elapsed;
|
||||
displayAll.Checked = Properties.Settings.Default.displayAll;
|
||||
displayInfo.Checked = Properties.Settings.Default.displayInfo;
|
||||
enablePreview.Checked = Properties.Settings.Default.enablePreview;
|
||||
akFixFaceSpriteNamesToolStripMenuItem.Checked = Properties.Settings.Default.fixFaceSpriteNames;
|
||||
akUseExternalAlphaToolStripMenuItem.Checked = Properties.Settings.Default.useExternalAlpha;
|
||||
showConsoleToolStripMenuItem.Checked = Properties.Settings.Default.showConsole;
|
||||
buildTreeStructureToolStripMenuItem.Checked = Properties.Settings.Default.buildTreeStructure;
|
||||
FMODinit();
|
||||
listSearchFilterMode.SelectedIndex = 0;
|
||||
|
||||
logger = new GUILogger(StatusStripUpdate);
|
||||
Logger.Default = logger;
|
||||
writeLogToFileToolStripMenuItem.Checked = Properties.Settings.Default.useFileLogger;
|
||||
|
||||
Progress.Default = new Progress<int>(SetProgressBarValue);
|
||||
Studio.StatusStripUpdate = StatusStripUpdate;
|
||||
}
|
||||
@ -141,21 +152,32 @@ namespace AssetStudioGUI
|
||||
{
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
{
|
||||
e.Effect = DragDropEffects.Move;
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
}
|
||||
}
|
||||
|
||||
private async void AssetStudioGUIForm_DragDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
var paths = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
if (paths.Length > 0)
|
||||
if (paths.Length == 0)
|
||||
return;
|
||||
|
||||
ResetForm();
|
||||
for (var i = 0; i < paths.Length; i++)
|
||||
{
|
||||
ResetForm();
|
||||
assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text;
|
||||
await Task.Run(() => assetsManager.LoadFilesAndFolders(out openDirectoryBackup, paths));
|
||||
saveDirectoryBackup = openDirectoryBackup;
|
||||
BuildAssetStructures();
|
||||
if (paths[i].ToLower().EndsWith(".lnk"))
|
||||
{
|
||||
var targetPath = LnkReader.GetLnkTarget(paths[i]);
|
||||
if (!string.IsNullOrEmpty(targetPath))
|
||||
{
|
||||
paths[i] = targetPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text;
|
||||
await Task.Run(() => assetsManager.LoadFilesAndFolders(out openDirectoryBackup, paths));
|
||||
saveDirectoryBackup = openDirectoryBackup;
|
||||
BuildAssetStructures();
|
||||
}
|
||||
|
||||
private async void loadFile_Click(object sender, EventArgs e)
|
||||
@ -224,17 +246,11 @@ namespace AssetStudioGUI
|
||||
return;
|
||||
}
|
||||
|
||||
(var productName, var treeNodeCollection) = await Task.Run(() => BuildAssetData());
|
||||
var (productName, treeNodeCollection) = await Task.Run(() => BuildAssetData());
|
||||
var typeMap = await Task.Run(() => BuildClassStructure());
|
||||
productName = string.IsNullOrEmpty(productName) ? "no productName" : productName;
|
||||
|
||||
if (!string.IsNullOrEmpty(productName))
|
||||
{
|
||||
Text = $"{Application.ProductName} v{Application.ProductVersion} - {productName} - {assetsManager.assetsFileList[0].unityVersion} - {assetsManager.assetsFileList[0].m_TargetPlatform}";
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = $"{Application.ProductName} v{Application.ProductVersion} - no productName - {assetsManager.assetsFileList[0].unityVersion} - {assetsManager.assetsFileList[0].m_TargetPlatform}";
|
||||
}
|
||||
Text = $"{guiTitle} - {productName} - {assetsManager.assetsFileList[0].unityVersion} - {assetsManager.assetsFileList[0].m_TargetPlatform}";
|
||||
|
||||
assetListView.VirtualListSize = visibleAssets.Count;
|
||||
|
||||
@ -1423,7 +1439,7 @@ namespace AssetStudioGUI
|
||||
|
||||
private void ResetForm()
|
||||
{
|
||||
Text = $"{Application.ProductName} v{Application.ProductVersion}";
|
||||
Text = guiTitle;
|
||||
assetsManager.Clear();
|
||||
assemblyLoader.Clear();
|
||||
exportableAssets.Clear();
|
||||
@ -2127,6 +2143,38 @@ namespace AssetStudioGUI
|
||||
}
|
||||
}
|
||||
|
||||
private void showConsoleToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var showConsole = showConsoleToolStripMenuItem.Checked;
|
||||
if (showConsole)
|
||||
ConsoleWindow.ShowConsoleWindow();
|
||||
else
|
||||
ConsoleWindow.HideConsoleWindow();
|
||||
|
||||
Properties.Settings.Default.showConsole = showConsole;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void writeLogToFileToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
var useFileLogger = writeLogToFileToolStripMenuItem.Checked;
|
||||
logger.UseFileLogger = useFileLogger;
|
||||
|
||||
Properties.Settings.Default.useFileLogger = useFileLogger;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void AssetStudioGUIForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
Logger.Verbose("Closing AssetStudio");
|
||||
}
|
||||
|
||||
private void buildTreeStructureToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.buildTreeStructure = buildTreeStructureToolStripMenuItem.Checked;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
#region FMOD
|
||||
private void FMODinit()
|
||||
{
|
||||
|
@ -57,14 +57,14 @@ namespace Arknights
|
||||
{
|
||||
var faceImage = m_Texture2D.ConvertToImage(true);
|
||||
var faceAlpha = avgSprite.FaceSpriteAlphaTexture.ConvertToImage(true);
|
||||
if (faceImage.Size() != avgSprite.FaceSize)
|
||||
if (new Size(faceImage.Width, faceImage.Height) != avgSprite.FaceSize)
|
||||
{
|
||||
faceImage.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
faceAlpha.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
}
|
||||
tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
tex.Mutate(x => x.DrawImage(faceImage, location: avgSprite.FacePos, opacity: 1f));
|
||||
alphaTex.Mutate(x => x.DrawImage(faceAlpha, location: avgSprite.FacePos, opacity: 1f));
|
||||
tex.Mutate(x => x.DrawImage(faceImage, avgSprite.FacePos, opacity: 1f));
|
||||
alphaTex.Mutate(x => x.DrawImage(faceAlpha, avgSprite.FacePos, opacity: 1f));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -91,11 +91,11 @@ namespace Arknights
|
||||
|
||||
var faceImage = m_Texture2D.ConvertToImage(true);
|
||||
var tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
if (faceImage.Size() != avgSprite.FaceSize)
|
||||
if (new Size(faceImage.Width, faceImage.Height) != avgSprite.FaceSize)
|
||||
{
|
||||
faceImage.Mutate(x => x.Resize(new ResizeOptions {Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch}));
|
||||
}
|
||||
tex.Mutate(x => x.DrawImage(faceImage, location: avgSprite.FacePos, opacity: 1f));
|
||||
tex.Mutate(x => x.DrawImage(faceImage, avgSprite.FacePos, opacity: 1f));
|
||||
|
||||
return tex;
|
||||
}
|
||||
@ -264,7 +264,7 @@ namespace Arknights
|
||||
{
|
||||
if (downscaleMultiplier > 0f && downscaleMultiplier != 1f)
|
||||
{
|
||||
var newSize = (Size)(originalImage.Size() / downscaleMultiplier);
|
||||
var newSize = (Size)(new Size(originalImage.Width, originalImage.Height) / downscaleMultiplier);
|
||||
originalImage.Mutate(x => x.Resize(newSize, KnownResamplers.Lanczos3, compand: true));
|
||||
}
|
||||
var rectX = (int)Math.Floor(textureRect.x);
|
||||
|
67
AssetStudioGUI/Components/ConsoleWindow.cs
Normal file
67
AssetStudioGUI/Components/ConsoleWindow.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using AssetStudio;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
internal static class ConsoleWindow
|
||||
{
|
||||
private enum CtrlSignalType
|
||||
{
|
||||
CTRL_C_EVENT,
|
||||
CTRL_BREAK_EVENT,
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool AllocConsole();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern IntPtr GetConsoleWindow();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
|
||||
|
||||
private delegate bool EventHandler(CtrlSignalType ctrlSignal);
|
||||
private static EventHandler eventHandler;
|
||||
private static IntPtr ConsoleWindowHandle;
|
||||
private static readonly int SW_HIDE = 0;
|
||||
private static readonly int SW_SHOW = 5;
|
||||
|
||||
private static bool CloseEventHandler(CtrlSignalType ctrlSignal)
|
||||
{
|
||||
switch (ctrlSignal)
|
||||
{
|
||||
case CtrlSignalType.CTRL_C_EVENT:
|
||||
case CtrlSignalType.CTRL_BREAK_EVENT:
|
||||
return true;
|
||||
default:
|
||||
Logger.Verbose("Closing AssetStudio");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RunConsole(bool showConsole)
|
||||
{
|
||||
AllocConsole();
|
||||
ConsoleWindowHandle = GetConsoleWindow();
|
||||
eventHandler += CloseEventHandler;
|
||||
SetConsoleCtrlHandler(eventHandler, true);
|
||||
|
||||
if (!showConsole)
|
||||
HideConsoleWindow();
|
||||
}
|
||||
|
||||
public static void ShowConsoleWindow()
|
||||
{
|
||||
ShowWindow(ConsoleWindowHandle, SW_SHOW);
|
||||
}
|
||||
|
||||
public static void HideConsoleWindow()
|
||||
{
|
||||
ShowWindow(ConsoleWindowHandle, SW_HIDE);
|
||||
}
|
||||
}
|
||||
}
|
164
AssetStudioGUI/Components/LnkReader.cs
Normal file
164
AssetStudioGUI/Components/LnkReader.cs
Normal file
@ -0,0 +1,164 @@
|
||||
// Shortcut (.lnk) file reader
|
||||
// by aelurum
|
||||
// Based on https://github.com/libyal/liblnk/blob/main/documentation/Windows%20Shortcut%20File%20(LNK)%20format.asciidoc
|
||||
|
||||
using AssetStudio;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
public static class LnkReader
|
||||
{
|
||||
[Flags]
|
||||
private enum LnkDataFlags
|
||||
{
|
||||
//The LNK file contains a link target identifier
|
||||
HasTargetIDList = 0x00000001,
|
||||
//The LNK file contains location information
|
||||
HasLinkInfo = 0x00000002,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum LnkLocFlags
|
||||
{
|
||||
//The linked file is on a volume
|
||||
//If set the volume information and the local path contain data
|
||||
VolumeIDAndLocalBasePath = 0x0001,
|
||||
//The linked file is on a network share
|
||||
//If set the network share information and common path contain data
|
||||
CommonNetworkRelativeLinkAndPathSuffix = 0x0002
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum PathTypeFlags
|
||||
{
|
||||
IsUnicodeLocalPath = 0x01,
|
||||
IsUnicodeNetShareName = 0x02,
|
||||
IsUnicodeCommonPath = 0x04
|
||||
}
|
||||
|
||||
public static string GetLnkTarget(string filePath)
|
||||
{
|
||||
var targetPath = string.Empty;
|
||||
var pathType = (PathTypeFlags)0;
|
||||
Encoding sysEncoding;
|
||||
try
|
||||
{
|
||||
sysEncoding = GetSysEncoding();
|
||||
Logger.Debug($"System default text encoding: {sysEncoding.CodePage}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error("Text encoding error", ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var reader = new FileReader(filePath))
|
||||
{
|
||||
reader.Endian = EndianType.LittleEndian;
|
||||
|
||||
var headerSize = reader.ReadUInt32(); //76 bytes
|
||||
reader.Position = 20; //skip LNK class identifier (GUID)
|
||||
var dataFlags = (LnkDataFlags)reader.ReadUInt32();
|
||||
if ((dataFlags & LnkDataFlags.HasLinkInfo) == 0)
|
||||
{
|
||||
Logger.Warning("Unsupported type of .lnk file. Link info was not found.");
|
||||
return null;
|
||||
}
|
||||
reader.Position = headerSize;
|
||||
|
||||
//Skip the shell item ID list
|
||||
if ((dataFlags & LnkDataFlags.HasTargetIDList) != 0)
|
||||
{
|
||||
var itemIDListSize = reader.ReadUInt16();
|
||||
reader.Position += itemIDListSize;
|
||||
}
|
||||
|
||||
//The offsets is relative to the start of the location information block
|
||||
var locInfoPos = reader.Position;
|
||||
var locInfoFullSize = reader.ReadUInt32();
|
||||
if (locInfoFullSize == 0)
|
||||
{
|
||||
Logger.Warning("Unsupported type of .lnk file. Link info was not found.");
|
||||
return null;
|
||||
}
|
||||
var locInfoHeaderSize = reader.ReadUInt32();
|
||||
var locFlags = (LnkLocFlags)reader.ReadUInt32();
|
||||
//Offset to the volume information block
|
||||
var offsetVolumeInfo = reader.ReadUInt32();
|
||||
//Offset to the ANSI local path
|
||||
var offsetLocalPath = reader.ReadUInt32();
|
||||
//Offset to the network share information block
|
||||
var offsetNetInfo = reader.ReadUInt32();
|
||||
//Offset to the ANSI common path. 0 if not available
|
||||
var offsetCommonPath = reader.ReadUInt32();
|
||||
if (locInfoHeaderSize > 28)
|
||||
{
|
||||
//Offset to the Unicode local path
|
||||
offsetLocalPath = reader.ReadUInt32();
|
||||
pathType |= PathTypeFlags.IsUnicodeLocalPath;
|
||||
}
|
||||
if (locInfoHeaderSize > 32)
|
||||
{
|
||||
//Offset to the Unicode common path
|
||||
offsetCommonPath = reader.ReadUInt32();
|
||||
pathType |= PathTypeFlags.IsUnicodeCommonPath;
|
||||
}
|
||||
|
||||
//Read local path, if exist
|
||||
if (offsetLocalPath > 0)
|
||||
{
|
||||
reader.Position = locInfoPos + offsetLocalPath;
|
||||
targetPath = (pathType & PathTypeFlags.IsUnicodeLocalPath) != 0
|
||||
? reader.ReadStringToNull(encoding: Encoding.Unicode)
|
||||
: reader.ReadStringToNull(encoding: sysEncoding);
|
||||
}
|
||||
|
||||
//Read network path, if exist
|
||||
if (locFlags == LnkLocFlags.CommonNetworkRelativeLinkAndPathSuffix)
|
||||
{
|
||||
reader.Position = locInfoPos + offsetNetInfo;
|
||||
var netInfoSize = reader.ReadUInt32();
|
||||
var netInfoFlags = reader.ReadUInt32();
|
||||
//Offset to the ANSI network share name. The offset is relative to the start of the network share information block
|
||||
var offsetNetShareName = reader.ReadUInt32();
|
||||
if (offsetNetShareName > 20)
|
||||
{
|
||||
reader.Position = locInfoPos + offsetNetInfo + 20;
|
||||
//Offset to the Unicode network share name
|
||||
offsetNetShareName = reader.ReadUInt32();
|
||||
pathType |= PathTypeFlags.IsUnicodeNetShareName;
|
||||
}
|
||||
if (offsetNetShareName > 0)
|
||||
{
|
||||
reader.Position = locInfoPos + offsetNetInfo + offsetNetShareName;
|
||||
targetPath = (pathType & PathTypeFlags.IsUnicodeNetShareName) != 0
|
||||
? reader.ReadStringToNull(encoding: Encoding.Unicode)
|
||||
: reader.ReadStringToNull(encoding: sysEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
//Read common path, if exist
|
||||
if (offsetCommonPath > 0)
|
||||
{
|
||||
reader.Position = locInfoPos + offsetCommonPath;
|
||||
var commonPath = (pathType & PathTypeFlags.IsUnicodeCommonPath) != 0
|
||||
? reader.ReadStringToNull(encoding: Encoding.Unicode)
|
||||
: reader.ReadStringToNull(encoding: sysEncoding);
|
||||
targetPath = Path.Combine(targetPath, commonPath);
|
||||
}
|
||||
}
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
private static Encoding GetSysEncoding()
|
||||
{
|
||||
#if !NETFRAMEWORK
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
#endif
|
||||
return Encoding.GetEncoding(0);
|
||||
}
|
||||
}
|
||||
}
|
178
AssetStudioGUI/ExportOptions.Designer.cs
generated
178
AssetStudioGUI/ExportOptions.Designer.cs
generated
@ -45,6 +45,12 @@
|
||||
this.topng = new System.Windows.Forms.RadioButton();
|
||||
this.tobmp = new System.Windows.Forms.RadioButton();
|
||||
this.converttexture = new System.Windows.Forms.CheckBox();
|
||||
this.l2dGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.l2dMotionExportMethodPanel = new System.Windows.Forms.Panel();
|
||||
this.l2dMonoBehaviourRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.l2dAnimationClipRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.l2dMotionExportMethodLabel = new System.Windows.Forms.Label();
|
||||
this.l2dForceBezierCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.exportAllUvsAsDiffuseMaps = new System.Windows.Forms.CheckBox();
|
||||
this.exportBlendShape = new System.Windows.Forms.CheckBox();
|
||||
@ -63,7 +69,6 @@
|
||||
this.castToBone = new System.Windows.Forms.CheckBox();
|
||||
this.exportAllNodes = new System.Windows.Forms.CheckBox();
|
||||
this.eulerFilter = new System.Windows.Forms.CheckBox();
|
||||
this.exportUvsTooltip = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.akResamplerLabel = new System.Windows.Forms.Label();
|
||||
this.akResamplerComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.akSpritesAlphaGroupBox = new System.Windows.Forms.GroupBox();
|
||||
@ -75,8 +80,11 @@
|
||||
this.akAlphaMaskGammaTrackBar = new System.Windows.Forms.TrackBar();
|
||||
this.akSpritesExportGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.akAddAliasesCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.optionTooltip = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.l2dGroupBox.SuspendLayout();
|
||||
this.l2dMotionExportMethodPanel.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.boneSize)).BeginInit();
|
||||
@ -120,8 +128,8 @@
|
||||
this.groupBox1.Controls.Add(this.converttexture);
|
||||
this.groupBox1.Location = new System.Drawing.Point(12, 13);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(301, 362);
|
||||
this.groupBox1.TabIndex = 9;
|
||||
this.groupBox1.Size = new System.Drawing.Size(301, 272);
|
||||
this.groupBox1.TabIndex = 1;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Export";
|
||||
//
|
||||
@ -133,7 +141,7 @@
|
||||
this.exportSpriteWithAlphaMask.Location = new System.Drawing.Point(6, 150);
|
||||
this.exportSpriteWithAlphaMask.Name = "exportSpriteWithAlphaMask";
|
||||
this.exportSpriteWithAlphaMask.Size = new System.Drawing.Size(205, 17);
|
||||
this.exportSpriteWithAlphaMask.TabIndex = 11;
|
||||
this.exportSpriteWithAlphaMask.TabIndex = 6;
|
||||
this.exportSpriteWithAlphaMask.Text = "Export sprites with alpha mask applied";
|
||||
this.exportSpriteWithAlphaMask.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -145,7 +153,7 @@
|
||||
this.openAfterExport.Location = new System.Drawing.Point(6, 196);
|
||||
this.openAfterExport.Name = "openAfterExport";
|
||||
this.openAfterExport.Size = new System.Drawing.Size(137, 17);
|
||||
this.openAfterExport.TabIndex = 10;
|
||||
this.openAfterExport.TabIndex = 8;
|
||||
this.openAfterExport.Text = "Open folder after export";
|
||||
this.openAfterExport.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -157,9 +165,9 @@
|
||||
this.restoreExtensionName.Location = new System.Drawing.Point(6, 63);
|
||||
this.restoreExtensionName.Name = "restoreExtensionName";
|
||||
this.restoreExtensionName.Size = new System.Drawing.Size(275, 17);
|
||||
this.restoreExtensionName.TabIndex = 9;
|
||||
this.restoreExtensionName.TabIndex = 3;
|
||||
this.restoreExtensionName.Text = "Try to restore/Use original TextAsset extension name";
|
||||
this.exportUvsTooltip.SetToolTip(this.restoreExtensionName, "If not checked, AssetStudio will export all TextAssets with the \".txt\" extension");
|
||||
this.optionTooltip.SetToolTip(this.restoreExtensionName, "If not checked, AssetStudio will export all TextAssets with the \".txt\" extension");
|
||||
this.restoreExtensionName.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// assetGroupOptions
|
||||
@ -175,7 +183,7 @@
|
||||
this.assetGroupOptions.Location = new System.Drawing.Point(6, 35);
|
||||
this.assetGroupOptions.Name = "assetGroupOptions";
|
||||
this.assetGroupOptions.Size = new System.Drawing.Size(165, 21);
|
||||
this.assetGroupOptions.TabIndex = 8;
|
||||
this.assetGroupOptions.TabIndex = 2;
|
||||
//
|
||||
// label6
|
||||
//
|
||||
@ -183,7 +191,7 @@
|
||||
this.label6.Location = new System.Drawing.Point(6, 18);
|
||||
this.label6.Name = "label6";
|
||||
this.label6.Size = new System.Drawing.Size(127, 13);
|
||||
this.label6.TabIndex = 7;
|
||||
this.label6.TabIndex = 1;
|
||||
this.label6.Text = "Group exported assets by";
|
||||
//
|
||||
// convertAudio
|
||||
@ -194,7 +202,7 @@
|
||||
this.convertAudio.Location = new System.Drawing.Point(6, 173);
|
||||
this.convertAudio.Name = "convertAudio";
|
||||
this.convertAudio.Size = new System.Drawing.Size(179, 17);
|
||||
this.convertAudio.TabIndex = 6;
|
||||
this.convertAudio.TabIndex = 7;
|
||||
this.convertAudio.Text = "Convert AudioClip to WAV(PCM)";
|
||||
this.convertAudio.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -216,8 +224,7 @@
|
||||
this.towebp.Location = new System.Drawing.Point(201, 7);
|
||||
this.towebp.Name = "towebp";
|
||||
this.towebp.Size = new System.Drawing.Size(54, 17);
|
||||
this.towebp.TabIndex = 5;
|
||||
this.towebp.TabStop = true;
|
||||
this.towebp.TabIndex = 4;
|
||||
this.towebp.Text = "Webp";
|
||||
this.towebp.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -227,7 +234,7 @@
|
||||
this.totga.Location = new System.Drawing.Point(150, 7);
|
||||
this.totga.Name = "totga";
|
||||
this.totga.Size = new System.Drawing.Size(44, 17);
|
||||
this.totga.TabIndex = 2;
|
||||
this.totga.TabIndex = 3;
|
||||
this.totga.Text = "Tga";
|
||||
this.totga.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -237,7 +244,7 @@
|
||||
this.tojpg.Location = new System.Drawing.Point(97, 7);
|
||||
this.tojpg.Name = "tojpg";
|
||||
this.tojpg.Size = new System.Drawing.Size(48, 17);
|
||||
this.tojpg.TabIndex = 4;
|
||||
this.tojpg.TabIndex = 2;
|
||||
this.tojpg.Text = "Jpeg";
|
||||
this.tojpg.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -248,7 +255,7 @@
|
||||
this.topng.Location = new System.Drawing.Point(50, 7);
|
||||
this.topng.Name = "topng";
|
||||
this.topng.Size = new System.Drawing.Size(44, 17);
|
||||
this.topng.TabIndex = 3;
|
||||
this.topng.TabIndex = 1;
|
||||
this.topng.TabStop = true;
|
||||
this.topng.Text = "Png";
|
||||
this.topng.UseVisualStyleBackColor = true;
|
||||
@ -259,7 +266,7 @@
|
||||
this.tobmp.Location = new System.Drawing.Point(3, 7);
|
||||
this.tobmp.Name = "tobmp";
|
||||
this.tobmp.Size = new System.Drawing.Size(46, 17);
|
||||
this.tobmp.TabIndex = 2;
|
||||
this.tobmp.TabIndex = 0;
|
||||
this.tobmp.Text = "Bmp";
|
||||
this.tobmp.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -271,10 +278,76 @@
|
||||
this.converttexture.Location = new System.Drawing.Point(6, 87);
|
||||
this.converttexture.Name = "converttexture";
|
||||
this.converttexture.Size = new System.Drawing.Size(116, 17);
|
||||
this.converttexture.TabIndex = 1;
|
||||
this.converttexture.TabIndex = 4;
|
||||
this.converttexture.Text = "Convert Texture2D";
|
||||
this.converttexture.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// l2dGroupBox
|
||||
//
|
||||
this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodPanel);
|
||||
this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodLabel);
|
||||
this.l2dGroupBox.Controls.Add(this.l2dForceBezierCheckBox);
|
||||
this.l2dGroupBox.Location = new System.Drawing.Point(12, 275);
|
||||
this.l2dGroupBox.Name = "l2dGroupBox";
|
||||
this.l2dGroupBox.Size = new System.Drawing.Size(301, 100);
|
||||
this.l2dGroupBox.TabIndex = 2;
|
||||
this.l2dGroupBox.TabStop = false;
|
||||
this.l2dGroupBox.Text = "Cubism Live2D";
|
||||
//
|
||||
// l2dMotionExportMethodPanel
|
||||
//
|
||||
this.l2dMotionExportMethodPanel.Controls.Add(this.l2dMonoBehaviourRadioButton);
|
||||
this.l2dMotionExportMethodPanel.Controls.Add(this.l2dAnimationClipRadioButton);
|
||||
this.l2dMotionExportMethodPanel.Location = new System.Drawing.Point(18, 40);
|
||||
this.l2dMotionExportMethodPanel.Name = "l2dMotionExportMethodPanel";
|
||||
this.l2dMotionExportMethodPanel.Size = new System.Drawing.Size(263, 27);
|
||||
this.l2dMotionExportMethodPanel.TabIndex = 2;
|
||||
//
|
||||
// l2dMonoBehaviourRadioButton
|
||||
//
|
||||
this.l2dMonoBehaviourRadioButton.AccessibleName = "MonoBehaviour";
|
||||
this.l2dMonoBehaviourRadioButton.AutoSize = true;
|
||||
this.l2dMonoBehaviourRadioButton.Checked = true;
|
||||
this.l2dMonoBehaviourRadioButton.Location = new System.Drawing.Point(3, 5);
|
||||
this.l2dMonoBehaviourRadioButton.Name = "l2dMonoBehaviourRadioButton";
|
||||
this.l2dMonoBehaviourRadioButton.Size = new System.Drawing.Size(167, 17);
|
||||
this.l2dMonoBehaviourRadioButton.TabIndex = 0;
|
||||
this.l2dMonoBehaviourRadioButton.TabStop = true;
|
||||
this.l2dMonoBehaviourRadioButton.Text = "MonoBehaviour (Fade motion)";
|
||||
this.optionTooltip.SetToolTip(this.l2dMonoBehaviourRadioButton, "If no Fade motions are found, the AnimationClip method will be used");
|
||||
this.l2dMonoBehaviourRadioButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// l2dAnimationClipRadioButton
|
||||
//
|
||||
this.l2dAnimationClipRadioButton.AccessibleName = "AnimationClip";
|
||||
this.l2dAnimationClipRadioButton.AutoSize = true;
|
||||
this.l2dAnimationClipRadioButton.Location = new System.Drawing.Point(172, 5);
|
||||
this.l2dAnimationClipRadioButton.Name = "l2dAnimationClipRadioButton";
|
||||
this.l2dAnimationClipRadioButton.Size = new System.Drawing.Size(88, 17);
|
||||
this.l2dAnimationClipRadioButton.TabIndex = 1;
|
||||
this.l2dAnimationClipRadioButton.Text = "AnimationClip";
|
||||
this.l2dAnimationClipRadioButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// l2dMotionExportMethodLabel
|
||||
//
|
||||
this.l2dMotionExportMethodLabel.AutoSize = true;
|
||||
this.l2dMotionExportMethodLabel.Location = new System.Drawing.Point(6, 21);
|
||||
this.l2dMotionExportMethodLabel.Name = "l2dMotionExportMethodLabel";
|
||||
this.l2dMotionExportMethodLabel.Size = new System.Drawing.Size(109, 13);
|
||||
this.l2dMotionExportMethodLabel.TabIndex = 1;
|
||||
this.l2dMotionExportMethodLabel.Text = "Motion export method";
|
||||
//
|
||||
// l2dForceBezierCheckBox
|
||||
//
|
||||
this.l2dForceBezierCheckBox.AutoSize = true;
|
||||
this.l2dForceBezierCheckBox.Location = new System.Drawing.Point(6, 77);
|
||||
this.l2dForceBezierCheckBox.Name = "l2dForceBezierCheckBox";
|
||||
this.l2dForceBezierCheckBox.Size = new System.Drawing.Size(278, 17);
|
||||
this.l2dForceBezierCheckBox.TabIndex = 3;
|
||||
this.l2dForceBezierCheckBox.Text = "Calculate Linear motion segments as Bezier segments";
|
||||
this.optionTooltip.SetToolTip(this.l2dForceBezierCheckBox, "May help if the exported motions look jerky/not smooth enough");
|
||||
this.l2dForceBezierCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.AutoSize = true;
|
||||
@ -298,7 +371,7 @@
|
||||
this.groupBox2.Location = new System.Drawing.Point(313, 13);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(224, 362);
|
||||
this.groupBox2.TabIndex = 11;
|
||||
this.groupBox2.TabIndex = 3;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Fbx";
|
||||
//
|
||||
@ -309,9 +382,9 @@
|
||||
this.exportAllUvsAsDiffuseMaps.Location = new System.Drawing.Point(6, 185);
|
||||
this.exportAllUvsAsDiffuseMaps.Name = "exportAllUvsAsDiffuseMaps";
|
||||
this.exportAllUvsAsDiffuseMaps.Size = new System.Drawing.Size(168, 17);
|
||||
this.exportAllUvsAsDiffuseMaps.TabIndex = 23;
|
||||
this.exportAllUvsAsDiffuseMaps.TabIndex = 9;
|
||||
this.exportAllUvsAsDiffuseMaps.Text = "Export all UVs as diffuse maps";
|
||||
this.exportUvsTooltip.SetToolTip(this.exportAllUvsAsDiffuseMaps, "Unchecked: UV1 exported as normal map. Check this if your export is missing a UV " +
|
||||
this.optionTooltip.SetToolTip(this.exportAllUvsAsDiffuseMaps, "Unchecked: UV1 exported as normal map. Check this if your export is missing a UV " +
|
||||
"map.");
|
||||
this.exportAllUvsAsDiffuseMaps.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -323,7 +396,7 @@
|
||||
this.exportBlendShape.Location = new System.Drawing.Point(6, 138);
|
||||
this.exportBlendShape.Name = "exportBlendShape";
|
||||
this.exportBlendShape.Size = new System.Drawing.Size(114, 17);
|
||||
this.exportBlendShape.TabIndex = 22;
|
||||
this.exportBlendShape.TabIndex = 7;
|
||||
this.exportBlendShape.Text = "Export blendshape";
|
||||
this.exportBlendShape.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -335,7 +408,7 @@
|
||||
this.exportAnimations.Location = new System.Drawing.Point(6, 114);
|
||||
this.exportAnimations.Name = "exportAnimations";
|
||||
this.exportAnimations.Size = new System.Drawing.Size(109, 17);
|
||||
this.exportAnimations.TabIndex = 21;
|
||||
this.exportAnimations.TabIndex = 6;
|
||||
this.exportAnimations.Text = "Export animations";
|
||||
this.exportAnimations.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -350,7 +423,7 @@
|
||||
this.scaleFactor.Location = new System.Drawing.Point(83, 243);
|
||||
this.scaleFactor.Name = "scaleFactor";
|
||||
this.scaleFactor.Size = new System.Drawing.Size(60, 20);
|
||||
this.scaleFactor.TabIndex = 20;
|
||||
this.scaleFactor.TabIndex = 13;
|
||||
this.scaleFactor.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
this.scaleFactor.Value = new decimal(new int[] {
|
||||
1,
|
||||
@ -364,7 +437,7 @@
|
||||
this.label5.Location = new System.Drawing.Point(6, 245);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(64, 13);
|
||||
this.label5.TabIndex = 19;
|
||||
this.label5.TabIndex = 12;
|
||||
this.label5.Text = "ScaleFactor";
|
||||
//
|
||||
// fbxFormat
|
||||
@ -377,7 +450,7 @@
|
||||
this.fbxFormat.Location = new System.Drawing.Point(77, 275);
|
||||
this.fbxFormat.Name = "fbxFormat";
|
||||
this.fbxFormat.Size = new System.Drawing.Size(61, 21);
|
||||
this.fbxFormat.TabIndex = 18;
|
||||
this.fbxFormat.TabIndex = 15;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
@ -385,7 +458,7 @@
|
||||
this.label4.Location = new System.Drawing.Point(6, 280);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(59, 13);
|
||||
this.label4.TabIndex = 17;
|
||||
this.label4.TabIndex = 14;
|
||||
this.label4.Text = "FBXFormat";
|
||||
//
|
||||
// fbxVersion
|
||||
@ -402,7 +475,7 @@
|
||||
this.fbxVersion.Location = new System.Drawing.Point(77, 308);
|
||||
this.fbxVersion.Name = "fbxVersion";
|
||||
this.fbxVersion.Size = new System.Drawing.Size(47, 21);
|
||||
this.fbxVersion.TabIndex = 16;
|
||||
this.fbxVersion.TabIndex = 17;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
@ -410,7 +483,7 @@
|
||||
this.label3.Location = new System.Drawing.Point(6, 311);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(62, 13);
|
||||
this.label3.TabIndex = 15;
|
||||
this.label3.TabIndex = 16;
|
||||
this.label3.Text = "FBXVersion";
|
||||
//
|
||||
// boneSize
|
||||
@ -442,7 +515,7 @@
|
||||
this.exportSkins.Location = new System.Drawing.Point(6, 90);
|
||||
this.exportSkins.Name = "exportSkins";
|
||||
this.exportSkins.Size = new System.Drawing.Size(83, 17);
|
||||
this.exportSkins.TabIndex = 8;
|
||||
this.exportSkins.TabIndex = 5;
|
||||
this.exportSkins.Text = "Export skins";
|
||||
this.exportSkins.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -452,7 +525,7 @@
|
||||
this.label1.Location = new System.Drawing.Point(26, 42);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(72, 13);
|
||||
this.label1.TabIndex = 7;
|
||||
this.label1.TabIndex = 2;
|
||||
this.label1.Text = "FilterPrecision";
|
||||
//
|
||||
// filterPrecision
|
||||
@ -466,7 +539,7 @@
|
||||
this.filterPrecision.Location = new System.Drawing.Point(127, 40);
|
||||
this.filterPrecision.Name = "filterPrecision";
|
||||
this.filterPrecision.Size = new System.Drawing.Size(51, 20);
|
||||
this.filterPrecision.TabIndex = 6;
|
||||
this.filterPrecision.TabIndex = 3;
|
||||
this.filterPrecision.Value = new decimal(new int[] {
|
||||
25,
|
||||
0,
|
||||
@ -479,7 +552,7 @@
|
||||
this.castToBone.Location = new System.Drawing.Point(6, 161);
|
||||
this.castToBone.Name = "castToBone";
|
||||
this.castToBone.Size = new System.Drawing.Size(131, 17);
|
||||
this.castToBone.TabIndex = 5;
|
||||
this.castToBone.TabIndex = 8;
|
||||
this.castToBone.Text = "All nodes cast to bone";
|
||||
this.castToBone.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -503,7 +576,7 @@
|
||||
this.eulerFilter.Location = new System.Drawing.Point(6, 22);
|
||||
this.eulerFilter.Name = "eulerFilter";
|
||||
this.eulerFilter.Size = new System.Drawing.Size(72, 17);
|
||||
this.eulerFilter.TabIndex = 3;
|
||||
this.eulerFilter.TabIndex = 1;
|
||||
this.eulerFilter.Text = "EulerFilter";
|
||||
this.eulerFilter.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -513,9 +586,9 @@
|
||||
this.akResamplerLabel.Location = new System.Drawing.Point(6, 21);
|
||||
this.akResamplerLabel.Name = "akResamplerLabel";
|
||||
this.akResamplerLabel.Size = new System.Drawing.Size(120, 13);
|
||||
this.akResamplerLabel.TabIndex = 5;
|
||||
this.akResamplerLabel.TabIndex = 1;
|
||||
this.akResamplerLabel.Text = "Alpha texture resampler:";
|
||||
this.exportUvsTooltip.SetToolTip(this.akResamplerLabel, "Only affects exported images");
|
||||
this.optionTooltip.SetToolTip(this.akResamplerLabel, "Only affects exported images");
|
||||
//
|
||||
// akResamplerComboBox
|
||||
//
|
||||
@ -531,8 +604,8 @@
|
||||
this.akResamplerComboBox.Location = new System.Drawing.Point(132, 18);
|
||||
this.akResamplerComboBox.Name = "akResamplerComboBox";
|
||||
this.akResamplerComboBox.Size = new System.Drawing.Size(162, 21);
|
||||
this.akResamplerComboBox.TabIndex = 4;
|
||||
this.exportUvsTooltip.SetToolTip(this.akResamplerComboBox, "Only affects exported images");
|
||||
this.akResamplerComboBox.TabIndex = 2;
|
||||
this.optionTooltip.SetToolTip(this.akResamplerComboBox, "Only affects exported images");
|
||||
//
|
||||
// akSpritesAlphaGroupBox
|
||||
//
|
||||
@ -547,7 +620,7 @@
|
||||
this.akSpritesAlphaGroupBox.Location = new System.Drawing.Point(537, 13);
|
||||
this.akSpritesAlphaGroupBox.Name = "akSpritesAlphaGroupBox";
|
||||
this.akSpritesAlphaGroupBox.Size = new System.Drawing.Size(300, 178);
|
||||
this.akSpritesAlphaGroupBox.TabIndex = 12;
|
||||
this.akSpritesAlphaGroupBox.TabIndex = 4;
|
||||
this.akSpritesAlphaGroupBox.TabStop = false;
|
||||
this.akSpritesAlphaGroupBox.Text = "Sprites: Alpha Texture [Arknights]";
|
||||
//
|
||||
@ -558,7 +631,7 @@
|
||||
this.akGammaNoteLabel.Location = new System.Drawing.Point(6, 138);
|
||||
this.akGammaNoteLabel.Name = "akGammaNoteLabel";
|
||||
this.akGammaNoteLabel.Size = new System.Drawing.Size(230, 13);
|
||||
this.akGammaNoteLabel.TabIndex = 7;
|
||||
this.akGammaNoteLabel.TabIndex = 8;
|
||||
this.akGammaNoteLabel.Text = "* Gamma settings also affect the preview image";
|
||||
//
|
||||
// akResamplerDescLabel
|
||||
@ -568,7 +641,7 @@
|
||||
this.akResamplerDescLabel.Location = new System.Drawing.Point(6, 43);
|
||||
this.akResamplerDescLabel.Name = "akResamplerDescLabel";
|
||||
this.akResamplerDescLabel.Size = new System.Drawing.Size(251, 13);
|
||||
this.akResamplerDescLabel.TabIndex = 6;
|
||||
this.akResamplerDescLabel.TabIndex = 3;
|
||||
this.akResamplerDescLabel.Text = "Alpha texture upscale method for 2048x2048 sprites";
|
||||
//
|
||||
// akResizedOnlyCheckBox
|
||||
@ -579,7 +652,7 @@
|
||||
this.akResizedOnlyCheckBox.Location = new System.Drawing.Point(172, 85);
|
||||
this.akResizedOnlyCheckBox.Name = "akResizedOnlyCheckBox";
|
||||
this.akResizedOnlyCheckBox.Size = new System.Drawing.Size(122, 17);
|
||||
this.akResizedOnlyCheckBox.TabIndex = 3;
|
||||
this.akResizedOnlyCheckBox.TabIndex = 6;
|
||||
this.akResizedOnlyCheckBox.Text = "Apply to resized only";
|
||||
this.akResizedOnlyCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -589,7 +662,7 @@
|
||||
this.akGammaValueLabel.Location = new System.Drawing.Point(111, 86);
|
||||
this.akGammaValueLabel.Name = "akGammaValueLabel";
|
||||
this.akGammaValueLabel.Size = new System.Drawing.Size(41, 13);
|
||||
this.akGammaValueLabel.TabIndex = 2;
|
||||
this.akGammaValueLabel.TabIndex = 5;
|
||||
this.akGammaValueLabel.Text = "Default";
|
||||
//
|
||||
// akGammaLabel
|
||||
@ -598,7 +671,7 @@
|
||||
this.akGammaLabel.Location = new System.Drawing.Point(6, 86);
|
||||
this.akGammaLabel.Name = "akGammaLabel";
|
||||
this.akGammaLabel.Size = new System.Drawing.Size(86, 13);
|
||||
this.akGammaLabel.TabIndex = 1;
|
||||
this.akGammaLabel.TabIndex = 4;
|
||||
this.akGammaLabel.Text = "Shadow gamma:";
|
||||
//
|
||||
// akAlphaMaskGammaTrackBar
|
||||
@ -609,7 +682,7 @@
|
||||
this.akAlphaMaskGammaTrackBar.Minimum = -5;
|
||||
this.akAlphaMaskGammaTrackBar.Name = "akAlphaMaskGammaTrackBar";
|
||||
this.akAlphaMaskGammaTrackBar.Size = new System.Drawing.Size(288, 45);
|
||||
this.akAlphaMaskGammaTrackBar.TabIndex = 0;
|
||||
this.akAlphaMaskGammaTrackBar.TabIndex = 7;
|
||||
this.akAlphaMaskGammaTrackBar.Scroll += new System.EventHandler(this.akAlphaMaskGammaTrackBar_Scroll);
|
||||
//
|
||||
// akSpritesExportGroupBox
|
||||
@ -618,7 +691,7 @@
|
||||
this.akSpritesExportGroupBox.Location = new System.Drawing.Point(537, 197);
|
||||
this.akSpritesExportGroupBox.Name = "akSpritesExportGroupBox";
|
||||
this.akSpritesExportGroupBox.Size = new System.Drawing.Size(300, 178);
|
||||
this.akSpritesExportGroupBox.TabIndex = 13;
|
||||
this.akSpritesExportGroupBox.TabIndex = 5;
|
||||
this.akSpritesExportGroupBox.TabStop = false;
|
||||
this.akSpritesExportGroupBox.Text = "Sprites: Export [Arknights]";
|
||||
//
|
||||
@ -628,7 +701,7 @@
|
||||
this.akAddAliasesCheckBox.Location = new System.Drawing.Point(6, 28);
|
||||
this.akAddAliasesCheckBox.Name = "akAddAliasesCheckBox";
|
||||
this.akAddAliasesCheckBox.Size = new System.Drawing.Size(261, 17);
|
||||
this.akAddAliasesCheckBox.TabIndex = 0;
|
||||
this.akAddAliasesCheckBox.TabIndex = 1;
|
||||
this.akAddAliasesCheckBox.Text = "Add aliases to avg character sprite names (if exist)";
|
||||
this.akAddAliasesCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@ -639,6 +712,7 @@
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.Cancel;
|
||||
this.ClientSize = new System.Drawing.Size(849, 416);
|
||||
this.Controls.Add(this.l2dGroupBox);
|
||||
this.Controls.Add(this.akSpritesExportGroupBox);
|
||||
this.Controls.Add(this.akSpritesAlphaGroupBox);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
@ -657,6 +731,10 @@
|
||||
this.groupBox1.PerformLayout();
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.l2dGroupBox.ResumeLayout(false);
|
||||
this.l2dGroupBox.PerformLayout();
|
||||
this.l2dMotionExportMethodPanel.ResumeLayout(false);
|
||||
this.l2dMotionExportMethodPanel.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).EndInit();
|
||||
@ -705,7 +783,7 @@
|
||||
private System.Windows.Forms.CheckBox restoreExtensionName;
|
||||
private System.Windows.Forms.CheckBox openAfterExport;
|
||||
private System.Windows.Forms.CheckBox exportAllUvsAsDiffuseMaps;
|
||||
private System.Windows.Forms.ToolTip exportUvsTooltip;
|
||||
private System.Windows.Forms.ToolTip optionTooltip;
|
||||
private System.Windows.Forms.CheckBox exportSpriteWithAlphaMask;
|
||||
private System.Windows.Forms.RadioButton towebp;
|
||||
private System.Windows.Forms.GroupBox akSpritesAlphaGroupBox;
|
||||
@ -719,5 +797,11 @@
|
||||
private System.Windows.Forms.GroupBox akSpritesExportGroupBox;
|
||||
private System.Windows.Forms.CheckBox akAddAliasesCheckBox;
|
||||
private System.Windows.Forms.Label akGammaNoteLabel;
|
||||
private System.Windows.Forms.GroupBox l2dGroupBox;
|
||||
private System.Windows.Forms.CheckBox l2dForceBezierCheckBox;
|
||||
private System.Windows.Forms.Label l2dMotionExportMethodLabel;
|
||||
private System.Windows.Forms.RadioButton l2dAnimationClipRadioButton;
|
||||
private System.Windows.Forms.RadioButton l2dMonoBehaviourRadioButton;
|
||||
private System.Windows.Forms.Panel l2dMotionExportMethodPanel;
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using AssetStudio;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
@ -14,15 +15,8 @@ namespace AssetStudioGUI
|
||||
converttexture.Checked = Properties.Settings.Default.convertTexture;
|
||||
exportSpriteWithAlphaMask.Checked = Properties.Settings.Default.exportSpriteWithMask;
|
||||
convertAudio.Checked = Properties.Settings.Default.convertAudio;
|
||||
var str = Properties.Settings.Default.convertType.ToString();
|
||||
foreach (Control c in panel1.Controls)
|
||||
{
|
||||
if (c.Text == str)
|
||||
{
|
||||
((RadioButton)c).Checked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var defaultImageType = Properties.Settings.Default.convertType.ToString();
|
||||
((RadioButton)panel1.Controls.Cast<Control>().First(x => x.Text == defaultImageType)).Checked = true;
|
||||
openAfterExport.Checked = Properties.Settings.Default.openAfterExport;
|
||||
eulerFilter.Checked = Properties.Settings.Default.eulerFilter;
|
||||
filterPrecision.Value = Properties.Settings.Default.filterPrecision;
|
||||
@ -44,6 +38,9 @@ namespace AssetStudioGUI
|
||||
akResizedOnlyCheckBox.Checked = Properties.Settings.Default.resizedOnly;
|
||||
akAddAliasesCheckBox.Checked = Properties.Settings.Default.addAliases;
|
||||
|
||||
var defaultMotionMode = Properties.Settings.Default.l2dMotionMode.ToString();
|
||||
((RadioButton)l2dMotionExportMethodPanel.Controls.Cast<Control>().First(x => x.AccessibleName == defaultMotionMode)).Checked = true;
|
||||
l2dForceBezierCheckBox.Checked = Properties.Settings.Default.l2dForceBezier;
|
||||
}
|
||||
|
||||
private void OKbutton_Click(object sender, EventArgs e)
|
||||
@ -53,14 +50,8 @@ namespace AssetStudioGUI
|
||||
Properties.Settings.Default.convertTexture = converttexture.Checked;
|
||||
Properties.Settings.Default.exportSpriteWithMask = exportSpriteWithAlphaMask.Checked;
|
||||
Properties.Settings.Default.convertAudio = convertAudio.Checked;
|
||||
foreach (Control c in panel1.Controls)
|
||||
{
|
||||
if (((RadioButton)c).Checked)
|
||||
{
|
||||
Properties.Settings.Default.convertType = (ImageFormat)Enum.Parse(typeof(ImageFormat), c.Text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
var checkedImageType = (RadioButton)panel1.Controls.Cast<Control>().First(x => ((RadioButton)x).Checked);
|
||||
Properties.Settings.Default.convertType = (ImageFormat)Enum.Parse(typeof(ImageFormat), checkedImageType.Text);
|
||||
Properties.Settings.Default.openAfterExport = openAfterExport.Checked;
|
||||
Properties.Settings.Default.eulerFilter = eulerFilter.Checked;
|
||||
Properties.Settings.Default.filterPrecision = filterPrecision.Value;
|
||||
@ -81,6 +72,9 @@ namespace AssetStudioGUI
|
||||
Properties.Settings.Default.resizedOnly = akResizedOnlyCheckBox.Checked;
|
||||
Properties.Settings.Default.addAliases = akAddAliasesCheckBox.Checked;
|
||||
|
||||
var checkedMotionMode = (RadioButton)l2dMotionExportMethodPanel.Controls.Cast<Control>().First(x => ((RadioButton)x).Checked);
|
||||
Properties.Settings.Default.l2dMotionMode = (CubismLive2DExtractor.Live2DMotionMode)Enum.Parse(typeof(CubismLive2DExtractor.Live2DMotionMode), checkedMotionMode.AccessibleName);
|
||||
Properties.Settings.Default.l2dForceBezier = l2dForceBezierCheckBox.Checked;
|
||||
Properties.Settings.Default.Save();
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
|
@ -117,7 +117,7 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="exportUvsTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<metadata name="optionTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
@ -1,5 +1,8 @@
|
||||
using AssetStudio;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
@ -7,15 +10,122 @@ namespace AssetStudioGUI
|
||||
class GUILogger : ILogger
|
||||
{
|
||||
public bool ShowErrorMessage = false;
|
||||
private bool IsFileLoggerRunning = false;
|
||||
private string LoggerInitString;
|
||||
private string FileLogName;
|
||||
private string FileLogPath;
|
||||
private Action<string> action;
|
||||
|
||||
private bool _useFileLogger = false;
|
||||
public bool UseFileLogger
|
||||
{
|
||||
get => _useFileLogger;
|
||||
set
|
||||
{
|
||||
_useFileLogger = value;
|
||||
if (_useFileLogger && !IsFileLoggerRunning)
|
||||
{
|
||||
var appAssembly = typeof(Program).Assembly.GetName();
|
||||
FileLogName = $"{appAssembly.Name}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log";
|
||||
FileLogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FileLogName);
|
||||
|
||||
LogToFile(LoggerEvent.Verbose, $"# {LoggerInitString} - Logger launched #");
|
||||
IsFileLoggerRunning = true;
|
||||
}
|
||||
else if (!_useFileLogger && IsFileLoggerRunning)
|
||||
{
|
||||
LogToFile(LoggerEvent.Verbose, "# Logger closed #");
|
||||
IsFileLoggerRunning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GUILogger(Action<string> action)
|
||||
{
|
||||
this.action = action;
|
||||
|
||||
var appAssembly = typeof(Program).Assembly.GetName();
|
||||
var arch = Environment.Is64BitProcess ? "x64" : "x32";
|
||||
var frameworkName = AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName;
|
||||
LoggerInitString = $"{appAssembly.Name} v{appAssembly.Version} [{arch}] [{frameworkName}]";
|
||||
try
|
||||
{
|
||||
Console.Title = $"Console Logger - {appAssembly.Name} v{appAssembly.Version}";
|
||||
Console.OutputEncoding = System.Text.Encoding.UTF8;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
Console.WriteLine($"# {LoggerInitString}");
|
||||
}
|
||||
|
||||
private static string ColorLogLevel(LoggerEvent logLevel)
|
||||
{
|
||||
var formattedLevel = $"[{logLevel}]";
|
||||
switch (logLevel)
|
||||
{
|
||||
case LoggerEvent.Info:
|
||||
return $"{formattedLevel.Color(ColorConsole.BrightCyan)}";
|
||||
case LoggerEvent.Warning:
|
||||
return $"{formattedLevel.Color(ColorConsole.BrightYellow)}";
|
||||
case LoggerEvent.Error:
|
||||
return $"{formattedLevel.Color(ColorConsole.BrightRed)}";
|
||||
default:
|
||||
return formattedLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatMessage(LoggerEvent logMsgLevel, string message, bool toConsole)
|
||||
{
|
||||
message = message.TrimEnd();
|
||||
var multiLine = message.Contains('\n');
|
||||
|
||||
string formattedMessage;
|
||||
if (toConsole)
|
||||
{
|
||||
var colorLogLevel = ColorLogLevel(logMsgLevel);
|
||||
formattedMessage = $"{colorLogLevel} {message}";
|
||||
if (multiLine)
|
||||
{
|
||||
formattedMessage = formattedMessage.Replace("\n", $"\n{colorLogLevel} ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var curTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
message = Regex.Replace(message, @"\e\[[0-9;]*m(?:\e\[K)?", ""); //Delete ANSI colors
|
||||
var logLevel = $"{logMsgLevel.ToString().ToUpper(),-7}";
|
||||
formattedMessage = $"{curTime} | {logLevel} | {message}";
|
||||
if (multiLine)
|
||||
{
|
||||
formattedMessage = formattedMessage.Replace("\n", $"\n{curTime} | {logLevel} | ");
|
||||
}
|
||||
}
|
||||
|
||||
return formattedMessage;
|
||||
}
|
||||
|
||||
private async void LogToFile(LoggerEvent logMsgLevel, string message)
|
||||
{
|
||||
using (var sw = new StreamWriter(FileLogPath, append: true, System.Text.Encoding.UTF8))
|
||||
{
|
||||
await sw.WriteLineAsync(FormatMessage(logMsgLevel, message, toConsole: false));
|
||||
}
|
||||
}
|
||||
|
||||
public void Log(LoggerEvent loggerEvent, string message, bool ignoreLevel)
|
||||
{
|
||||
//File logger
|
||||
if (_useFileLogger)
|
||||
{
|
||||
LogToFile(loggerEvent, message);
|
||||
}
|
||||
|
||||
//Console logger
|
||||
Console.WriteLine(FormatMessage(loggerEvent, message, toConsole: true));
|
||||
|
||||
//GUI logger
|
||||
switch (loggerEvent)
|
||||
{
|
||||
case LoggerEvent.Error:
|
||||
|
62
AssetStudioGUI/Properties/Settings.Designer.cs
generated
62
AssetStudioGUI/Properties/Settings.Designer.cs
generated
@ -12,7 +12,7 @@ namespace AssetStudioGUI.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.8.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
@ -358,5 +358,65 @@ namespace AssetStudioGUI.Properties {
|
||||
this["alphaMaskGamma"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("MonoBehaviour")]
|
||||
public global::CubismLive2DExtractor.Live2DMotionMode l2dMotionMode {
|
||||
get {
|
||||
return ((global::CubismLive2DExtractor.Live2DMotionMode)(this["l2dMotionMode"]));
|
||||
}
|
||||
set {
|
||||
this["l2dMotionMode"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool l2dForceBezier {
|
||||
get {
|
||||
return ((bool)(this["l2dForceBezier"]));
|
||||
}
|
||||
set {
|
||||
this["l2dForceBezier"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool showConsole {
|
||||
get {
|
||||
return ((bool)(this["showConsole"]));
|
||||
}
|
||||
set {
|
||||
this["showConsole"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool useFileLogger {
|
||||
get {
|
||||
return ((bool)(this["useFileLogger"]));
|
||||
}
|
||||
set {
|
||||
this["useFileLogger"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool buildTreeStructure {
|
||||
get {
|
||||
return ((bool)(this["buildTreeStructure"]));
|
||||
}
|
||||
set {
|
||||
this["buildTreeStructure"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,5 +86,20 @@
|
||||
<Setting Name="alphaMaskGamma" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">2</Value>
|
||||
</Setting>
|
||||
<Setting Name="l2dMotionMode" Type="CubismLive2DExtractor.Live2DMotionMode" Scope="User">
|
||||
<Value Profile="(Default)">MonoBehaviour</Value>
|
||||
</Setting>
|
||||
<Setting Name="l2dForceBezier" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="showConsole" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="useFileLogger" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="buildTreeStructure" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
@ -158,10 +158,13 @@ namespace AssetStudioGUI
|
||||
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
|
||||
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
|
||||
var containers = new List<(PPtr<Object>, string)>();
|
||||
int i = 0;
|
||||
allContainers.Clear();
|
||||
var i = 0;
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||
{
|
||||
var preloadTable = Array.Empty<PPtr<Object>>();
|
||||
|
||||
foreach (var asset in assetsFile.Objects)
|
||||
{
|
||||
var assetItem = new AssetItem(asset);
|
||||
@ -170,6 +173,9 @@ namespace AssetStudioGUI
|
||||
var exportable = false;
|
||||
switch (asset)
|
||||
{
|
||||
case PreloadData m_PreloadData:
|
||||
preloadTable = m_PreloadData.m_Assets;
|
||||
break;
|
||||
case GameObject m_GameObject:
|
||||
assetItem.Text = m_GameObject.m_Name;
|
||||
break;
|
||||
@ -187,7 +193,7 @@ namespace AssetStudioGUI
|
||||
break;
|
||||
case VideoClip m_VideoClip:
|
||||
if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath))
|
||||
assetItem.FullSize = asset.byteSize + (long)m_VideoClip.m_ExternalResources.m_Size;
|
||||
assetItem.FullSize = asset.byteSize + m_VideoClip.m_ExternalResources.m_Size;
|
||||
assetItem.Text = m_VideoClip.m_Name;
|
||||
exportable = true;
|
||||
break;
|
||||
@ -226,17 +232,23 @@ namespace AssetStudioGUI
|
||||
productName = m_PlayerSettings.productName;
|
||||
break;
|
||||
case AssetBundle m_AssetBundle:
|
||||
var isStreamedSceneAssetBundle = m_AssetBundle.m_IsStreamedSceneAssetBundle;
|
||||
if (!isStreamedSceneAssetBundle)
|
||||
{
|
||||
preloadTable = m_AssetBundle.m_PreloadTable;
|
||||
}
|
||||
assetItem.Text = string.IsNullOrEmpty(m_AssetBundle.m_AssetBundleName) ? m_AssetBundle.m_Name : m_AssetBundle.m_AssetBundleName;
|
||||
|
||||
foreach (var m_Container in m_AssetBundle.m_Container)
|
||||
{
|
||||
var preloadIndex = m_Container.Value.preloadIndex;
|
||||
var preloadSize = m_Container.Value.preloadSize;
|
||||
var preloadSize = isStreamedSceneAssetBundle ? preloadTable.Length : m_Container.Value.preloadSize;
|
||||
var preloadEnd = preloadIndex + preloadSize;
|
||||
for (int k = preloadIndex; k < preloadEnd; k++)
|
||||
for (var k = preloadIndex; k < preloadEnd; k++)
|
||||
{
|
||||
containers.Add((m_AssetBundle.m_PreloadTable[k], m_Container.Key));
|
||||
containers.Add((preloadTable[k], m_Container.Key));
|
||||
}
|
||||
}
|
||||
assetItem.Text = m_AssetBundle.m_Name;
|
||||
break;
|
||||
case ResourceManager m_ResourceManager:
|
||||
foreach (var m_Container in m_ResourceManager.m_Container)
|
||||
@ -259,7 +271,7 @@ namespace AssetStudioGUI
|
||||
Progress.Report(++i, objectCount);
|
||||
}
|
||||
}
|
||||
foreach ((var pptr, var container) in containers)
|
||||
foreach (var (pptr, container) in containers)
|
||||
{
|
||||
if (pptr.TryGet(out var obj))
|
||||
{
|
||||
@ -285,12 +297,19 @@ namespace AssetStudioGUI
|
||||
|
||||
visibleAssets = exportableAssets;
|
||||
|
||||
if (!Properties.Settings.Default.buildTreeStructure)
|
||||
{
|
||||
Logger.Info("Building tree structure step is skipped");
|
||||
objectAssetItemDic.Clear();
|
||||
return (productName, new List<TreeNode>());
|
||||
}
|
||||
|
||||
Logger.Info("Building tree structure...");
|
||||
|
||||
var treeNodeCollection = new List<TreeNode>();
|
||||
var treeNodeDictionary = new Dictionary<GameObject, GameObjectTreeNode>();
|
||||
var assetsFileCount = assetsManager.assetsFileList.Count;
|
||||
int j = 0;
|
||||
var j = 0;
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||
{
|
||||
@ -358,7 +377,6 @@ namespace AssetStudioGUI
|
||||
Progress.Report(++j, assetsFileCount);
|
||||
}
|
||||
treeNodeDictionary.Clear();
|
||||
|
||||
objectAssetItemDic.Clear();
|
||||
|
||||
return (productName, treeNodeCollection);
|
||||
@ -396,7 +414,6 @@ namespace AssetStudioGUI
|
||||
typeMap.Add(assetsFile.unityVersion, items);
|
||||
}
|
||||
}
|
||||
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
@ -755,6 +772,8 @@ namespace AssetStudioGUI
|
||||
public static void ExportLive2D(Object[] cubismMocs, string exportPath)
|
||||
{
|
||||
var baseDestPath = Path.Combine(exportPath, "Live2DOutput");
|
||||
var motionMode = Properties.Settings.Default.l2dMotionMode;
|
||||
var forceBezier = Properties.Settings.Default.l2dForceBezier;
|
||||
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
@ -763,48 +782,73 @@ namespace AssetStudioGUI
|
||||
var useFullContainerPath = false;
|
||||
if (cubismMocs.Length > 1)
|
||||
{
|
||||
var basePathSet = cubismMocs.Select(x => allContainers[x].Substring(0, allContainers[x].LastIndexOf("/"))).ToHashSet();
|
||||
var basePathSet = cubismMocs.Select(x =>
|
||||
{
|
||||
var pathLen = allContainers.TryGetValue(x, out var itemContainer) ? itemContainer.LastIndexOf("/") : 0;
|
||||
pathLen = pathLen < 0 ? allContainers[x].Length : pathLen;
|
||||
return itemContainer?.Substring(0, pathLen);
|
||||
}).ToHashSet();
|
||||
|
||||
if (basePathSet.All(x => x == null))
|
||||
{
|
||||
Logger.Error($"Live2D Cubism export error\r\nCannot find any model related files");
|
||||
StatusStripUpdate("Live2D export canceled");
|
||||
Progress.Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (basePathSet.Count != cubismMocs.Length)
|
||||
{
|
||||
useFullContainerPath = true;
|
||||
}
|
||||
}
|
||||
var basePathList = useFullContainerPath ?
|
||||
cubismMocs.Select(x => allContainers[x]).ToList() :
|
||||
cubismMocs.Select(x => allContainers[x].Substring(0, allContainers[x].LastIndexOf("/"))).ToList();
|
||||
|
||||
var basePathList = cubismMocs.Select(x =>
|
||||
{
|
||||
allContainers.TryGetValue(x, out var container);
|
||||
container = useFullContainerPath
|
||||
? container
|
||||
: container?.Substring(0, container.LastIndexOf("/"));
|
||||
return container;
|
||||
}).Where(x => x != null).ToList();
|
||||
|
||||
var lookup = allContainers.ToLookup(
|
||||
x => basePathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
||||
x => x.Key
|
||||
);
|
||||
|
||||
var totalModelCount = lookup.LongCount(x => x.Key != null);
|
||||
var name = "";
|
||||
var modelCounter = 0;
|
||||
foreach (var assets in lookup)
|
||||
{
|
||||
var container = assets.Key;
|
||||
if (container == null)
|
||||
var srcContainer = assets.Key;
|
||||
if (srcContainer == null)
|
||||
continue;
|
||||
name = container;
|
||||
var container = srcContainer;
|
||||
|
||||
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{container}\"...");
|
||||
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{srcContainer}\"...");
|
||||
try
|
||||
{
|
||||
var modelName = useFullContainerPath ? Path.GetFileNameWithoutExtension(container) : container.Substring(container.LastIndexOf('/') + 1);
|
||||
container = Path.HasExtension(container) ? container.Replace(Path.GetExtension(container), "") : container;
|
||||
var destPath = Path.Combine(baseDestPath, container) + Path.DirectorySeparatorChar;
|
||||
|
||||
ExtractLive2D(assets, destPath, modelName, assemblyLoader);
|
||||
ExtractLive2D(assets, destPath, modelName, assemblyLoader, motionMode, forceBezier);
|
||||
modelCounter++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"Live2D model export error: \"{name}\"", ex);
|
||||
Logger.Error($"Live2D model export error: \"{srcContainer}\"", ex);
|
||||
}
|
||||
Progress.Report(modelCounter, (int)totalModelCount);
|
||||
}
|
||||
|
||||
Logger.Info($"Finished exporting [{modelCounter}/{totalModelCount}] Live2D model(s).");
|
||||
if (modelCounter < totalModelCount)
|
||||
{
|
||||
var total = (int)totalModelCount;
|
||||
Progress.Report(total, total);
|
||||
}
|
||||
if (Properties.Settings.Default.openAfterExport && modelCounter > 0)
|
||||
{
|
||||
OpenFolderInExplorer(exportPath);
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<Version>1.0.1</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
@ -22,7 +22,7 @@
|
||||
<PackageReference Include="Kyaru.Texture2DDecoder">
|
||||
<Version>0.17.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
|
||||
|
30
AssetStudioUtility/CubismLive2DExtractor/CubismFadeMotion.cs
Normal file
30
AssetStudioUtility/CubismLive2DExtractor/CubismFadeMotion.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace CubismLive2DExtractor
|
||||
{
|
||||
public class AnimationCurve
|
||||
{
|
||||
public CubismKeyframeData[] m_Curve { get; set; }
|
||||
public int m_PreInfinity { get; set; }
|
||||
public int m_PostInfinity { get; set; }
|
||||
public int m_RotationOrder { get; set; }
|
||||
}
|
||||
|
||||
public class CubismFadeMotion
|
||||
{
|
||||
public string m_Name { get; set; }
|
||||
public string MotionName { get; set; }
|
||||
public float FadeInTime { get; set; }
|
||||
public float FadeOutTime { get; set; }
|
||||
public string[] ParameterIds { get; set; }
|
||||
public AnimationCurve[] ParameterCurves { get; set; }
|
||||
public float[] ParameterFadeInTimes { get; set; }
|
||||
public float[] ParameterFadeOutTimes { get; set; }
|
||||
public float MotionLength { get; set; }
|
||||
|
||||
public CubismFadeMotion()
|
||||
{
|
||||
ParameterIds = Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
namespace CubismLive2DExtractor
|
||||
{
|
||||
public class CubismKeyframeData
|
||||
{
|
||||
public float time { get; set; }
|
||||
public float value { get; set; }
|
||||
public float inSlope { get; set; }
|
||||
public float outSlope { get; set; }
|
||||
public int weightedMode { get; set; }
|
||||
public float inWeight { get; set; }
|
||||
public float outWeight { get; set; }
|
||||
|
||||
public CubismKeyframeData() { }
|
||||
|
||||
public CubismKeyframeData(ImportedKeyframe<float> keyframe)
|
||||
{
|
||||
time = keyframe.time;
|
||||
value = keyframe.value;
|
||||
inSlope = keyframe.inSlope;
|
||||
outSlope = keyframe.outSlope;
|
||||
weightedMode = 0;
|
||||
inWeight = 0;
|
||||
outWeight = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AssetStudio;
|
||||
|
||||
@ -73,7 +72,7 @@ namespace CubismLive2DExtractor
|
||||
|
||||
if (iAnim.TrackList.Count == 0 || iAnim.Events.Count == 0)
|
||||
{
|
||||
Logger.Warning($"[Motion Converter] {iAnim.Name} has {iAnim.TrackList.Count} tracks and {iAnim.Events.Count} event!.");
|
||||
Logger.Warning($"[Motion Converter] \"{iAnim.Name}\" has {iAnim.TrackList.Count} tracks and {iAnim.Events.Count} event!.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,7 +83,7 @@ namespace CubismLive2DExtractor
|
||||
GetLive2dPath(binding, out var target, out var boneName);
|
||||
if (string.IsNullOrEmpty(boneName))
|
||||
{
|
||||
Logger.Warning($"[Motion Converter] {iAnim.Name} read fail on binding {Array.IndexOf(m_ClipBindingConstant.genericBindings, binding)}");
|
||||
Logger.Warning($"[Motion Converter] \"{iAnim.Name}\" read fail on binding {Array.IndexOf(m_ClipBindingConstant.genericBindings, binding)}");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -99,7 +98,7 @@ namespace CubismLive2DExtractor
|
||||
GetLive2dPath(binding, out var target, out var boneName);
|
||||
if (string.IsNullOrEmpty(boneName))
|
||||
{
|
||||
Logger.Warning($"[Motion Converter] {iAnim.Name} read fail on binding {Array.IndexOf(m_ClipBindingConstant.genericBindings, binding)}");
|
||||
Logger.Warning($"[Motion Converter] \"{iAnim.Name}\" read fail on binding {Array.IndexOf(m_ClipBindingConstant.genericBindings, binding)}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
using System;
|
||||
// File Format Specifications
|
||||
// https://github.com/Live2D/CubismSpecs/blob/master/FileFormats/motion3.json.md
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CubismLive2DExtractor
|
||||
{
|
||||
@ -18,24 +20,238 @@ namespace CubismLive2DExtractor
|
||||
public float Fps;
|
||||
public bool Loop;
|
||||
public bool AreBeziersRestricted;
|
||||
public float FadeInTime;
|
||||
public float FadeOutTime;
|
||||
public int CurveCount;
|
||||
public int TotalSegmentCount;
|
||||
public int TotalPointCount;
|
||||
public int UserDataCount;
|
||||
public int TotalUserDataSize;
|
||||
};
|
||||
}
|
||||
|
||||
public class SerializableCurve
|
||||
{
|
||||
public string Target;
|
||||
public string Id;
|
||||
public float FadeInTime;
|
||||
public float FadeOutTime;
|
||||
public List<float> Segments;
|
||||
};
|
||||
}
|
||||
|
||||
public class SerializableUserData
|
||||
{
|
||||
public float Time;
|
||||
public string Value;
|
||||
}
|
||||
|
||||
private static void AddSegments(
|
||||
CubismKeyframeData curve,
|
||||
CubismKeyframeData preCurve,
|
||||
CubismKeyframeData nextCurve,
|
||||
SerializableCurve cubismCurve,
|
||||
bool forceBezier,
|
||||
ref int totalPointCount,
|
||||
ref int totalSegmentCount,
|
||||
ref int j
|
||||
)
|
||||
{
|
||||
if (Math.Abs(curve.time - preCurve.time - 0.01f) < 0.0001f) // InverseSteppedSegment
|
||||
{
|
||||
if (nextCurve.value == curve.value)
|
||||
{
|
||||
cubismCurve.Segments.Add(3f); // Segment ID
|
||||
cubismCurve.Segments.Add(nextCurve.time);
|
||||
cubismCurve.Segments.Add(nextCurve.value);
|
||||
j += 1;
|
||||
totalPointCount += 1;
|
||||
totalSegmentCount++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (float.IsPositiveInfinity(curve.inSlope)) // SteppedSegment
|
||||
{
|
||||
cubismCurve.Segments.Add(2f); // Segment ID
|
||||
cubismCurve.Segments.Add(curve.time);
|
||||
cubismCurve.Segments.Add(curve.value);
|
||||
totalPointCount += 1;
|
||||
}
|
||||
else if (preCurve.outSlope == 0f && Math.Abs(curve.inSlope) < 0.0001f && !forceBezier) // LinearSegment
|
||||
{
|
||||
cubismCurve.Segments.Add(0f); // Segment ID
|
||||
cubismCurve.Segments.Add(curve.time);
|
||||
cubismCurve.Segments.Add(curve.value);
|
||||
totalPointCount += 1;
|
||||
}
|
||||
else // BezierSegment
|
||||
{
|
||||
var tangentLength = (curve.time - preCurve.time) / 3f;
|
||||
cubismCurve.Segments.Add(1f); // Segment ID
|
||||
cubismCurve.Segments.Add(preCurve.time + tangentLength);
|
||||
cubismCurve.Segments.Add(preCurve.outSlope * tangentLength + preCurve.value);
|
||||
cubismCurve.Segments.Add(curve.time - tangentLength);
|
||||
cubismCurve.Segments.Add(curve.value - curve.inSlope * tangentLength);
|
||||
cubismCurve.Segments.Add(curve.time);
|
||||
cubismCurve.Segments.Add(curve.value);
|
||||
totalPointCount += 3;
|
||||
}
|
||||
totalSegmentCount++;
|
||||
}
|
||||
|
||||
public CubismMotion3Json(CubismFadeMotion fadeMotion, HashSet<string> paramNames, HashSet<string> partNames, bool forceBezier)
|
||||
{
|
||||
Version = 3;
|
||||
Meta = new SerializableMeta
|
||||
{
|
||||
// Duration of the motion in seconds.
|
||||
Duration = fadeMotion.MotionLength,
|
||||
// Framerate of the motion in seconds.
|
||||
Fps = 30,
|
||||
// [Optional] Status of the looping of the motion.
|
||||
Loop = true,
|
||||
// [Optional] Status of the restriction of Bezier handles'X translations.
|
||||
AreBeziersRestricted = true,
|
||||
// [Optional] Time of the overall Fade-In for easing in seconds.
|
||||
FadeInTime = fadeMotion.FadeInTime,
|
||||
// [Optional] Time of the overall Fade-Out for easing in seconds.
|
||||
FadeOutTime = fadeMotion.FadeOutTime,
|
||||
// The total number of curves.
|
||||
CurveCount = (int)fadeMotion.ParameterCurves.LongCount(x => x.m_Curve.Length > 0),
|
||||
// [Optional] The total number of UserData.
|
||||
UserDataCount = 0
|
||||
};
|
||||
// Motion curves.
|
||||
Curves = new SerializableCurve[Meta.CurveCount];
|
||||
|
||||
var totalSegmentCount = 1;
|
||||
var totalPointCount = 1;
|
||||
var actualCurveCount = 0;
|
||||
for (var i = 0; i < fadeMotion.ParameterCurves.Length; i++)
|
||||
{
|
||||
if (fadeMotion.ParameterCurves[i].m_Curve.Length == 0)
|
||||
continue;
|
||||
|
||||
string target;
|
||||
string paramId = fadeMotion.ParameterIds[i];
|
||||
switch (paramId)
|
||||
{
|
||||
case "Opacity":
|
||||
case "EyeBlink":
|
||||
case "LipSync":
|
||||
target = "Model";
|
||||
break;
|
||||
default:
|
||||
if (paramNames.Contains(paramId))
|
||||
{
|
||||
target = "Parameter";
|
||||
}
|
||||
else if (partNames.Contains(paramId))
|
||||
{
|
||||
target = "PartOpacity";
|
||||
}
|
||||
else
|
||||
{
|
||||
target = paramId.ToLower().Contains("part") ? "PartOpacity" : "Parameter";
|
||||
AssetStudio.Logger.Warning($"[{fadeMotion.m_Name}] Binding error: Unable to find \"{paramId}\" among the model parts/parameters");
|
||||
}
|
||||
break;
|
||||
}
|
||||
Curves[actualCurveCount] = new SerializableCurve
|
||||
{
|
||||
// Target type.
|
||||
Target = target,
|
||||
// Identifier for mapping curve to target.
|
||||
Id = paramId,
|
||||
// [Optional] Time of the Fade - In for easing in seconds.
|
||||
FadeInTime = fadeMotion.ParameterFadeInTimes[i],
|
||||
// [Optional] Time of the Fade - Out for easing in seconds.
|
||||
FadeOutTime = fadeMotion.ParameterFadeOutTimes[i],
|
||||
// Flattened segments.
|
||||
Segments = new List<float>
|
||||
{
|
||||
// First point
|
||||
fadeMotion.ParameterCurves[i].m_Curve[0].time,
|
||||
fadeMotion.ParameterCurves[i].m_Curve[0].value
|
||||
}
|
||||
};
|
||||
for (var j = 1; j < fadeMotion.ParameterCurves[i].m_Curve.Length; j++)
|
||||
{
|
||||
var curve = fadeMotion.ParameterCurves[i].m_Curve[j];
|
||||
var preCurve = fadeMotion.ParameterCurves[i].m_Curve[j - 1];
|
||||
var next = fadeMotion.ParameterCurves[i].m_Curve.ElementAtOrDefault(j + 1);
|
||||
var nextCurve = next ?? new CubismKeyframeData();
|
||||
AddSegments(curve, preCurve, nextCurve, Curves[actualCurveCount], forceBezier, ref totalPointCount, ref totalSegmentCount, ref j);
|
||||
}
|
||||
actualCurveCount++;
|
||||
}
|
||||
|
||||
// The total number of segments (from all curves).
|
||||
Meta.TotalSegmentCount = totalSegmentCount;
|
||||
// The total number of points (from all segments of all curves).
|
||||
Meta.TotalPointCount = totalPointCount;
|
||||
|
||||
UserData = Array.Empty<SerializableUserData>();
|
||||
// [Optional] The total size of UserData in bytes.
|
||||
Meta.TotalUserDataSize = 0;
|
||||
}
|
||||
|
||||
public CubismMotion3Json(ImportedKeyframedAnimation animation, bool forceBezier)
|
||||
{
|
||||
Version = 3;
|
||||
Meta = new SerializableMeta
|
||||
{
|
||||
Duration = animation.Duration,
|
||||
Fps = animation.SampleRate,
|
||||
Loop = true,
|
||||
AreBeziersRestricted = true,
|
||||
FadeInTime = 0,
|
||||
FadeOutTime = 0,
|
||||
CurveCount = animation.TrackList.Count,
|
||||
UserDataCount = animation.Events.Count
|
||||
};
|
||||
Curves = new SerializableCurve[Meta.CurveCount];
|
||||
|
||||
var totalSegmentCount = 1;
|
||||
var totalPointCount = 1;
|
||||
for (var i = 0; i < Meta.CurveCount; i++)
|
||||
{
|
||||
var track = animation.TrackList[i];
|
||||
Curves[i] = new SerializableCurve
|
||||
{
|
||||
Target = track.Target,
|
||||
Id = track.Name,
|
||||
FadeInTime = -1,
|
||||
FadeOutTime = -1,
|
||||
Segments = new List<float>
|
||||
{
|
||||
0f,
|
||||
track.Curve[0].value
|
||||
}
|
||||
};
|
||||
for (var j = 1; j < track.Curve.Count; j++)
|
||||
{
|
||||
var curve = new CubismKeyframeData(track.Curve[j]);
|
||||
var preCurve = new CubismKeyframeData(track.Curve[j - 1]);
|
||||
var next = track.Curve.ElementAtOrDefault(j + 1);
|
||||
var nextCurve = next != null ? new CubismKeyframeData(next) : new CubismKeyframeData();
|
||||
AddSegments(curve, preCurve, nextCurve, Curves[i], forceBezier, ref totalPointCount, ref totalSegmentCount, ref j);
|
||||
}
|
||||
}
|
||||
Meta.TotalSegmentCount = totalSegmentCount;
|
||||
Meta.TotalPointCount = totalPointCount;
|
||||
|
||||
UserData = new SerializableUserData[Meta.UserDataCount];
|
||||
var totalUserDataSize = 0;
|
||||
for (var i = 0; i < Meta.UserDataCount; i++)
|
||||
{
|
||||
var @event = animation.Events[i];
|
||||
UserData[i] = new SerializableUserData
|
||||
{
|
||||
Time = @event.time,
|
||||
Value = @event.value
|
||||
};
|
||||
totalUserDataSize += @event.value.Length;
|
||||
}
|
||||
Meta.TotalUserDataSize = totalUserDataSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ namespace CubismLive2DExtractor
|
||||
{
|
||||
public static class Live2DExtractor
|
||||
{
|
||||
public static void ExtractLive2D(IGrouping<string, AssetStudio.Object> assets, string destPath, string modelName, AssemblyLoader assemblyLoader)
|
||||
public static void ExtractLive2D(IGrouping<string, AssetStudio.Object> assets, string destPath, string modelName, AssemblyLoader assemblyLoader, Live2DMotionMode motionMode, bool forceBezier = false)
|
||||
{
|
||||
var destTexturePath = Path.Combine(destPath, "textures") + Path.DirectorySeparatorChar;
|
||||
var destMotionPath = Path.Combine(destPath, "motions") + Path.DirectorySeparatorChar;
|
||||
@ -26,20 +26,75 @@ namespace CubismLive2DExtractor
|
||||
Directory.CreateDirectory(destPath);
|
||||
Directory.CreateDirectory(destTexturePath);
|
||||
|
||||
var monoBehaviours = new List<MonoBehaviour>();
|
||||
var texture2Ds = new List<Texture2D>();
|
||||
var expressionList = new List<MonoBehaviour>();
|
||||
var fadeMotionList = new List<MonoBehaviour>();
|
||||
var gameObjects = new List<GameObject>();
|
||||
var animationClips = new List<AnimationClip>();
|
||||
|
||||
var textures = new SortedSet<string>();
|
||||
var eyeBlinkParameters = new HashSet<string>();
|
||||
var lipSyncParameters = new HashSet<string>();
|
||||
var parameterNames = new HashSet<string>();
|
||||
var partNames = new HashSet<string>();
|
||||
MonoBehaviour physics = null;
|
||||
|
||||
foreach (var asset in assets)
|
||||
{
|
||||
switch (asset)
|
||||
{
|
||||
case MonoBehaviour m_MonoBehaviour:
|
||||
monoBehaviours.Add(m_MonoBehaviour);
|
||||
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
switch (m_Script.m_ClassName)
|
||||
{
|
||||
case "CubismMoc":
|
||||
File.WriteAllBytes($"{destPath}{modelName}.moc3", ParseMoc(m_MonoBehaviour)); //moc
|
||||
break;
|
||||
case "CubismPhysicsController":
|
||||
physics = physics ?? m_MonoBehaviour;
|
||||
break;
|
||||
case "CubismExpressionData":
|
||||
expressionList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismFadeMotionData":
|
||||
fadeMotionList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismEyeBlinkParameter":
|
||||
if (m_MonoBehaviour.m_GameObject.TryGet(out var blinkGameObject))
|
||||
{
|
||||
eyeBlinkParameters.Add(blinkGameObject.m_Name);
|
||||
}
|
||||
break;
|
||||
case "CubismMouthParameter":
|
||||
if (m_MonoBehaviour.m_GameObject.TryGet(out var mouthGameObject))
|
||||
{
|
||||
lipSyncParameters.Add(mouthGameObject.m_Name);
|
||||
}
|
||||
break;
|
||||
case "CubismParameter":
|
||||
if (m_MonoBehaviour.m_GameObject.TryGet(out var paramGameObject))
|
||||
{
|
||||
parameterNames.Add(paramGameObject.m_Name);
|
||||
}
|
||||
break;
|
||||
case "CubismPart":
|
||||
if (m_MonoBehaviour.m_GameObject.TryGet(out var partGameObject))
|
||||
{
|
||||
partNames.Add(partGameObject.m_Name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Texture2D m_Texture2D:
|
||||
texture2Ds.Add(m_Texture2D);
|
||||
using (var image = m_Texture2D.ConvertToImage(flip: true))
|
||||
{
|
||||
using (var file = File.OpenWrite($"{destTexturePath}{m_Texture2D.m_Name}.png"))
|
||||
{
|
||||
image.WriteToStream(file, ImageFormat.Png);
|
||||
}
|
||||
textures.Add($"textures/{m_Texture2D.m_Name}.png"); //texture
|
||||
}
|
||||
break;
|
||||
case GameObject m_GameObject:
|
||||
gameObjects.Add(m_GameObject);
|
||||
@ -50,15 +105,12 @@ namespace CubismLive2DExtractor
|
||||
}
|
||||
}
|
||||
|
||||
//physics
|
||||
var physics = monoBehaviours.FirstOrDefault(x =>
|
||||
if (textures.Count == 0)
|
||||
{
|
||||
if (x.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
return m_Script.m_ClassName == "CubismPhysicsController";
|
||||
}
|
||||
return false;
|
||||
});
|
||||
Logger.Warning($"No textures found for \"{modelName}\" model.");
|
||||
}
|
||||
|
||||
//physics
|
||||
if (physics != null)
|
||||
{
|
||||
try
|
||||
@ -73,36 +125,51 @@ namespace CubismLive2DExtractor
|
||||
}
|
||||
}
|
||||
|
||||
//moc
|
||||
var moc = monoBehaviours.First(x =>
|
||||
{
|
||||
if (x.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
return m_Script.m_ClassName == "CubismMoc";
|
||||
}
|
||||
return false;
|
||||
});
|
||||
File.WriteAllBytes($"{destPath}{modelName}.moc3", ParseMoc(moc));
|
||||
|
||||
//texture
|
||||
var textures = new SortedSet<string>();
|
||||
foreach (var texture2D in texture2Ds)
|
||||
{
|
||||
using (var image = texture2D.ConvertToImage(flip: true))
|
||||
{
|
||||
textures.Add($"textures/{texture2D.m_Name}.png");
|
||||
using (var file = File.OpenWrite($"{destTexturePath}{texture2D.m_Name}.png"))
|
||||
{
|
||||
image.WriteToStream(file, ImageFormat.Png);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//motion
|
||||
var motions = new SortedDictionary<string, JArray>();
|
||||
|
||||
if (gameObjects.Count > 0)
|
||||
if (motionMode == Live2DMotionMode.MonoBehaviour && fadeMotionList.Count > 0) //motion from MonoBehaviour
|
||||
{
|
||||
Logger.Debug("Motion export method: MonoBehaviour (Fade motion)");
|
||||
Directory.CreateDirectory(destMotionPath);
|
||||
foreach (var fadeMotionMono in fadeMotionList)
|
||||
{
|
||||
var fadeMotionObj = fadeMotionMono.ToType();
|
||||
if (fadeMotionObj == null)
|
||||
{
|
||||
var m_Type = fadeMotionMono.ConvertToTypeTree(assemblyLoader);
|
||||
fadeMotionObj = fadeMotionMono.ToType(m_Type);
|
||||
if (fadeMotionObj == null)
|
||||
{
|
||||
Logger.Warning($"Fade motion \"{fadeMotionMono.m_Name}\" is not readable.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var fadeMotion = JsonConvert.DeserializeObject<CubismFadeMotion>(JsonConvert.SerializeObject(fadeMotionObj));
|
||||
if (fadeMotion.ParameterIds.Length == 0)
|
||||
continue;
|
||||
|
||||
var motionJson = new CubismMotion3Json(fadeMotion, parameterNames, partNames, forceBezier);
|
||||
|
||||
var animName = Path.GetFileNameWithoutExtension(fadeMotion.m_Name);
|
||||
if (motions.ContainsKey(animName))
|
||||
{
|
||||
animName = $"{animName}_{fadeMotion.GetHashCode()}";
|
||||
|
||||
if (motions.ContainsKey(animName))
|
||||
continue;
|
||||
}
|
||||
var motionPath = new JObject(new JProperty("File", $"motions/{animName}.motion3.json"));
|
||||
motions.Add(animName, new JArray(motionPath));
|
||||
File.WriteAllText($"{destMotionPath}{animName}.motion3.json", JsonConvert.SerializeObject(motionJson, Formatting.Indented, new MyJsonConverter()));
|
||||
}
|
||||
}
|
||||
else if (gameObjects.Count > 0) //motion from AnimationClip
|
||||
{
|
||||
var exportMethod = motionMode == Live2DMotionMode.AnimationClip
|
||||
? "AnimationClip"
|
||||
: "AnimationClip (no Fade motions found)";
|
||||
Logger.Debug($"Motion export method: {exportMethod}");
|
||||
var rootTransform = gameObjects[0].m_Transform;
|
||||
while (rootTransform.m_Father.TryGet(out var m_Father))
|
||||
{
|
||||
@ -114,114 +181,37 @@ namespace CubismLive2DExtractor
|
||||
{
|
||||
Directory.CreateDirectory(destMotionPath);
|
||||
}
|
||||
foreach (ImportedKeyframedAnimation animation in converter.AnimationList)
|
||||
foreach (var animation in converter.AnimationList)
|
||||
{
|
||||
var json = new CubismMotion3Json
|
||||
{
|
||||
Version = 3,
|
||||
Meta = new CubismMotion3Json.SerializableMeta
|
||||
{
|
||||
Duration = animation.Duration,
|
||||
Fps = animation.SampleRate,
|
||||
Loop = true,
|
||||
AreBeziersRestricted = true,
|
||||
CurveCount = animation.TrackList.Count,
|
||||
UserDataCount = animation.Events.Count
|
||||
},
|
||||
Curves = new CubismMotion3Json.SerializableCurve[animation.TrackList.Count]
|
||||
};
|
||||
int totalSegmentCount = 1;
|
||||
int totalPointCount = 1;
|
||||
for (int i = 0; i < animation.TrackList.Count; i++)
|
||||
{
|
||||
var track = animation.TrackList[i];
|
||||
json.Curves[i] = new CubismMotion3Json.SerializableCurve
|
||||
{
|
||||
Target = track.Target,
|
||||
Id = track.Name,
|
||||
Segments = new List<float> { 0f, track.Curve[0].value }
|
||||
};
|
||||
for (var j = 1; j < track.Curve.Count; j++)
|
||||
{
|
||||
var curve = track.Curve[j];
|
||||
var preCurve = track.Curve[j - 1];
|
||||
if (Math.Abs(curve.time - preCurve.time - 0.01f) < 0.0001f) //InverseSteppedSegment
|
||||
{
|
||||
var nextCurve = track.Curve[j + 1];
|
||||
if (nextCurve.value == curve.value)
|
||||
{
|
||||
json.Curves[i].Segments.Add(3f);
|
||||
json.Curves[i].Segments.Add(nextCurve.time);
|
||||
json.Curves[i].Segments.Add(nextCurve.value);
|
||||
j += 1;
|
||||
totalPointCount += 1;
|
||||
totalSegmentCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (float.IsPositiveInfinity(curve.inSlope)) //SteppedSegment
|
||||
{
|
||||
json.Curves[i].Segments.Add(2f);
|
||||
json.Curves[i].Segments.Add(curve.time);
|
||||
json.Curves[i].Segments.Add(curve.value);
|
||||
totalPointCount += 1;
|
||||
}
|
||||
else if (preCurve.outSlope == 0f && Math.Abs(curve.inSlope) < 0.0001f) //LinearSegment
|
||||
{
|
||||
json.Curves[i].Segments.Add(0f);
|
||||
json.Curves[i].Segments.Add(curve.time);
|
||||
json.Curves[i].Segments.Add(curve.value);
|
||||
totalPointCount += 1;
|
||||
}
|
||||
else //BezierSegment
|
||||
{
|
||||
var tangentLength = (curve.time - preCurve.time) / 3f;
|
||||
json.Curves[i].Segments.Add(1f);
|
||||
json.Curves[i].Segments.Add(preCurve.time + tangentLength);
|
||||
json.Curves[i].Segments.Add(preCurve.outSlope * tangentLength + preCurve.value);
|
||||
json.Curves[i].Segments.Add(curve.time - tangentLength);
|
||||
json.Curves[i].Segments.Add(curve.value - curve.inSlope * tangentLength);
|
||||
json.Curves[i].Segments.Add(curve.time);
|
||||
json.Curves[i].Segments.Add(curve.value);
|
||||
totalPointCount += 3;
|
||||
}
|
||||
totalSegmentCount++;
|
||||
}
|
||||
}
|
||||
json.Meta.TotalSegmentCount = totalSegmentCount;
|
||||
json.Meta.TotalPointCount = totalPointCount;
|
||||
var motionJson = new CubismMotion3Json(animation, forceBezier);
|
||||
|
||||
json.UserData = new CubismMotion3Json.SerializableUserData[animation.Events.Count];
|
||||
var totalUserDataSize = 0;
|
||||
for (var i = 0; i < animation.Events.Count; i++)
|
||||
var animName = animation.Name;
|
||||
if (motions.ContainsKey(animName))
|
||||
{
|
||||
var @event = animation.Events[i];
|
||||
json.UserData[i] = new CubismMotion3Json.SerializableUserData
|
||||
{
|
||||
Time = @event.time,
|
||||
Value = @event.value
|
||||
};
|
||||
totalUserDataSize += @event.value.Length;
|
||||
animName = $"{animName}_{animation.GetHashCode()}";
|
||||
|
||||
if (motions.ContainsKey(animName))
|
||||
continue;
|
||||
}
|
||||
json.Meta.TotalUserDataSize = totalUserDataSize;
|
||||
|
||||
var motionPath = new JObject(new JProperty("File", $"motions/{animation.Name}.motion3.json"));
|
||||
motions.Add(animation.Name, new JArray(motionPath));
|
||||
File.WriteAllText($"{destMotionPath}{animation.Name}.motion3.json", JsonConvert.SerializeObject(json, Formatting.Indented, new MyJsonConverter()));
|
||||
var motionPath = new JObject(new JProperty("File", $"motions/{animName}.motion3.json"));
|
||||
motions.Add(animName, new JArray(motionPath));
|
||||
File.WriteAllText($"{destMotionPath}{animName}.motion3.json", JsonConvert.SerializeObject(motionJson, Formatting.Indented, new MyJsonConverter()));
|
||||
}
|
||||
}
|
||||
if (motions.Count == 0)
|
||||
{
|
||||
Logger.Warning($"No motions found for \"{modelName}\" model.");
|
||||
}
|
||||
|
||||
//expression
|
||||
var expressions = new JArray();
|
||||
var monoBehaviourArray = monoBehaviours.Where(x => x.m_Name.EndsWith(".exp3")).ToArray();
|
||||
if (monoBehaviourArray.Length > 0)
|
||||
if (expressionList.Count > 0)
|
||||
{
|
||||
Directory.CreateDirectory(destExpressionPath);
|
||||
}
|
||||
foreach (var monoBehaviour in monoBehaviourArray)
|
||||
foreach (var monoBehaviour in expressionList)
|
||||
{
|
||||
var fullName = monoBehaviour.m_Name;
|
||||
var expressionName = fullName.Replace(".exp3", "");
|
||||
var expressionName = monoBehaviour.m_Name.Replace(".exp3", "");
|
||||
var expressionObj = monoBehaviour.ToType();
|
||||
if (expressionObj == null)
|
||||
{
|
||||
@ -238,57 +228,38 @@ namespace CubismLive2DExtractor
|
||||
expressions.Add(new JObject
|
||||
{
|
||||
{ "Name", expressionName },
|
||||
{ "File", $"expressions/{fullName}.json" }
|
||||
{ "File", $"expressions/{expressionName}.exp3.json" }
|
||||
});
|
||||
File.WriteAllText($"{destExpressionPath}{fullName}.json", JsonConvert.SerializeObject(expression, Formatting.Indented));
|
||||
File.WriteAllText($"{destExpressionPath}{expressionName}.exp3.json", JsonConvert.SerializeObject(expression, Formatting.Indented));
|
||||
}
|
||||
|
||||
//model
|
||||
//group
|
||||
var groups = new List<CubismModel3Json.SerializableGroup>();
|
||||
|
||||
var eyeBlinkParameters = monoBehaviours.Where(x =>
|
||||
{
|
||||
x.m_Script.TryGet(out var m_Script);
|
||||
return m_Script?.m_ClassName == "CubismEyeBlinkParameter";
|
||||
}).Select(x =>
|
||||
{
|
||||
x.m_GameObject.TryGet(out var m_GameObject);
|
||||
return m_GameObject?.m_Name;
|
||||
}).ToHashSet();
|
||||
//Try looking for group IDs among the gameObjects
|
||||
if (eyeBlinkParameters.Count == 0)
|
||||
{
|
||||
eyeBlinkParameters = gameObjects.Where(x =>
|
||||
{
|
||||
return x.m_Name.ToLower().Contains("eye")
|
||||
x.m_Name.ToLower().Contains("eye")
|
||||
&& x.m_Name.ToLower().Contains("open")
|
||||
&& (x.m_Name.ToLower().Contains('l') || x.m_Name.ToLower().Contains('r'));
|
||||
}).Select(x => x.m_Name).ToHashSet();
|
||||
&& (x.m_Name.ToLower().Contains('l') || x.m_Name.ToLower().Contains('r'))
|
||||
).Select(x => x.m_Name).ToHashSet();
|
||||
}
|
||||
if (lipSyncParameters.Count == 0)
|
||||
{
|
||||
lipSyncParameters = gameObjects.Where(x =>
|
||||
x.m_Name.ToLower().Contains("mouth")
|
||||
&& x.m_Name.ToLower().Contains("open")
|
||||
&& x.m_Name.ToLower().Contains('y')
|
||||
).Select(x => x.m_Name).ToHashSet();
|
||||
}
|
||||
|
||||
groups.Add(new CubismModel3Json.SerializableGroup
|
||||
{
|
||||
Target = "Parameter",
|
||||
Name = "EyeBlink",
|
||||
Ids = eyeBlinkParameters.ToArray()
|
||||
});
|
||||
|
||||
var lipSyncParameters = monoBehaviours.Where(x =>
|
||||
{
|
||||
x.m_Script.TryGet(out var m_Script);
|
||||
return m_Script?.m_ClassName == "CubismMouthParameter";
|
||||
}).Select(x =>
|
||||
{
|
||||
x.m_GameObject.TryGet(out var m_GameObject);
|
||||
return m_GameObject?.m_Name;
|
||||
}).ToHashSet();
|
||||
if (lipSyncParameters.Count == 0)
|
||||
{
|
||||
lipSyncParameters = gameObjects.Where(x =>
|
||||
{
|
||||
return x.m_Name.ToLower().Contains("mouth")
|
||||
&& x.m_Name.ToLower().Contains("open")
|
||||
&& x.m_Name.ToLower().Contains('y');
|
||||
}).Select(x => x.m_Name).ToHashSet();
|
||||
}
|
||||
groups.Add(new CubismModel3Json.SerializableGroup
|
||||
{
|
||||
Target = "Parameter",
|
||||
@ -296,6 +267,7 @@ namespace CubismLive2DExtractor
|
||||
Ids = lipSyncParameters.ToArray()
|
||||
});
|
||||
|
||||
//model
|
||||
var model3 = new CubismModel3Json
|
||||
{
|
||||
Version = 3,
|
||||
|
@ -0,0 +1,8 @@
|
||||
namespace CubismLive2DExtractor
|
||||
{
|
||||
public enum Live2DMotionMode
|
||||
{
|
||||
MonoBehaviour,
|
||||
AnimationClip
|
||||
}
|
||||
}
|
@ -154,9 +154,16 @@ namespace AssetStudio
|
||||
if (triangles.Length < 1024)
|
||||
{
|
||||
var rectP = new RectangularPolygon(0, 0, rect.Width, rect.Height);
|
||||
spriteImage.Mutate(x => x.Fill(options, SixLabors.ImageSharp.Color.Red, rectP.Clip(path)));
|
||||
spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
|
||||
return spriteImage;
|
||||
try
|
||||
{
|
||||
spriteImage.Mutate(x => x.Fill(options, SixLabors.ImageSharp.Color.Red, rectP.Clip(path)));
|
||||
spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
|
||||
return spriteImage;
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
using (var mask = new Image<Bgra32>(rect.Width, rect.Height, SixLabors.ImageSharp.Color.Black))
|
||||
{
|
||||
@ -167,9 +174,9 @@ namespace AssetStudio
|
||||
return spriteImage;
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
// ignored
|
||||
Logger.Warning($"{m_Sprite.m_Name} Unable to render the packed sprite correctly.\n{e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,9 @@
|
||||
- ArknightsStudio-net7
|
||||
- GUI/CLI (Windows) - [.NET Desktop Runtime 7.0](https://dotnet.microsoft.com/download/dotnet/7.0)
|
||||
- CLI (Linux/Mac) - [.NET Runtime 7.0](https://dotnet.microsoft.com/download/dotnet/7.0)
|
||||
- ArknightsStudio-net8
|
||||
- GUI/CLI (Windows) - [.NET Desktop Runtime 7.0](https://dotnet.microsoft.com/download/dotnet/8.0)
|
||||
- CLI (Linux/Mac) - [.NET Runtime 7.0](https://dotnet.microsoft.com/download/dotnet/8.0)
|
||||
|
||||
## CLI Usage
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user