Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d07fc6d6f5 | ||
|
|
ee2976aaf1 | ||
|
|
f144037bc0 | ||
|
|
0e097bda04 | ||
|
|
9686eee3b7 | ||
|
|
b6318e6d9b |
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>1.1.0</Version>
|
||||
<Version>1.2.0</Version>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -2,19 +2,18 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
|
||||
<Version>1.2.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2025</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
|
||||
<PackageReference Include="System.Memory" Version="4.5.4" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.0.0" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.1.11" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace AssetStudio
|
||||
Lzma,
|
||||
Lz4,
|
||||
Lz4HC,
|
||||
Lzham
|
||||
Lz4Inv,
|
||||
}
|
||||
|
||||
public class BundleFile
|
||||
@@ -378,20 +378,31 @@ namespace AssetStudio
|
||||
}
|
||||
case CompressionType.Lz4:
|
||||
case CompressionType.Lz4HC:
|
||||
case CompressionType.Lz4Inv:
|
||||
{
|
||||
var compressedSize = (int)blockInfo.compressedSize;
|
||||
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
|
||||
reader.Read(compressedBytes, 0, compressedSize);
|
||||
_ = reader.Read(compressedBytes, 0, compressedSize);
|
||||
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
||||
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
|
||||
var numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
|
||||
if (numWrite != uncompressedSize)
|
||||
try
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
var compressedSpan = compressedBytes.AsSpan(0, compressedSize);
|
||||
var uncompressedSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
||||
var numWrite = compressionType == CompressionType.Lz4Inv
|
||||
? LZ4Inv.Instance.Decompress(compressedSpan, uncompressedSpan)
|
||||
: LZ4Codec.Decode(compressedSpan, uncompressedSpan);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
}
|
||||
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BigArrayPool<byte>.Shared.Return(compressedBytes);
|
||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
||||
}
|
||||
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
||||
BigArrayPool<byte>.Shared.Return(compressedBytes);
|
||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
75
AssetStudio/LZ4/LZ4.cs
Normal file
75
AssetStudio/LZ4/LZ4.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class LZ4
|
||||
{
|
||||
public static LZ4 Instance => new LZ4();
|
||||
|
||||
public virtual int Decompress(ReadOnlySpan<byte> cmp, Span<byte> dec)
|
||||
{
|
||||
int cmpPos = 0;
|
||||
int decPos = 0;
|
||||
|
||||
do
|
||||
{
|
||||
var (encCount, litCount) = GetLiteralToken(cmp, ref cmpPos);
|
||||
|
||||
//Copy literal chunk
|
||||
litCount = GetLength(litCount, cmp, ref cmpPos);
|
||||
|
||||
cmp.Slice(cmpPos, litCount).CopyTo(dec.Slice(decPos));
|
||||
|
||||
cmpPos += litCount;
|
||||
decPos += litCount;
|
||||
|
||||
if (cmpPos >= cmp.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//Copy compressed chunk
|
||||
int back = GetChunkEnd(cmp, ref cmpPos);
|
||||
|
||||
encCount = GetLength(encCount, cmp, ref cmpPos) + 4;
|
||||
|
||||
int encPos = decPos - back;
|
||||
|
||||
if (encCount <= back)
|
||||
{
|
||||
dec.Slice(encPos, encCount).CopyTo(dec.Slice(decPos));
|
||||
decPos += encCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (encCount-- > 0)
|
||||
{
|
||||
dec[decPos++] = dec[encPos++];
|
||||
}
|
||||
}
|
||||
} while (cmpPos < cmp.Length && decPos < dec.Length);
|
||||
|
||||
return decPos;
|
||||
}
|
||||
|
||||
protected virtual (int encCount, int litCount) GetLiteralToken(ReadOnlySpan<byte> cmp, ref int cmpPos) =>
|
||||
((cmp[cmpPos] >> 0) & 0xf, (cmp[cmpPos++] >> 4) & 0xf);
|
||||
|
||||
protected virtual int GetChunkEnd(ReadOnlySpan<byte> cmp, ref int cmpPos) =>
|
||||
cmp[cmpPos++] << 0 | cmp[cmpPos++] << 8;
|
||||
|
||||
protected virtual int GetLength(int length, ReadOnlySpan<byte> cmp, ref int cmpPos)
|
||||
{
|
||||
byte sum;
|
||||
|
||||
if (length == 0xf)
|
||||
{
|
||||
do
|
||||
{
|
||||
length += sum = cmp[cmpPos++];
|
||||
} while (sum == 0xff);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
AssetStudio/LZ4/LZ4Inv.cs
Normal file
15
AssetStudio/LZ4/LZ4Inv.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class LZ4Inv : LZ4
|
||||
{
|
||||
public new static LZ4Inv Instance => new LZ4Inv();
|
||||
|
||||
protected override (int encCount, int litCount) GetLiteralToken(ReadOnlySpan<byte> cmp, ref int cmpPos) =>
|
||||
((cmp[cmpPos] >> 4) & 0xf, (cmp[cmpPos++] >> 0) & 0xf);
|
||||
|
||||
protected override int GetChunkEnd(ReadOnlySpan<byte> cmp, ref int cmpPos) =>
|
||||
cmp[cmpPos++] << 8 | cmp[cmpPos++] << 0;
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
<TargetFrameworks>net472;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<AssemblyTitle>ArknightsStudio by aelurum</AssemblyTitle>
|
||||
<AssemblyName>ArknightsStudioCLI</AssemblyName>
|
||||
<Version>1.1.0</Version>
|
||||
<Copyright>Copyright © Perfare; Copyright © aelurum 2023</Copyright>
|
||||
<Version>1.2.0</Version>
|
||||
<Copyright>Copyright © Perfare; Copyright © aelurum 2025</Copyright>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -4,6 +4,7 @@ using AssetStudioCLI;
|
||||
using SixLabors.ImageSharp;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Arknights
|
||||
@@ -43,17 +44,39 @@ namespace Arknights
|
||||
private bool TryGetSpriteHub(AssetItem assetItem, out AvgSpriteConfig spriteHubData)
|
||||
{
|
||||
spriteHubData = null;
|
||||
var avgSpriteHubItem = Studio.loadedAssetsList.Find(x =>
|
||||
var scriptAssets = Studio.loadedAssetsList.FindAll(x =>
|
||||
x.Type == ClassIDType.MonoBehaviour
|
||||
&& x.Container == assetItem.Container
|
||||
&& x.Text.IndexOf("AVGCharacterSpriteHub", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
);
|
||||
if (avgSpriteHubItem == null)
|
||||
&& x.Container == assetItem.Container);
|
||||
if (scriptAssets.Count == 0)
|
||||
{
|
||||
Logger.Warning("AVGCharacterSpriteHub was not found.");
|
||||
Logger.Warning("No MonoBehaviours were found.");
|
||||
return false;
|
||||
}
|
||||
var spriteHubDict = ((MonoBehaviour)avgSpriteHubItem.Asset).ToType();
|
||||
|
||||
OrderedDictionary spriteHubDict = null;
|
||||
var isGrouped = false;
|
||||
foreach (var scriptAsset in scriptAssets)
|
||||
{
|
||||
var scriptAssetDict = ((MonoBehaviour)scriptAsset.Asset).ToType();
|
||||
if (scriptAssetDict == null)
|
||||
{
|
||||
Logger.Warning("MonoBehaviour is not readable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scriptAssetDict.Contains("spriteGroups"))
|
||||
{
|
||||
spriteHubDict = scriptAssetDict;
|
||||
isGrouped = true;
|
||||
break;
|
||||
}
|
||||
if (scriptAssetDict.Contains("sprites"))
|
||||
{
|
||||
spriteHubDict = scriptAssetDict;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (spriteHubDict == null)
|
||||
{
|
||||
Logger.Warning("AVGCharacterSpriteHub is not readable.");
|
||||
@@ -61,7 +84,7 @@ namespace Arknights
|
||||
}
|
||||
|
||||
var spriteHubJson = JsonConvert.SerializeObject(spriteHubDict);
|
||||
if (avgSpriteHubItem.Text.ToLower().Contains("hubgroup"))
|
||||
if (isGrouped)
|
||||
{
|
||||
var groupedSpriteHub = JsonConvert.DeserializeObject<AvgSpriteConfigGroup>(spriteHubJson);
|
||||
spriteHubData = GetCurSpriteGroup(groupedSpriteHub, assetItem.m_PathID, assetItem.Text);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>1.1.0</Version>
|
||||
<Version>1.2.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
|
||||
<AssemblyTitle>ArknightsStudio by aelurum</AssemblyTitle>
|
||||
<AssemblyName>ArknightsStudioGUI</AssemblyName>
|
||||
<Version>1.1.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2021-2023</Copyright>
|
||||
<Version>1.2.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2021-2025</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -57,14 +57,19 @@ namespace Arknights
|
||||
{
|
||||
var faceImage = m_Texture2D.ConvertToImage(true);
|
||||
var faceAlpha = avgSprite.FaceSpriteAlphaTexture.ConvertToImage(true);
|
||||
|
||||
tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
var facePos = tex.Width == 512 ? avgSprite.FacePos / 2 : avgSprite.FacePos; // ?
|
||||
var faceSize = tex.Width == 512 ? avgSprite.FaceSize / 2 : 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 }));
|
||||
faceImage.Mutate(x => x.Resize(new ResizeOptions { Size = faceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
faceAlpha.Mutate(x => x.Resize(new ResizeOptions { Size = faceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
}
|
||||
tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
tex.Mutate(x => x.DrawImage(faceImage, avgSprite.FacePos, opacity: 1f));
|
||||
alphaTex.Mutate(x => x.DrawImage(faceAlpha, avgSprite.FacePos, opacity: 1f));
|
||||
|
||||
tex.Mutate(x => x.DrawImage(faceImage, facePos, opacity: 1f));
|
||||
alphaTex.Mutate(x => x.DrawImage(faceAlpha, facePos, opacity: 1f));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using AssetStudioGUI;
|
||||
using SixLabors.ImageSharp;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Arknights
|
||||
@@ -43,17 +44,39 @@ namespace Arknights
|
||||
private bool TryGetSpriteHub(AssetItem assetItem, out AvgSpriteConfig spriteHubData)
|
||||
{
|
||||
spriteHubData = null;
|
||||
var avgSpriteHubItem = Studio.exportableAssets.Find(x =>
|
||||
var scriptAssets = Studio.exportableAssets.FindAll(x =>
|
||||
x.Type == ClassIDType.MonoBehaviour
|
||||
&& x.Container == assetItem.Container
|
||||
&& x.Text.IndexOf("AVGCharacterSpriteHub", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
);
|
||||
if (avgSpriteHubItem == null)
|
||||
&& x.Container == assetItem.Container);
|
||||
if (scriptAssets.Count == 0)
|
||||
{
|
||||
Logger.Warning("AVGCharacterSpriteHub was not found.");
|
||||
Logger.Warning("No MonoBehaviours were found.");
|
||||
return false;
|
||||
}
|
||||
var spriteHubDict = ((MonoBehaviour)avgSpriteHubItem.Asset).ToType();
|
||||
|
||||
OrderedDictionary spriteHubDict = null;
|
||||
var isGrouped = false;
|
||||
foreach (var scriptAsset in scriptAssets)
|
||||
{
|
||||
var scriptAssetDict = ((MonoBehaviour)scriptAsset.Asset).ToType();
|
||||
if (scriptAssetDict == null)
|
||||
{
|
||||
Logger.Warning("MonoBehaviour is not readable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scriptAssetDict.Contains("spriteGroups"))
|
||||
{
|
||||
spriteHubDict = scriptAssetDict;
|
||||
isGrouped = true;
|
||||
break;
|
||||
}
|
||||
if (scriptAssetDict.Contains("sprites"))
|
||||
{
|
||||
spriteHubDict = scriptAssetDict;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (spriteHubDict == null)
|
||||
{
|
||||
Logger.Warning("AVGCharacterSpriteHub is not readable.");
|
||||
@@ -61,7 +84,7 @@ namespace Arknights
|
||||
}
|
||||
|
||||
var spriteHubJson = JsonConvert.SerializeObject(spriteHubDict);
|
||||
if (avgSpriteHubItem.Text.ToLower().Contains("hubgroup"))
|
||||
if (isGrouped)
|
||||
{
|
||||
var groupedSpriteHub = JsonConvert.DeserializeObject<AvgSpriteConfigGroup>(spriteHubJson);
|
||||
spriteHubData = GetCurSpriteGroup(groupedSpriteHub, assetItem.m_PathID, assetItem.Text);
|
||||
@@ -118,7 +141,7 @@ namespace Arknights
|
||||
}
|
||||
else
|
||||
{
|
||||
FullAlphaTexture = (Texture2D)Studio.exportableAssets.Find(x => x.m_PathID == curSpriteData.AlphaTex.m_PathID).Asset;
|
||||
FullAlphaTexture = (Texture2D)Studio.exportableAssets.Find(x => x.m_PathID == curSpriteData.AlphaTex.m_PathID)?.Asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
|
||||
<Version>1.2.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2025</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# ArknightsStudio
|
||||
|
||||
[](https://ci.appveyor.com/project/aelurum/arknightsstudio)
|
||||
[](https://github.com/aelurum/AssetStudio/tags) [](https://github.com/aelurum/AssetStudio/tags)
|
||||
|
||||
[](https://ci.appveyor.com/project/aelurum/arknightsstudio) [](https://ci.appveyor.com/project/aelurum/arknightsstudio/build/artifacts)
|
||||
|
||||
|
||||
**ArknightsStudio** is a modified version of AssetStudio designed for Arknights. Based on [AssetStudioMod](https://github.com/aelurum/AssetStudio).
|
||||
|
||||
@@ -26,8 +29,8 @@
|
||||
- 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)
|
||||
- GUI/CLI (Windows) - [.NET Desktop Runtime 8.0](https://dotnet.microsoft.com/download/dotnet/8.0)
|
||||
- CLI (Linux/Mac) - [.NET Runtime 8.0](https://dotnet.microsoft.com/download/dotnet/8.0)
|
||||
|
||||
## CLI Usage
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>1.1.0</Version>
|
||||
<Version>1.2.0</Version>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
Reference in New Issue
Block a user