Compare commits

..

51 Commits

Author SHA1 Message Date
Perfare ab98585b6a Fix Shader reading. Close #720 2021-05-29 05:11:05 +08:00
Perfare 075d53a455 small improvement 2021-05-28 23:19:31 +08:00
Perfare 432116d834 Improve SerializedFile reading. 2021-05-28 22:23:07 +08:00
Perfare caa45216ef fix compilation error 2021-05-28 22:16:50 +08:00
Perfare c9394cd957 Fixed #734 2021-05-28 03:49:46 +08:00
Perfare 46c0e8ffe1 Improve stream file processing 2021-05-28 03:43:32 +08:00
Perfare d14c232015 Improve the error message 2021-05-28 03:27:50 +08:00
Perfare 4002bdecb8 Update README.md 2021-05-27 03:55:37 +08:00
StarHeart 17259e00c7 correct grammar (#749) 2021-05-27 03:49:40 +08:00
Perfare 44b02b92d8 fix lzma decompression 2021-05-27 03:46:15 +08:00
Joshua May 251854cc41 Adds exporter for list of assets to XML (#710) 2021-04-18 01:27:15 +08:00
Perfare 6f7b77245d Merge pull request #639 from sk-zk/nul-fix
[GUI] Fix \0 chars in TextAssets cutting off preview
2021-04-18 01:21:16 +08:00
Perfare 6d99f5ebf6 Improve vertex format parsing. Close #689 2021-04-12 15:11:17 +08:00
Perfare f1f2430f97 Support 2021.1 2021-04-11 23:49:44 +08:00
Perfare b52696c965 Merge pull request #713 from K0lb3/patch-1
Update ClassIDType according to official reference
2021-04-11 21:54:45 +08:00
K0lb3 5fba52dc83 Update ClassIDType according to official reference
I noticed that Unity has made a [ClassID Reference table](https://docs.unity3d.com/Manual/ClassIDReference.html) and thought that copying it over here might be useful for dumps.
2021-03-28 14:24:20 -07:00
Perfare dfb74baf79 Fix for mesh weights output 2021-01-15 09:32:57 +08:00
Perfare 978e90a403 Fix if AudioClip does not contain subsound. Close #672 2021-01-15 05:39:45 +08:00
Perfare c17d7d6331 Update README.md 2021-01-15 04:38:54 +08:00
Perfare 9fef18d6ea fixes bug 2021-01-15 04:33:54 +08:00
Perfare ee0cd4ab52 Fixed #609 2021-01-15 03:43:52 +08:00
Perfare f904bc138b typo 2021-01-15 02:17:11 +08:00
Perfare 7ed5345b1b Fixed #652 2021-01-15 02:12:54 +08:00
Perfare d7f652d572 improved Sprite export 2021-01-14 19:27:57 +08:00
Perfare 32ce032655 Support 2020.2 2021-01-14 05:23:19 +08:00
Perfare e1cf36aa3c Fixed #650 2020-12-14 21:20:04 +08:00
sk-zk f644396a15 Fix \0 chars in TextAssets cutting off preview 2020-10-30 23:08:06 +01:00
Perfare 3e77c34bd5 Fixed #618 2020-09-29 07:08:14 +08:00
Perfare 052c60f629 Fix file occupation conflict 2020-09-26 23:29:38 +08:00
Perfare a1f2e3e7fe Merge pull request #613 from Ishotihadus/master
Problems in exporting fbx with multiple blendshapes
2020-09-26 10:18:42 -05:00
Ishotihadus 32ee8b326f fix problems in exporting fbx with multiple blendshapes 2020-09-16 19:44:11 +09:00
Perfare 06ce479eb6 Fixes #591 2020-08-26 09:50:25 +08:00
Perfare 03f74bac64 Fix BlendShape output error 2020-08-24 22:00:53 +08:00
Perfare 344b675745 Update README.md 2020-08-16 18:53:55 +08:00
Perfare 86590d95a5 Add dump viewer 2020-08-14 17:38:43 +08:00
Perfare bbea1341b2 Update README.md 2020-08-14 15:50:45 +08:00
Perfare ca60dd9834 Support exporting MonoBehaviour to json. Close #477 2020-08-14 15:45:48 +08:00
Perfare 7aa35b5b8c Fix get class from divided UnityEngine.dll 2020-08-14 01:31:49 +08:00
Perfare bd2decdb8f Fix element alignment errors 2020-08-14 01:18:43 +08:00
Perfare 9b2c85bcae Refactor MonoBehaviour reading 2020-08-14 00:02:59 +08:00
Perfare efbab7c43a using Nuget 2020-08-12 22:22:04 +08:00
Perfare 729a8a8263 implemented SPIR-V shader export 2020-08-12 22:11:26 +08:00
Perfare 0ec29f62ca Improve shader conversion, fixes #589 2020-08-12 20:49:36 +08:00
Perfare 796317f9d9 support 2020.1 2020-08-12 19:13:10 +08:00
Perfare 7596dcc7cd keep path when extracting folder 2020-08-12 02:55:02 +08:00
Perfare 422851cdab Fix mesh index errors 2020-08-12 02:24:08 +08:00
Perfare ec0a2a47f1 can choose the directory to save the extracted files 2020-08-10 14:07:29 +08:00
Perfare 8ce5b947f6 Update README.md 2020-08-10 11:01:37 +08:00
Perfare 419ca63f9d Set Runtime Library to /MT 2020-08-10 09:52:09 +08:00
Perfare 6fdb0c7b0e add ResourceManager 2020-08-06 23:17:44 +08:00
Perfare 4e97b4b898 improve export 2020-08-06 21:07:37 +08:00
92 changed files with 9370 additions and 1502 deletions
+2 -1
View File
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
@@ -26,7 +27,7 @@ namespace AssetStudio.PInvoke
private static string GetDirectedDllDirectory()
{
var localPath = new Uri(typeof(DllLoader).Assembly.CodeBase).LocalPath;
var localPath = Process.GetCurrentProcess().MainModule.FileName;
var localDir = Path.GetDirectoryName(localPath);
var subDir = Environment.Is64BitProcess ? "x64" : "x86";
+3 -8
View File
@@ -33,13 +33,6 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="7zip\Common\CommandLineParser.cs" />
@@ -103,6 +96,7 @@
<Compile Include="Classes\PPtr.cs" />
<Compile Include="Classes\RectTransform.cs" />
<Compile Include="Classes\Renderer.cs" />
<Compile Include="Classes\ResourceManager.cs" />
<Compile Include="Classes\RuntimeAnimatorController.cs" />
<Compile Include="Classes\Shader.cs" />
<Compile Include="Classes\SkinnedMeshRenderer.cs" />
@@ -141,13 +135,14 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ResourceReader.cs" />
<Compile Include="SerializedFile.cs" />
<Compile Include="SerializedFileFormatVersion.cs" />
<Compile Include="SerializedFileHeader.cs" />
<Compile Include="SerializedType.cs" />
<Compile Include="SevenZipHelper.cs" />
<Compile Include="StreamFile.cs" />
<Compile Include="TypeTree.cs" />
<Compile Include="TypeTreeHelper.cs" />
<Compile Include="TypeTreeNode.cs" />
<Compile Include="UType.cs" />
<Compile Include="WebFile.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+20 -16
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static AssetStudio.ImportHelper;
namespace AssetStudio
@@ -86,7 +87,7 @@ namespace AssetStudio
foreach (var sharedFile in assetsFile.m_Externals)
{
var sharedFilePath = Path.GetDirectoryName(fullName) + "\\" + sharedFile.fileName;
var sharedFilePath = Path.Combine(Path.GetDirectoryName(fullName), sharedFile.fileName);
var sharedFileName = sharedFile.fileName;
if (!importFilesHash.Contains(sharedFileName))
@@ -108,10 +109,10 @@ namespace AssetStudio
}
}
}
catch
catch (Exception e)
{
Logger.Error($"Error while reading assets file {fileName}", e);
reader.Dispose();
//Logger.Warning($"Unable to load assets file {fileName}");
}
}
else
@@ -129,16 +130,16 @@ namespace AssetStudio
{
var assetsFile = new SerializedFile(this, fullName, reader);
assetsFile.originalPath = originalPath;
if (assetsFile.header.m_Version < 7)
if (assetsFile.header.m_Version < SerializedFileFormatVersion.kUnknown_7)
{
assetsFile.SetVersion(unityVersion);
}
assetsFileList.Add(assetsFile);
assetsFileListHash.Add(assetsFile.fileName);
}
catch
catch (Exception e)
{
//Logger.Error($"Unable to load assets file {fileName} from {Path.GetFileName(originalPath)}");
Logger.Error($"Error while reading assets file {fileName} from {Path.GetFileName(originalPath)}", e);
resourceFileReaders.Add(fileName, reader);
}
}
@@ -161,18 +162,18 @@ namespace AssetStudio
}
else
{
resourceFileReaders.Add(file.fileName, subReader);
resourceFileReaders[file.fileName] = subReader; //TODO
}
}
}
catch
catch (Exception e)
{
/*var str = $"Unable to load bundle file {fileName}";
var str = $"Error while reading bundle file {fileName}";
if (parentPath != null)
{
str += $" from {Path.GetFileName(parentPath)}";
}
Logger.Error(str);*/
Logger.Error(str, e);
}
finally
{
@@ -189,7 +190,7 @@ namespace AssetStudio
var webFile = new WebFile(reader);
foreach (var file in webFile.fileList)
{
var dummyPath = Path.GetDirectoryName(fullName) + "\\" + file.fileName;
var dummyPath = Path.Combine(Path.GetDirectoryName(fullName), file.fileName);
switch (CheckFileType(file.stream, out var fileReader))
{
case FileType.AssetsFile:
@@ -202,14 +203,14 @@ namespace AssetStudio
LoadWebFile(dummyPath, fileReader);
break;
case FileType.ResourceFile:
resourceFileReaders.Add(file.fileName, fileReader);
resourceFileReaders[file.fileName] = fileReader; //TODO
break;
}
}
}
catch
catch (Exception e)
{
//Logger.Error($"Unable to load web file {fileName}");
Logger.Error($"Error while reading web file {fileName}", e);
}
finally
{
@@ -333,6 +334,9 @@ namespace AssetStudio
case ClassIDType.VideoClip:
obj = new VideoClip(objectReader);
break;
case ClassIDType.ResourceManager:
obj = new ResourceManager(objectReader);
break;
default:
obj = new Object(objectReader);
break;
@@ -341,13 +345,13 @@ namespace AssetStudio
}
catch (Exception e)
{
/*var sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("Unable to load object")
.AppendLine($"Assets {assetsFile.fileName}")
.AppendLine($"Type {objectReader.type}")
.AppendLine($"PathID {objectInfo.m_PathID}")
.Append(e);
Logger.Error(sb.ToString());*/
Logger.Error(sb.ToString());
}
Progress.Report(++i, progressCount);
+8 -2
View File
@@ -7,7 +7,7 @@ namespace AssetStudio
{
public enum BuildTarget
{
UnknownPlatform = 3716,
NoTarget = -2,
DashboardWidget = 1,
StandaloneOSX = 2,
StandaloneOSXPPC = 3,
@@ -42,6 +42,12 @@ namespace AssetStudio
WiiU,
tvOS,
Switch,
NoTarget = -2
Lumin,
Stadia,
CloudRendering,
GameCoreXboxSeries,
GameCoreXboxOne,
PS5,
UnknownPlatform = 9999
}
}
+22 -14
View File
@@ -45,12 +45,19 @@ namespace AssetStudio
{
m_Header = new Header();
m_Header.signature = reader.ReadStringToNull();
m_Header.version = reader.ReadUInt32();
m_Header.unityVersion = reader.ReadStringToNull();
m_Header.unityRevision = reader.ReadStringToNull();
switch (m_Header.signature)
{
case "UnityArchive":
break; //TODO
case "UnityWeb":
case "UnityRaw":
if (m_Header.version == 6)
{
goto case "UnityFS";
}
ReadHeaderAndBlocksInfo(reader);
using (var blocksStream = CreateBlocksStream(path))
{
@@ -73,16 +80,13 @@ namespace AssetStudio
private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
{
var isCompressed = m_Header.signature == "UnityWeb";
m_Header.version = reader.ReadUInt32();
m_Header.unityVersion = reader.ReadStringToNull();
m_Header.unityRevision = reader.ReadStringToNull();
if (m_Header.version >= 4)
{
var hash = reader.ReadBytes(16);
var crc = reader.ReadUInt32();
}
var minimumStreamedBytes = reader.ReadUInt32();
var headerSize = reader.ReadUInt32();
m_Header.size = reader.ReadUInt32();
var numberOfLevelsToDownloadBeforeStreaming = reader.ReadUInt32();
var levelCount = reader.ReadInt32();
m_BlocksInfo = new StorageBlock[1];
@@ -107,7 +111,7 @@ namespace AssetStudio
{
var fileInfoHeaderSize = reader.ReadUInt32();
}
reader.Position = headerSize;
reader.Position = m_Header.size;
}
private Stream CreateBlocksStream(string path)
@@ -167,6 +171,7 @@ namespace AssetStudio
var node = m_DirectoryInfo[i];
var file = new StreamFile();
fileList[i] = file;
file.path = node.path;
file.fileName = Path.GetFileName(node.path);
if (node.size >= int.MaxValue)
{
@@ -174,7 +179,7 @@ namespace AssetStudio
file.stream = memoryMappedFile.CreateViewStream();*/
var extractPath = path + "_unpacked" + Path.DirectorySeparatorChar;
Directory.CreateDirectory(extractPath);
file.stream = File.Create(extractPath + file.fileName);
file.stream = new FileStream(extractPath + file.fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
}
else
{
@@ -188,18 +193,23 @@ namespace AssetStudio
private void ReadHeader(EndianBinaryReader reader)
{
m_Header.version = reader.ReadUInt32();
m_Header.unityVersion = reader.ReadStringToNull();
m_Header.unityRevision = reader.ReadStringToNull();
m_Header.size = reader.ReadInt64();
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
m_Header.uncompressedBlocksInfoSize = reader.ReadUInt32();
m_Header.flags = reader.ReadUInt32();
if (m_Header.signature != "UnityFS")
{
reader.ReadByte();
}
}
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader)
{
byte[] blocksInfoBytes;
if (m_Header.version >= 7)
{
reader.AlignStream(16);
}
if ((m_Header.flags & 0x80) != 0) //kArchiveBlocksInfoAtTheEnd
{
var position = reader.Position;
@@ -209,10 +219,6 @@ namespace AssetStudio
}
else //0x40 kArchiveBlocksAndDirectoryInfoCombined
{
if (m_Header.version >= 7)
{
reader.AlignStream(16);
}
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
}
var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes);
@@ -226,7 +232,9 @@ namespace AssetStudio
}
case 1: //LZMA
{
blocksInfoUncompresseddStream = SevenZipHelper.StreamDecompress(blocksInfoCompressedStream);
blocksInfoUncompresseddStream = new MemoryStream((int)(m_Header.uncompressedBlocksInfoSize));
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompresseddStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
blocksInfoUncompresseddStream.Position = 0;
blocksInfoCompressedStream.Close();
break;
}
+103 -10
View File
@@ -1,4 +1,5 @@
namespace AssetStudio
// official Class ID Reference: https://docs.unity3d.com/Manual/ClassIDReference.html
namespace AssetStudio
{
public enum ClassIDType
{
@@ -26,7 +27,7 @@
ParticleRenderer = 26,
Texture = 27,
Texture2D = 28,
SceneSettings = 29,
OcclusionCullingSettings = 29,
GraphicsSettings = 30,
MeshFilter = 33,
OcclusionPortal = 41,
@@ -49,7 +50,7 @@
PhysicsMaterial2D = 62,
MeshCollider = 64,
BoxCollider = 65,
SpriteCollider2D = 66,
CompositeCollider2D = 66,
EdgeCollider2D = 68,
CapsuleCollider2D = 70,
ComputeShader = 72,
@@ -92,6 +93,7 @@
FlareLayer = 124,
HaloLayer = 125,
NavMeshAreas = 126,
NavMeshProjectSettings = 126,
HaloManager = 127,
Font = 128,
PlayerSettings = 129,
@@ -158,7 +160,7 @@
BlendTree = 206,
Motion = 207,
NavMeshObstacle = 208,
TerrainInstance = 210,
SortingGroup = 210,
SpriteRenderer = 212,
Sprite = 213,
CachedSpriteAtlas = 214,
@@ -216,15 +218,19 @@
PerformanceReportingManager = 305,
UnityConnectSettings = 310,
AvatarMask = 319,
PlayableDirector = 320,
VideoPlayer = 328,
VideoClip = 329,
ParticleSystemForceField = 330,
SpriteMask = 331,
WorldAnchor = 362,
OcclusionCullingData = 363,
//kLargestRuntimeClassID = 364
SmallestEditorClassID = 1000,
Prefab = 1001,
PrefabInstance = 1001,
EditorExtensionImpl = 1002,
AssetImporter = 1003,
AssetDatabase = 1004,
AssetDatabaseV1 = 1004,
Mesh3DSImporter = 1005,
TextureImporter = 1006,
ShaderImporter = 1007,
@@ -259,13 +265,13 @@
AnimatorState = 1102,
HumanTemplate = 1105,
AnimatorStateMachine = 1107,
PreviewAssetType = 1108,
PreviewAnimationClip = 1108,
AnimatorTransition = 1109,
SpeedTreeImporter = 1110,
AnimatorTransitionBase = 1111,
SubstanceImporter = 1112,
LightmapParameters = 1113,
LightmapSnapshot = 1120,
LightingDataAsset = 1120,
GISRaster = 1121,
GISRasterImporter = 1122,
CadImporter = 1123,
@@ -276,11 +282,98 @@
ActivationLogComponent = 2000,
//kLargestEditorClassID = 2001
//kClassIdOutOfHierarchy = 100000
SubDerived = 367388927,
//int = 100000,
//bool = 100001,
//float = 100002,
MonoObject = 100003,
Collision = 100004,
Vector3f = 100005,
RootMotionData = 100006,
Collision2D = 100007,
AudioMixerLiveUpdateFloat = 100008,
AudioMixerLiveUpdateBool = 100009,
Polygon2D = 100010,
//void = 100011,
TilemapCollider2D = 19719996,
AssetImporterLog = 41386430,
VFXRenderer = 73398921,
SerializableManagedRefTestClass = 76251197,
Grid = 156049354,
ScenesUsingAssets = 156483287,
ArticulationBody = 171741748,
Preset = 181963792,
EmptyObject = 277625683,
IConstraint = 285090594,
TestObjectWithSpecialLayoutOne = 293259124,
AssemblyDefinitionReferenceImporter = 294290339,
SiblingDerived = 334799969,
TestObjectWithSerializedMapStringNonAlignedStruct = 342846651,
SubDerived = 367388927,
AssetImportInProgressProxy = 369655926,
PluginBuildInfo = 382020655,
EditorProjectAccess = 426301858,
PrefabImporter = 468431735,
TestObjectWithSerializedArray = 478637458,
TestObjectWithSerializedAnimationCurve = 478637459,
TilemapRenderer = 483693784,
ScriptableCamera = 488575907,
SpriteAtlasAsset = 612988286,
SpriteAtlasDatabase = 638013454,
AudioBuildInfo = 641289076,
CachedSpriteAtlasRuntimeData = 644342135,
RendererFake = 646504946,
AssemblyDefinitionReferenceAsset = 662584278,
BuiltAssetBundleInfoSet = 668709126,
SpriteAtlas = 687078895,
RayTracingShaderImporter = 747330370,
RayTracingShader = 825902497,
LightingSettings = 850595691,
PlatformModuleSetup = 877146078,
VersionControlSettings = 890905787,
AimConstraint = 895512359,
VFXManager = 937362698,
VisualEffectSubgraph = 994735392,
VisualEffectSubgraphOperator = 994735403,
VisualEffectSubgraphBlock = 994735404,
LocalizationImporter = 1027052791,
Derived = 1091556383,
PropertyModificationsTargetTestObject = 1111377672,
ReferencesArtifactGenerator = 1114811875,
AssemblyDefinitionAsset = 1152215463,
SceneVisibilityState = 1154873562,
LookAtConstraint = 1183024399,
SpriteAtlasImporter = 1210832254,
MultiArtifactTestImporter = 1223240404,
GameObjectRecorder = 1268269756,
LightingDataAssetParent = 1325145578,
PresetManager = 1386491679,
TestObjectWithSpecialLayoutTwo = 1392443030,
StreamingManager = 1403656975,
LowerResBlitTexture = 1480428607,
RenderPassAttachment = 1571458007
StreamingController = 1542919678,
RenderPassAttachment = 1571458007,
TestObjectVectorPairStringBool = 1628831178,
GridLayout = 1742807556,
AssemblyDefinitionImporter = 1766753193,
ParentConstraint = 1773428102,
FakeComponent = 1803986026,
PositionConstraint = 1818360608,
RotationConstraint = 1818360609,
ScaleConstraint = 1818360610,
Tilemap = 1839735485,
PackageManifest = 1896753125,
PackageManifestImporter = 1896753126,
TerrainLayer = 1953259897,
SpriteShapeRenderer = 1971053207,
NativeObjectType = 1977754360,
TestObjectWithSerializedMapStringBool = 1981279845,
SerializableManagedHost = 1995898324,
VisualEffectAsset = 2058629509,
VisualEffectImporter = 2058629510,
VisualEffectResource = 2058629511,
VisualEffectObject = 2059678085,
VisualEffect = 2083052967,
LocalizationAsset = 2083778819,
ScriptedImporter = 2089858483
}
}
+4 -3
View File
@@ -27,7 +27,7 @@ namespace AssetStudio
public AudioCompressionFormat m_CompressionFormat;
public string m_Source;
public long m_Offset;
public ulong m_Offset;
public long m_Size;
public ResourceReader m_AudioData;
@@ -48,7 +48,7 @@ namespace AssetStudio
var tsize = m_Size % 4 != 0 ? m_Size + 4 - m_Size % 4 : m_Size;
if (reader.byteSize + reader.byteStart - reader.Position != tsize)
{
m_Offset = reader.ReadInt32();
m_Offset = reader.ReadUInt32();
m_Source = assetsFile.fullName + ".resS";
}
}
@@ -72,8 +72,9 @@ namespace AssetStudio
m_Legacy3D = reader.ReadBoolean();
reader.AlignStream();
//StreamedResource m_Resource
m_Source = reader.ReadAlignedString();
m_Offset = reader.ReadInt64();
m_Offset = reader.ReadUInt64();
m_Size = reader.ReadInt64();
m_CompressionFormat = (AudioCompressionFormat)reader.ReadInt32();
}
+15
View File
@@ -19,11 +19,14 @@ namespace AssetStudio
public class UnityPropertySheet
{
public KeyValuePair<string, UnityTexEnv>[] m_TexEnvs;
public KeyValuePair<string, int>[] m_Ints;
public KeyValuePair<string, float>[] m_Floats;
public KeyValuePair<string, Color>[] m_Colors;
public UnityPropertySheet(ObjectReader reader)
{
var version = reader.version;
int m_TexEnvsSize = reader.ReadInt32();
m_TexEnvs = new KeyValuePair<string, UnityTexEnv>[m_TexEnvsSize];
for (int i = 0; i < m_TexEnvsSize; i++)
@@ -31,6 +34,16 @@ namespace AssetStudio
m_TexEnvs[i] = new KeyValuePair<string, UnityTexEnv>(reader.ReadAlignedString(), new UnityTexEnv(reader));
}
if (version[0] >= 2021) //2021.1 and up
{
int m_IntsSize = reader.ReadInt32();
m_Ints = new KeyValuePair<string, int>[m_IntsSize];
for (int i = 0; i < m_IntsSize; i++)
{
m_Ints[i] = new KeyValuePair<string, int>(reader.ReadAlignedString(), reader.ReadInt32());
}
}
int m_FloatsSize = reader.ReadInt32();
m_Floats = new KeyValuePair<string, float>[m_FloatsSize];
for (int i = 0; i < m_FloatsSize; i++)
@@ -95,6 +108,8 @@ namespace AssetStudio
}
m_SavedProperties = new UnityPropertySheet(reader);
//vector m_BuildTextureStacks 2020 and up
}
}
}
+120 -119
View File
@@ -174,7 +174,7 @@ namespace AssetStudio
GetStreams(version);
}
m_DataSize = reader.ReadBytes(reader.ReadInt32());
m_DataSize = reader.ReadUInt8Array();
reader.AlignStream();
}
@@ -195,7 +195,7 @@ namespace AssetStudio
if (m_Channel.dimension > 0)
{
chnMask |= 1u << chn;
stride += m_Channel.dimension * MeshHelper.GetFormatSize(version, m_Channel.format);
stride += m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version));
}
}
}
@@ -253,7 +253,7 @@ namespace AssetStudio
m_Channel.dimension = 4;
break;
}
offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(version, m_Channel.format));
offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version)));
}
}
}
@@ -446,7 +446,7 @@ namespace AssetStudio
public sealed class Mesh : NamedObject
{
private bool m_Use16BitIndices = true; //3.5.0 and newer always uses 16bit indices;
private bool m_Use16BitIndices = true;
public SubMesh[] m_SubMeshes;
private uint[] m_IndexBuffer;
public BlendShapeData m_Shapes;
@@ -550,6 +550,7 @@ namespace AssetStudio
((version[0] == 2017 && version[1] == 3) && m_MeshCompression == 0))//2017.3.xfx with no compression
{
var m_IndexFormat = reader.ReadInt32();
m_Use16BitIndices = m_IndexFormat == 0;
}
int m_IndexBuffer_size = reader.ReadInt32();
@@ -652,9 +653,9 @@ namespace AssetStudio
if (version[0] >= 5) //5.0 and up
{
var m_BakedConvexCollisionMesh = reader.ReadBytes(reader.ReadInt32());
var m_BakedConvexCollisionMesh = reader.ReadUInt8Array();
reader.AlignStream();
var m_BakedTriangleCollisionMesh = reader.ReadBytes(reader.ReadInt32());
var m_BakedTriangleCollisionMesh = reader.ReadUInt8Array();
reader.AlignStream();
}
@@ -710,12 +711,13 @@ namespace AssetStudio
var channelMask = new BitArray(new[] { (int)m_Stream.channelMask });
if (channelMask.Get(chn))
{
if (version[0] < 2018 && chn == 2 && m_Channel.format == 2)
if (version[0] < 2018 && chn == 2 && m_Channel.format == 2) //kShaderChannelColor && kChannelFormatColor
{
m_Channel.dimension = 4;
}
var componentByteSize = (int)MeshHelper.GetFormatSize(version, m_Channel.format);
var vertexFormat = MeshHelper.ToVertexFormat(m_Channel.format, version);
var componentByteSize = (int)MeshHelper.GetFormatSize(vertexFormat);
var componentBytes = new byte[m_VertexCount * m_Channel.dimension * componentByteSize];
for (int v = 0; v < m_VertexCount; v++)
{
@@ -740,10 +742,10 @@ namespace AssetStudio
int[] componentsIntArray = null;
float[] componentsFloatArray = null;
if (MeshHelper.IsIntFormat(version, m_Channel.format))
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, componentByteSize);
if (MeshHelper.IsIntFormat(vertexFormat))
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, vertexFormat);
else
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, componentByteSize);
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
if (version[0] >= 2018)
{
@@ -1189,7 +1191,7 @@ namespace AssetStudio
public static class MeshHelper
{
private enum VertexChannelFormat
public enum VertexChannelFormat
{
kChannelFormatFloat,
kChannelFormatFloat16,
@@ -1198,7 +1200,7 @@ namespace AssetStudio
kChannelFormatUInt32
}
private enum VertexFormat
public enum VertexFormat2017
{
kVertexFormatFloat,
kVertexFormatFloat16,
@@ -1215,7 +1217,7 @@ namespace AssetStudio
kVertexFormatSInt32
}
private enum VertexFormatV2019
public enum VertexFormat
{
kVertexFormatFloat,
kVertexFormatFloat16,
@@ -1231,147 +1233,146 @@ namespace AssetStudio
kVertexFormatSInt32
}
public static uint GetFormatSize(int[] version, int format)
public static VertexFormat ToVertexFormat(int format, int[] version)
{
if (version[0] < 2017)
{
switch ((VertexChannelFormat)format)
{
case VertexChannelFormat.kChannelFormatFloat:
return 4u;
return VertexFormat.kVertexFormatFloat;
case VertexChannelFormat.kChannelFormatFloat16:
return 2u;
return VertexFormat.kVertexFormatFloat16;
case VertexChannelFormat.kChannelFormatColor: //in 4.x is size 4
return 1u;
return VertexFormat.kVertexFormatUNorm8;
case VertexChannelFormat.kChannelFormatByte:
return 1u;
return VertexFormat.kVertexFormatUInt8;
case VertexChannelFormat.kChannelFormatUInt32: //in 5.x
return 4u;
return VertexFormat.kVertexFormatUInt32;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
else if (version[0] < 2019)
{
switch ((VertexFormat)format)
switch ((VertexFormat2017)format)
{
case VertexFormat2017.kVertexFormatFloat:
return VertexFormat.kVertexFormatFloat;
case VertexFormat2017.kVertexFormatFloat16:
return VertexFormat.kVertexFormatFloat16;
case VertexFormat2017.kVertexFormatColor:
case VertexFormat2017.kVertexFormatUNorm8:
return VertexFormat.kVertexFormatUNorm8;
case VertexFormat2017.kVertexFormatSNorm8:
return VertexFormat.kVertexFormatSNorm8;
case VertexFormat2017.kVertexFormatUNorm16:
return VertexFormat.kVertexFormatUNorm16;
case VertexFormat2017.kVertexFormatSNorm16:
return VertexFormat.kVertexFormatSNorm16;
case VertexFormat2017.kVertexFormatUInt8:
return VertexFormat.kVertexFormatUInt8;
case VertexFormat2017.kVertexFormatSInt8:
return VertexFormat.kVertexFormatSInt8;
case VertexFormat2017.kVertexFormatUInt16:
return VertexFormat.kVertexFormatUInt16;
case VertexFormat2017.kVertexFormatSInt16:
return VertexFormat.kVertexFormatSInt16;
case VertexFormat2017.kVertexFormatUInt32:
return VertexFormat.kVertexFormatUInt32;
case VertexFormat2017.kVertexFormatSInt32:
return VertexFormat.kVertexFormatSInt32;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
else
{
return (VertexFormat)format;
}
}
public static uint GetFormatSize(VertexFormat format)
{
switch (format)
{
case VertexFormat.kVertexFormatFloat:
case VertexFormat.kVertexFormatUInt32:
case VertexFormat.kVertexFormatSInt32:
return 4u;
case VertexFormat.kVertexFormatFloat16:
case VertexFormat.kVertexFormatUNorm16:
case VertexFormat.kVertexFormatSNorm16:
case VertexFormat.kVertexFormatUInt16:
case VertexFormat.kVertexFormatSInt16:
return 2u;
case VertexFormat.kVertexFormatUNorm8:
case VertexFormat.kVertexFormatSNorm8:
case VertexFormat.kVertexFormatUInt8:
case VertexFormat.kVertexFormatSInt8:
return 1u;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
public static bool IsIntFormat(VertexFormat format)
{
return format >= VertexFormat.kVertexFormatUInt8;
}
public static float[] BytesToFloatArray(byte[] inputBytes, VertexFormat format)
{
var size = GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new float[len];
for (int i = 0; i < len; i++)
{
switch (format)
{
case VertexFormat.kVertexFormatFloat:
return 4u;
result[i] = BitConverter.ToSingle(inputBytes, i * 4);
break;
case VertexFormat.kVertexFormatFloat16:
return 2u;
case VertexFormat.kVertexFormatColor:
return 1u;
result[i] = Half.ToHalf(inputBytes, i * 2);
break;
case VertexFormat.kVertexFormatUNorm8:
return 1u;
result[i] = inputBytes[i] / 255f;
break;
case VertexFormat.kVertexFormatSNorm8:
return 1u;
result[i] = Math.Max((sbyte)inputBytes[i] / 127f, -1f);
break;
case VertexFormat.kVertexFormatUNorm16:
return 2u;
result[i] = BitConverter.ToUInt16(inputBytes, i * 2) / 65535f;
break;
case VertexFormat.kVertexFormatSNorm16:
return 2u;
case VertexFormat.kVertexFormatUInt8:
return 1u;
case VertexFormat.kVertexFormatSInt8:
return 1u;
case VertexFormat.kVertexFormatUInt16:
return 2u;
case VertexFormat.kVertexFormatSInt16:
return 2u;
case VertexFormat.kVertexFormatUInt32:
return 4u;
case VertexFormat.kVertexFormatSInt32:
return 4u;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
else
{
switch ((VertexFormatV2019)format)
{
case VertexFormatV2019.kVertexFormatFloat:
return 4u;
case VertexFormatV2019.kVertexFormatFloat16:
return 2u;
case VertexFormatV2019.kVertexFormatUNorm8:
return 1u;
case VertexFormatV2019.kVertexFormatSNorm8:
return 1u;
case VertexFormatV2019.kVertexFormatUNorm16:
return 2u;
case VertexFormatV2019.kVertexFormatSNorm16:
return 2u;
case VertexFormatV2019.kVertexFormatUInt8:
return 1u;
case VertexFormatV2019.kVertexFormatSInt8:
return 1u;
case VertexFormatV2019.kVertexFormatUInt16:
return 2u;
case VertexFormatV2019.kVertexFormatSInt16:
return 2u;
case VertexFormatV2019.kVertexFormatUInt32:
return 4u;
case VertexFormatV2019.kVertexFormatSInt32:
return 4u;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
}
public static bool IsIntFormat(int[] version, int format)
{
if (version[0] < 2017)
{
return format == 4;
}
else if (version[0] < 2019)
{
return format >= 7;
}
else
{
return format >= 6;
}
}
public static float[] BytesToFloatArray(byte[] inputBytes, int size)
{
var result = new float[inputBytes.Length / size];
for (int i = 0; i < inputBytes.Length / size; i++)
{
var value = 0f;
switch (size)
{
case 1:
value = inputBytes[i] / 255.0f;
break;
case 2:
value = Half.ToHalf(inputBytes, i * 2);
break;
case 4:
value = BitConverter.ToSingle(inputBytes, i * 4);
result[i] = Math.Max(BitConverter.ToInt16(inputBytes, i * 2) / 32767f, -1f);
break;
}
result[i] = value;
}
return result;
}
public static int[] BytesToIntArray(byte[] inputBytes, int size)
public static int[] BytesToIntArray(byte[] inputBytes, VertexFormat format)
{
var result = new int[inputBytes.Length / size];
for (int i = 0; i < inputBytes.Length / size; i++)
var size = GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new int[len];
for (int i = 0; i < len; i++)
{
switch (size)
switch (format)
{
case 1:
case VertexFormat.kVertexFormatUInt8:
case VertexFormat.kVertexFormatSInt8:
result[i] = inputBytes[i];
break;
case 2:
case VertexFormat.kVertexFormatUInt16:
case VertexFormat.kVertexFormatSInt16:
result[i] = BitConverter.ToInt16(inputBytes, i * 2);
break;
case 4:
case VertexFormat.kVertexFormatUInt32:
case VertexFormat.kVertexFormatSInt32:
result[i] = BitConverter.ToInt32(inputBytes, i * 4);
break;
}
+1 -1
View File
@@ -8,7 +8,7 @@ namespace AssetStudio
public sealed class MonoScript : NamedObject
{
public string m_ClassName;
public string m_Namespace = string.Empty;
public string m_Namespace;
public string m_AssemblyName;
public MonoScript(ObjectReader reader) : base(reader)
+1 -1
View File
@@ -15,7 +15,7 @@ namespace AssetStudio
var m_Loop = reader.ReadBoolean();
reader.AlignStream();
m_AudioClip = new PPtr<AudioClip>(reader);
m_MovieData = reader.ReadBytes(reader.ReadInt32());
m_MovieData = reader.ReadUInt8Array();
}
}
}
+30 -14
View File
@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
namespace AssetStudio
{
@@ -36,19 +33,38 @@ namespace AssetStudio
}
}
protected bool HasStructMember(string name)
{
return serializedType?.m_Nodes != null && serializedType.m_Nodes.Any(x => x.m_Name == name);
}
public string Dump()
{
reader.Reset();
if (serializedType?.m_Nodes != null)
if (serializedType?.m_Type != null)
{
var sb = new StringBuilder();
TypeTreeHelper.ReadTypeString(sb, serializedType.m_Nodes, reader);
return sb.ToString();
return TypeTreeHelper.ReadTypeString(serializedType.m_Type, reader);
}
return null;
}
public string Dump(TypeTree m_Type)
{
if (m_Type != null)
{
return TypeTreeHelper.ReadTypeString(m_Type, reader);
}
return null;
}
public OrderedDictionary ToType()
{
if (serializedType?.m_Type != null)
{
return TypeTreeHelper.ReadType(serializedType.m_Type, reader);
}
return null;
}
public OrderedDictionary ToType(TypeTree m_Type)
{
if (m_Type != null)
{
return TypeTreeHelper.ReadType(m_Type, reader);
}
return null;
}
+1 -1
View File
@@ -13,7 +13,7 @@ namespace AssetStudio
public PPtr(ObjectReader reader)
{
m_FileID = reader.ReadInt32();
m_PathID = reader.m_Version < 14 ? reader.ReadInt32() : reader.ReadInt64();
m_PathID = reader.m_Version < SerializedFileFormatVersion.kUnknown_14 ? reader.ReadInt32() : reader.ReadInt64();
assetsFile = reader.assetsFile;
}
+8
View File
@@ -43,6 +43,10 @@ namespace AssetStudio
{
var m_DynamicOccludee = reader.ReadByte();
}
if (version[0] >= 2021) //2021.1 and up
{
var m_StaticShadowCaster = reader.ReadByte();
}
var m_MotionVectors = reader.ReadByte();
var m_LightProbeUsage = reader.ReadByte();
var m_ReflectionProbeUsage = reader.ReadByte();
@@ -50,6 +54,10 @@ namespace AssetStudio
{
var m_RayTracingMode = reader.ReadByte();
}
if (version[0] >= 2020) //2020.1 and up
{
var m_RayTraceProcedural = reader.ReadByte();
}
reader.AlignStream();
}
else
+19
View File
@@ -0,0 +1,19 @@
using System.Collections.Generic;
namespace AssetStudio
{
public class ResourceManager : Object
{
public KeyValuePair<string, PPtr<Object>>[] m_Container;
public ResourceManager(ObjectReader reader) : base(reader)
{
var m_ContainerSize = reader.ReadInt32();
m_Container = new KeyValuePair<string, PPtr<Object>>[m_ContainerSize];
for (int i = 0; i < m_ContainerSize; i++)
{
m_Container[i] = new KeyValuePair<string, PPtr<Object>>(reader.ReadAlignedString(), new PPtr<Object>(reader));
}
}
}
}
+255 -44
View File
@@ -5,6 +5,16 @@ using System.Linq;
namespace AssetStudio
{
public class Hash128
{
public byte[] bytes;
public Hash128(BinaryReader reader)
{
bytes = reader.ReadBytes(16);
}
}
public class StructParameter
{
public MatrixParameter[] m_MatrixParams;
@@ -201,6 +211,7 @@ namespace AssetStudio
public SerializedShaderFloatValue zTest;
public SerializedShaderFloatValue zWrite;
public SerializedShaderFloatValue culling;
public SerializedShaderFloatValue conservative;
public SerializedShaderFloatValue offsetFactor;
public SerializedShaderFloatValue offsetUnits;
public SerializedShaderFloatValue alphaToMask;
@@ -239,6 +250,10 @@ namespace AssetStudio
zTest = new SerializedShaderFloatValue(reader);
zWrite = new SerializedShaderFloatValue(reader);
culling = new SerializedShaderFloatValue(reader);
if (version[0] >= 2020) //2020.1 and up
{
conservative = new SerializedShaderFloatValue(reader);
}
offsetFactor = new SerializedShaderFloatValue(reader);
offsetUnits = new SerializedShaderFloatValue(reader);
alphaToMask = new SerializedShaderFloatValue(reader);
@@ -357,11 +372,18 @@ namespace AssetStudio
{
public int m_NameIndex;
public int m_Index;
public int m_ArraySize;
public BufferBinding(BinaryReader reader)
public BufferBinding(ObjectReader reader)
{
var version = reader.version;
m_NameIndex = reader.ReadInt32();
m_Index = reader.ReadInt32();
if (version[0] >= 2020) //2020.1 and up
{
m_ArraySize = reader.ReadInt32();
}
}
}
@@ -372,6 +394,7 @@ namespace AssetStudio
public VectorParameter[] m_VectorParams;
public StructParameter[] m_StructParams;
public int m_Size;
public bool m_IsPartialCB;
public ConstantBuffer(ObjectReader reader)
{
@@ -402,6 +425,16 @@ namespace AssetStudio
}
}
m_Size = reader.ReadInt32();
if ((version[0] == 2020 && version[1] > 3) ||
(version[0] == 2020 && version[1] == 3 && version[2] > 0) ||
(version[0] == 2020 && version[1] == 3 && version[2] == 0 && version[3] >= 2) || //2020.3.0f2 to 2020.3.x
(version[0] == 2021 && version[1] > 1) ||
(version[0] == 2021 && version[1] == 1 && version[2] >= 4)) //2021.1.4f1 to 2021.1.x
{
m_IsPartialCB = reader.ReadBoolean();
reader.AlignStream();
}
}
}
@@ -447,16 +480,16 @@ namespace AssetStudio
kShaderGpuProgramMetalVS = 23,
kShaderGpuProgramMetalFS = 24,
kShaderGpuProgramSPIRV = 25,
kShaderGpuProgramConsole = 26
kShaderGpuProgramConsoleVS = 26,
kShaderGpuProgramConsoleFS = 27,
kShaderGpuProgramConsoleHS = 28,
kShaderGpuProgramConsoleDS = 29,
kShaderGpuProgramConsoleGS = 30,
kShaderGpuProgramRayTracing = 31,
};
public class SerializedSubProgram
public class SerializedProgramParameters
{
public uint m_BlobIndex;
public ParserBindChannels m_Channels;
public ushort[] m_KeywordIndices;
public sbyte m_ShaderHardwareTier;
public ShaderGpuProgramType m_GpuProgramType;
public VectorParameter[] m_VectorParams;
public MatrixParameter[] m_MatrixParams;
public TextureParameter[] m_TextureParams;
@@ -466,33 +499,8 @@ namespace AssetStudio
public UAVParameter[] m_UAVParams;
public SamplerParameter[] m_Samplers;
public SerializedSubProgram(ObjectReader reader)
public SerializedProgramParameters(ObjectReader reader)
{
var version = reader.version;
m_BlobIndex = reader.ReadUInt32();
m_Channels = new ParserBindChannels(reader);
if (version[0] >= 2019) //2019 and up
{
var m_GlobalKeywordIndices = reader.ReadUInt16Array();
reader.AlignStream();
var m_LocalKeywordIndices = reader.ReadUInt16Array();
reader.AlignStream();
}
else
{
m_KeywordIndices = reader.ReadUInt16Array();
if (version[0] >= 2017) //2017 and up
{
reader.AlignStream();
}
}
m_ShaderHardwareTier = reader.ReadSByte();
m_GpuProgramType = (ShaderGpuProgramType)reader.ReadSByte();
reader.AlignStream();
int numVectorParams = reader.ReadInt32();
m_VectorParams = new VectorParameter[numVectorParams];
for (int i = 0; i < numVectorParams; i++)
@@ -542,18 +550,139 @@ namespace AssetStudio
m_UAVParams[i] = new UAVParameter(reader);
}
if (version[0] >= 2017) //2017 and up
int numSamplers = reader.ReadInt32();
m_Samplers = new SamplerParameter[numSamplers];
for (int i = 0; i < numSamplers; i++)
{
int numSamplers = reader.ReadInt32();
m_Samplers = new SamplerParameter[numSamplers];
for (int i = 0; i < numSamplers; i++)
m_Samplers[i] = new SamplerParameter(reader);
}
}
}
public class SerializedSubProgram
{
public uint m_BlobIndex;
public ParserBindChannels m_Channels;
public ushort[] m_KeywordIndices;
public sbyte m_ShaderHardwareTier;
public ShaderGpuProgramType m_GpuProgramType;
public SerializedProgramParameters m_Parameters;
public VectorParameter[] m_VectorParams;
public MatrixParameter[] m_MatrixParams;
public TextureParameter[] m_TextureParams;
public BufferBinding[] m_BufferParams;
public ConstantBuffer[] m_ConstantBuffers;
public BufferBinding[] m_ConstantBufferBindings;
public UAVParameter[] m_UAVParams;
public SamplerParameter[] m_Samplers;
public SerializedSubProgram(ObjectReader reader)
{
var version = reader.version;
m_BlobIndex = reader.ReadUInt32();
m_Channels = new ParserBindChannels(reader);
if (version[0] >= 2019) //2019 and up
{
var m_GlobalKeywordIndices = reader.ReadUInt16Array();
reader.AlignStream();
var m_LocalKeywordIndices = reader.ReadUInt16Array();
reader.AlignStream();
}
else
{
m_KeywordIndices = reader.ReadUInt16Array();
if (version[0] >= 2017) //2017 and up
{
m_Samplers[i] = new SamplerParameter(reader);
reader.AlignStream();
}
}
m_ShaderHardwareTier = reader.ReadSByte();
m_GpuProgramType = (ShaderGpuProgramType)reader.ReadSByte();
reader.AlignStream();
if ((version[0] == 2020 && version[1] > 3) ||
(version[0] == 2020 && version[1] == 3 && version[2] > 0) ||
(version[0] == 2020 && version[1] == 3 && version[2] == 0 && version[3] >= 2) || //2020.3.0f2 to 2020.3.x
(version[0] == 2021 && version[1] > 1) ||
(version[0] == 2021 && version[1] == 1 && version[2] >= 4)) //2021.1.4f1 to 2021.1.x
{
m_Parameters = new SerializedProgramParameters(reader);
}
else
{
int numVectorParams = reader.ReadInt32();
m_VectorParams = new VectorParameter[numVectorParams];
for (int i = 0; i < numVectorParams; i++)
{
m_VectorParams[i] = new VectorParameter(reader);
}
int numMatrixParams = reader.ReadInt32();
m_MatrixParams = new MatrixParameter[numMatrixParams];
for (int i = 0; i < numMatrixParams; i++)
{
m_MatrixParams[i] = new MatrixParameter(reader);
}
int numTextureParams = reader.ReadInt32();
m_TextureParams = new TextureParameter[numTextureParams];
for (int i = 0; i < numTextureParams; i++)
{
m_TextureParams[i] = new TextureParameter(reader);
}
int numBufferParams = reader.ReadInt32();
m_BufferParams = new BufferBinding[numBufferParams];
for (int i = 0; i < numBufferParams; i++)
{
m_BufferParams[i] = new BufferBinding(reader);
}
int numConstantBuffers = reader.ReadInt32();
m_ConstantBuffers = new ConstantBuffer[numConstantBuffers];
for (int i = 0; i < numConstantBuffers; i++)
{
m_ConstantBuffers[i] = new ConstantBuffer(reader);
}
int numConstantBufferBindings = reader.ReadInt32();
m_ConstantBufferBindings = new BufferBinding[numConstantBufferBindings];
for (int i = 0; i < numConstantBufferBindings; i++)
{
m_ConstantBufferBindings[i] = new BufferBinding(reader);
}
int numUAVParams = reader.ReadInt32();
m_UAVParams = new UAVParameter[numUAVParams];
for (int i = 0; i < numUAVParams; i++)
{
m_UAVParams[i] = new UAVParameter(reader);
}
if (version[0] >= 2017) //2017 and up
{
int numSamplers = reader.ReadInt32();
m_Samplers = new SamplerParameter[numSamplers];
for (int i = 0; i < numSamplers; i++)
{
m_Samplers[i] = new SamplerParameter(reader);
}
}
}
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
{
var m_ShaderRequirements = reader.ReadInt32();
if (version[0] >= 2021) //2021.1 and up
{
var m_ShaderRequirements = reader.ReadInt64();
}
else
{
var m_ShaderRequirements = reader.ReadInt32();
}
}
}
}
@@ -561,15 +690,27 @@ namespace AssetStudio
public class SerializedProgram
{
public SerializedSubProgram[] m_SubPrograms;
public SerializedProgramParameters m_CommonParameters;
public SerializedProgram(ObjectReader reader)
{
var version = reader.version;
int numSubPrograms = reader.ReadInt32();
m_SubPrograms = new SerializedSubProgram[numSubPrograms];
for (int i = 0; i < numSubPrograms; i++)
{
m_SubPrograms[i] = new SerializedSubProgram(reader);
}
if ((version[0] == 2020 && version[1] > 3) ||
(version[0] == 2020 && version[1] == 3 && version[2] > 0) ||
(version[0] == 2020 && version[1] == 3 && version[2] == 0 && version[3] >= 2) || //2020.3.0f2 to 2020.3.x
(version[0] == 2021 && version[1] > 1) ||
(version[0] == 2021 && version[1] == 1 && version[2] >= 4)) //2021.1.4f1 to 2021.1.x
{
m_CommonParameters = new SerializedProgramParameters(reader);
}
}
}
@@ -582,6 +723,10 @@ namespace AssetStudio
public class SerializedPass
{
public Hash128[] m_EditorDataHash;
public byte[] m_Platforms;
public ushort[] m_LocalKeywordMask;
public ushort[] m_GlobalKeywordMask;
public KeyValuePair<string, int>[] m_NameIndices;
public PassType m_Type;
public SerializedShaderState m_State;
@@ -602,6 +747,23 @@ namespace AssetStudio
{
var version = reader.version;
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
{
int numEditorDataHash = reader.ReadInt32();
m_EditorDataHash = new Hash128[numEditorDataHash];
for (int i = 0; i < numEditorDataHash; i++)
{
m_EditorDataHash[i] = new Hash128(reader);
}
reader.AlignStream();
m_Platforms = reader.ReadUInt8Array();
reader.AlignStream();
m_LocalKeywordMask = reader.ReadUInt16Array();
reader.AlignStream();
m_GlobalKeywordMask = reader.ReadUInt16Array();
reader.AlignStream();
}
int numIndices = reader.ReadInt32();
m_NameIndices = new KeyValuePair<string, int>[numIndices];
for (int i = 0; i < numIndices; i++)
@@ -681,6 +843,18 @@ namespace AssetStudio
}
}
public class SerializedCustomEditorForRenderPipeline
{
public string customEditorName;
public string renderPipelineType;
public SerializedCustomEditorForRenderPipeline(BinaryReader reader)
{
customEditorName = reader.ReadAlignedString();
renderPipelineType = reader.ReadAlignedString();
}
}
public class SerializedShader
{
public SerializedProperties m_PropInfo;
@@ -689,10 +863,13 @@ namespace AssetStudio
public string m_CustomEditorName;
public string m_FallbackName;
public SerializedShaderDependency[] m_Dependencies;
public SerializedCustomEditorForRenderPipeline[] m_CustomEditorForRenderPipelines;
public bool m_DisableNoSubshadersMessage;
public SerializedShader(ObjectReader reader)
{
var version = reader.version;
m_PropInfo = new SerializedProperties(reader);
int numSubShaders = reader.ReadInt32();
@@ -713,6 +890,16 @@ namespace AssetStudio
m_Dependencies[i] = new SerializedShaderDependency(reader);
}
if (version[0] >= 2021) //2021.1 and up
{
int m_CustomEditorForRenderPipelinesSize = reader.ReadInt32();
m_CustomEditorForRenderPipelines = new SerializedCustomEditorForRenderPipeline[m_CustomEditorForRenderPipelinesSize];
for (int i = 0; i < m_CustomEditorForRenderPipelinesSize; i++)
{
m_CustomEditorForRenderPipelines[i] = new SerializedCustomEditorForRenderPipeline(reader);
}
}
m_DisableNoSubshadersMessage = reader.ReadBoolean();
reader.AlignStream();
}
@@ -741,7 +928,11 @@ namespace AssetStudio
kShaderCompPlatformWiiU = 17,
kShaderCompPlatformVulkan = 18,
kShaderCompPlatformSwitch = 19,
kShaderCompPlatformXboxOneD3D12 = 20
kShaderCompPlatformXboxOneD3D12 = 20,
kShaderCompPlatformGameCoreXboxOne = 21,
kShaderCompPlatformGameCoreScarlett = 22,
kShaderCompPlatformPS5 = 23,
kShaderCompPlatformPS5NGGC = 24,
};
public class Shader : NamedObject
@@ -776,17 +967,37 @@ namespace AssetStudio
compressedLengths = reader.ReadUInt32Array();
decompressedLengths = reader.ReadUInt32Array();
}
compressedBlob = reader.ReadBytes(reader.ReadInt32());
compressedBlob = reader.ReadUInt8Array();
reader.AlignStream();
var m_DependenciesCount = reader.ReadInt32();
for (int i = 0; i < m_DependenciesCount; i++)
{
new PPtr<Shader>(reader);
}
if (version[0] >= 2018)
{
var m_NonModifiableTexturesCount = reader.ReadInt32();
for (int i = 0; i < m_NonModifiableTexturesCount; i++)
{
var first = reader.ReadAlignedString();
new PPtr<Texture>(reader);
}
}
var m_ShaderIsBaked = reader.ReadBoolean();
reader.AlignStream();
}
else
{
m_Script = reader.ReadBytes(reader.ReadInt32());
m_Script = reader.ReadUInt8Array();
reader.AlignStream();
var m_PathName = reader.ReadAlignedString();
if (version[0] == 5 && version[1] >= 3) //5.3 - 5.4
{
decompressedSize = reader.ReadUInt32();
m_SubProgramBlob = reader.ReadBytes(reader.ReadInt32());
m_SubProgramBlob = reader.ReadUInt8Array();
}
}
}
+21 -6
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace AssetStudio
@@ -88,7 +87,7 @@ namespace AssetStudio
public ushort[] indices;
public Matrix4x4[] m_Bindpose;
public BoneWeights4[] m_SourceSkin;
public RectangleF textureRect;
public Rectf textureRect;
public Vector2 textureRectOffset;
public Vector2 atlasRectOffset;
public SpriteSettings settingsRaw;
@@ -124,7 +123,7 @@ namespace AssetStudio
m_SubMeshes[i] = new SubMesh(reader);
}
m_IndexBuffer = reader.ReadBytes(reader.ReadInt32());
m_IndexBuffer = reader.ReadUInt8Array();
reader.AlignStream();
m_VertexData = new VertexData(reader);
@@ -156,7 +155,7 @@ namespace AssetStudio
}
}
textureRect = reader.ReadRectangleF();
textureRect = new Rectf(reader);
textureRectOffset = reader.ReadVector2();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
{
@@ -176,9 +175,25 @@ namespace AssetStudio
}
}
public class Rectf
{
public float x;
public float y;
public float width;
public float height;
public Rectf(BinaryReader reader)
{
x = reader.ReadSingle();
y = reader.ReadSingle();
width = reader.ReadSingle();
height = reader.ReadSingle();
}
}
public sealed class Sprite : NamedObject
{
public RectangleF m_Rect;
public Rectf m_Rect;
public Vector2 m_Offset;
public Vector4 m_Border;
public float m_PixelsToUnits;
@@ -193,7 +208,7 @@ namespace AssetStudio
public Sprite(ObjectReader reader) : base(reader)
{
m_Rect = reader.ReadRectangleF();
m_Rect = new Rectf(reader);
m_Offset = reader.ReadVector2();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
{
+13 -2
View File
@@ -7,19 +7,20 @@ namespace AssetStudio
{
public PPtr<Texture2D> texture;
public PPtr<Texture2D> alphaTexture;
public System.Drawing.RectangleF textureRect;
public Rectf textureRect;
public Vector2 textureRectOffset;
public Vector2 atlasRectOffset;
public Vector4 uvTransform;
public float downscaleMultiplier;
public SpriteSettings settingsRaw;
public SecondarySpriteTexture[] secondaryTextures;
public SpriteAtlasData(ObjectReader reader)
{
var version = reader.version;
texture = new PPtr<Texture2D>(reader);
alphaTexture = new PPtr<Texture2D>(reader);
textureRect = reader.ReadRectangleF();
textureRect = new Rectf(reader);
textureRectOffset = reader.ReadVector2();
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
{
@@ -28,6 +29,16 @@ namespace AssetStudio
uvTransform = reader.ReadVector4();
downscaleMultiplier = reader.ReadSingle();
settingsRaw = new SpriteSettings(reader);
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
{
var secondaryTexturesSize = reader.ReadInt32();
secondaryTextures = new SecondarySpriteTexture[secondaryTexturesSize];
for (int i = 0; i < secondaryTexturesSize; i++)
{
secondaryTextures[i] = new SecondarySpriteTexture(reader);
}
reader.AlignStream();
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ namespace AssetStudio
public TextAsset(ObjectReader reader) : base(reader)
{
m_Script = reader.ReadBytes(reader.ReadInt32());
m_Script = reader.ReadUInt8Array();
}
}
}
+4
View File
@@ -13,6 +13,10 @@ namespace AssetStudio
{
var m_ForcedFallbackFormat = reader.ReadInt32();
var m_DownscaleFallback = reader.ReadBoolean();
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
{
var m_IsAlphaChannelOptional = reader.ReadBoolean();
}
reader.AlignStream();
}
}
+46 -5
View File
@@ -4,13 +4,22 @@ namespace AssetStudio
{
public class StreamingInfo
{
public uint offset;
public ulong offset;
public uint size;
public string path;
public StreamingInfo(ObjectReader reader)
{
offset = reader.ReadUInt32();
var version = reader.version;
if (version[0] >= 2020) //2020.1 and up
{
offset = reader.ReadUInt64();
}
else
{
offset = reader.ReadUInt32();
}
size = reader.ReadUInt32();
path = reader.ReadAlignedString();
}
@@ -59,6 +68,10 @@ namespace AssetStudio
m_Width = reader.ReadInt32();
m_Height = reader.ReadInt32();
var m_CompleteImageSize = reader.ReadInt32();
if (version[0] >= 2020) //2020.1 and up
{
var m_MipsStripped = reader.ReadInt32();
}
m_TextureFormat = (TextureFormat)reader.ReadInt32();
if (version[0] < 5 || (version[0] == 5 && version[1] < 2)) //5.2 down
{
@@ -68,9 +81,29 @@ namespace AssetStudio
{
m_MipCount = reader.ReadInt32();
}
var m_IsReadable = reader.ReadBoolean(); //2.6.0 and up
var m_ReadAllowed = reader.ReadBoolean(); //3.0.0 - 5.4
//bool m_StreamingMipmaps 2018.2 and up
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6)) //2.6.0 and up
{
var m_IsReadable = reader.ReadBoolean();
}
if (version[0] >= 2020) //2020.1 and up
{
var m_IsPreProcessed = reader.ReadBoolean();
}
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
{
var m_IgnoreMasterTextureLimit = reader.ReadBoolean();
}
if (version[0] >= 3) //3.0.0 - 5.4
{
if (version[0] < 5 || (version[0] == 5 && version[1] <= 4))
{
var m_ReadAllowed = reader.ReadBoolean();
}
}
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
{
var m_StreamingMipmaps = reader.ReadBoolean();
}
reader.AlignStream();
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
{
@@ -87,6 +120,11 @@ namespace AssetStudio
{
var m_ColorSpace = reader.ReadInt32();
}
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
{
var m_PlatformBlob = reader.ReadUInt8Array();
reader.AlignStream();
}
var image_data_size = reader.ReadInt32();
if (image_data_size == 0 && ((version[0] == 5 && version[1] >= 3) || version[0] > 5))//5.3.0 and up
{
@@ -171,5 +209,8 @@ namespace AssetStudio
ASTC_HDR_8x8,
ASTC_HDR_10x10,
ASTC_HDR_12x12,
RG32,
RGB48,
RGBA64
}
}
+33 -14
View File
@@ -1,17 +1,26 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.IO;
namespace AssetStudio
{
public class StreamedResource
{
public string m_Source;
public ulong m_Offset;
public ulong m_Size;
public StreamedResource(BinaryReader reader)
{
m_Source = reader.ReadAlignedString();
m_Offset = reader.ReadUInt64();
m_Size = reader.ReadUInt64();
}
}
public sealed class VideoClip : NamedObject
{
public ResourceReader m_VideoData;
public string m_OriginalPath;
public string m_Source;
public ulong m_Size;
public StreamedResource m_ExternalResources;
public VideoClip(ObjectReader reader) : base(reader)
{
@@ -32,20 +41,30 @@ namespace AssetStudio
reader.AlignStream();
var m_AudioSampleRate = reader.ReadUInt32Array();
var m_AudioLanguage = reader.ReadStringArray();
//StreamedResource m_ExternalResources
m_Source = reader.ReadAlignedString();
var m_Offset = reader.ReadUInt64();
m_Size = reader.ReadUInt64();
if (version[0] >= 2020) //2020.1 and up
{
var m_VideoShadersSize = reader.ReadInt32();
var m_VideoShaders = new PPtr<Shader>[m_VideoShadersSize];
for (int i = 0; i < m_VideoShadersSize; i++)
{
m_VideoShaders[i] = new PPtr<Shader>(reader);
}
}
m_ExternalResources = new StreamedResource(reader);
var m_HasSplitAlpha = reader.ReadBoolean();
if (version[0] >= 2020) //2020.1 and up
{
var m_sRGB = reader.ReadBoolean();
}
ResourceReader resourceReader;
if (!string.IsNullOrEmpty(m_Source))
if (!string.IsNullOrEmpty(m_ExternalResources.m_Source))
{
resourceReader = new ResourceReader(m_Source, assetsFile, (long)m_Offset, (int)m_Size);
resourceReader = new ResourceReader(m_ExternalResources.m_Source, assetsFile, m_ExternalResources.m_Offset, (int)m_ExternalResources.m_Size);
}
else
{
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size);
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_ExternalResources.m_Size);
}
m_VideoData = resourceReader;
}
+2 -1
View File
@@ -113,7 +113,8 @@ namespace AssetStudio
{1093, "m_CorrespondingSourceObject"},
{1121, "m_PrefabInstance"},
{1138, "m_PrefabAsset"},
{1152, "FileSize"}
{1152, "FileSize"},
{1161, "Hash128"}
};
}
}
@@ -72,11 +72,6 @@ namespace AssetStudio
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
}
public static System.Drawing.RectangleF ReadRectangleF(this BinaryReader reader)
{
return new System.Drawing.RectangleF(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
}
public static Color ReadColor4(this BinaryReader reader)
{
return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
@@ -102,6 +97,11 @@ namespace AssetStudio
return ReadArray(reader.ReadBoolean, reader.ReadInt32());
}
public static byte[] ReadUInt8Array(this BinaryReader reader)
{
return reader.ReadBytes(reader.ReadInt32());
}
public static ushort[] ReadUInt16Array(this BinaryReader reader)
{
return ReadArray(reader.ReadUInt16, reader.ReadInt32());
+4 -4
View File
@@ -20,8 +20,8 @@ namespace AssetStudio
foreach (var splitFile in splitFiles)
{
var destFile = Path.GetFileNameWithoutExtension(splitFile);
var destPath = Path.GetDirectoryName(splitFile) + "\\";
var destFull = destPath + destFile;
var destPath = Path.GetDirectoryName(splitFile);
var destFull = Path.Combine(destPath, destFile);
if (!File.Exists(destFull))
{
var splitParts = Directory.GetFiles(destPath, destFile + ".split*");
@@ -43,7 +43,7 @@ namespace AssetStudio
public static string[] ProcessingSplitFiles(List<string> selectFile)
{
var splitFiles = selectFile.Where(x => x.Contains(".split"))
.Select(x => Path.GetDirectoryName(x) + "\\" + Path.GetFileNameWithoutExtension(x))
.Select(x => Path.Combine(Path.GetDirectoryName(x), Path.GetFileNameWithoutExtension(x)))
.Distinct()
.ToList();
selectFile.RemoveAll(x => x.Contains(".split"));
@@ -65,7 +65,7 @@ namespace AssetStudio
public static FileType CheckFileType(string fileName, out EndianBinaryReader reader)
{
reader = new EndianBinaryReader(File.OpenRead(fileName));
reader = new EndianBinaryReader(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
return CheckFileType(reader);
}
+8
View File
@@ -14,5 +14,13 @@ namespace AssetStudio
public static void Info(string message) => Default.Log(LoggerEvent.Info, message);
public static void Warning(string message) => Default.Log(LoggerEvent.Warning, message);
public static void Error(string message) => Default.Log(LoggerEvent.Error, message);
public static void Error(string message, Exception e)
{
var sb = new StringBuilder();
sb.AppendLine(message);
sb.AppendLine(e.ToString());
Default.Log(LoggerEvent.Error, sb.ToString());
}
}
}
+2
View File
@@ -11,6 +11,8 @@ namespace AssetStudio
public uint byteSize;
public int typeID;
public int classID;
public ushort isDestroyed;
public byte stripped;
public long m_PathID;
public SerializedType serializedType;
+1 -1
View File
@@ -15,7 +15,7 @@ namespace AssetStudio
public ClassIDType type;
public SerializedType serializedType;
public BuildTarget platform;
public uint m_Version;
public SerializedFileFormatVersion m_Version;
public int[] version => assetsFile.version;
public BuildType buildType => assetsFile.buildType;
+2 -2
View File
@@ -12,12 +12,12 @@ namespace AssetStudio
private BinaryReader reader;
public ResourceReader(string path, SerializedFile assetsFile, long offset, int size)
public ResourceReader(string path, SerializedFile assetsFile, ulong offset, int size)
{
needSearch = true;
this.path = path;
this.assetsFile = assetsFile;
this.offset = offset;
this.offset = (long)offset;
this.size = size;
}
+78 -66
View File
@@ -19,15 +19,17 @@ namespace AssetStudio
public Dictionary<long, Object> ObjectsDic;
public SerializedFileHeader header;
private EndianType m_FileEndianess;
private byte m_FileEndianess;
public string unityVersion = "2.5.0f5";
public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform;
private bool m_EnableTypeTree = true;
public List<SerializedType> m_Types;
public List<SerializedType> m_RefTypes;
public int bigIDEnabled = 0;
public List<ObjectInfo> m_Objects;
private List<LocalSerializedObjectIdentifier> m_ScriptTypes;
public List<FileIdentifier> m_Externals;
public List<SerializedType> m_RefTypes;
public string userInformation;
public SerializedFile(AssetsManager assetsManager, string fullName, EndianBinaryReader reader)
{
@@ -36,26 +38,26 @@ namespace AssetStudio
this.fullName = fullName;
fileName = Path.GetFileName(fullName);
//ReadHeader
// ReadHeader
header = new SerializedFileHeader();
header.m_MetadataSize = reader.ReadUInt32();
header.m_FileSize = reader.ReadUInt32();
header.m_Version = reader.ReadUInt32();
header.m_Version = (SerializedFileFormatVersion)reader.ReadUInt32();
header.m_DataOffset = reader.ReadUInt32();
if (header.m_Version >= 9)
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_9)
{
header.m_Endianess = reader.ReadByte();
header.m_Reserved = reader.ReadBytes(3);
m_FileEndianess = (EndianType)header.m_Endianess;
m_FileEndianess = header.m_Endianess;
}
else
{
reader.Position = header.m_FileSize - header.m_MetadataSize;
m_FileEndianess = (EndianType)reader.ReadByte();
m_FileEndianess = reader.ReadByte();
}
if (header.m_Version >= 22)
if (header.m_Version >= SerializedFileFormatVersion.kLargeFilesSupport)
{
header.m_MetadataSize = reader.ReadUInt32();
header.m_FileSize = reader.ReadInt64();
@@ -63,17 +65,17 @@ namespace AssetStudio
reader.ReadInt64(); // unknown
}
//ReadMetadata
if (m_FileEndianess == EndianType.LittleEndian)
// ReadMetadata
if (m_FileEndianess == 0)
{
reader.endian = EndianType.LittleEndian;
}
if (header.m_Version >= 7)
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_7)
{
unityVersion = reader.ReadStringToNull();
SetVersion(unityVersion);
}
if (header.m_Version >= 8)
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_8)
{
m_TargetPlatform = (BuildTarget)reader.ReadInt32();
if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform))
@@ -81,26 +83,25 @@ namespace AssetStudio
m_TargetPlatform = BuildTarget.UnknownPlatform;
}
}
if (header.m_Version >= 13)
if (header.m_Version >= SerializedFileFormatVersion.kHasTypeTreeHashes)
{
m_EnableTypeTree = reader.ReadBoolean();
}
//ReadTypes
// Read Types
int typeCount = reader.ReadInt32();
m_Types = new List<SerializedType>(typeCount);
for (int i = 0; i < typeCount; i++)
{
m_Types.Add(ReadSerializedType());
m_Types.Add(ReadSerializedType(false));
}
var bigIDEnabled = 0;
if (header.m_Version >= 7 && header.m_Version < 14)
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_7 && header.m_Version < SerializedFileFormatVersion.kUnknown_14)
{
bigIDEnabled = reader.ReadInt32();
}
//ReadObjects
// Read Objects
int objectCount = reader.ReadInt32();
m_Objects = new List<ObjectInfo>(objectCount);
Objects = new List<Object>(objectCount);
@@ -112,7 +113,7 @@ namespace AssetStudio
{
objectInfo.m_PathID = reader.ReadInt64();
}
else if (header.m_Version < 14)
else if (header.m_Version < SerializedFileFormatVersion.kUnknown_14)
{
objectInfo.m_PathID = reader.ReadInt32();
}
@@ -122,7 +123,7 @@ namespace AssetStudio
objectInfo.m_PathID = reader.ReadInt64();
}
if (header.m_Version >= 22)
if (header.m_Version >= SerializedFileFormatVersion.kLargeFilesSupport)
objectInfo.byteStart = reader.ReadInt64();
else
objectInfo.byteStart = reader.ReadUInt32();
@@ -130,7 +131,7 @@ namespace AssetStudio
objectInfo.byteStart += header.m_DataOffset;
objectInfo.byteSize = reader.ReadUInt32();
objectInfo.typeID = reader.ReadInt32();
if (header.m_Version < 16)
if (header.m_Version < SerializedFileFormatVersion.kRefactoredClassId)
{
objectInfo.classID = reader.ReadUInt16();
objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID);
@@ -141,24 +142,24 @@ namespace AssetStudio
objectInfo.serializedType = type;
objectInfo.classID = type.classID;
}
if (header.m_Version < 11)
if (header.m_Version < SerializedFileFormatVersion.kHasScriptTypeIndex)
{
var isDestroyed = reader.ReadUInt16();
objectInfo.isDestroyed = reader.ReadUInt16();
}
if (header.m_Version >= 11 && header.m_Version < 17)
if (header.m_Version >= SerializedFileFormatVersion.kHasScriptTypeIndex && header.m_Version < SerializedFileFormatVersion.kRefactorTypeData)
{
var m_ScriptTypeIndex = reader.ReadInt16();
if (objectInfo.serializedType != null)
objectInfo.serializedType.m_ScriptTypeIndex = m_ScriptTypeIndex;
}
if (header.m_Version == 15 || header.m_Version == 16)
if (header.m_Version == SerializedFileFormatVersion.kSupportsStrippedObject || header.m_Version == SerializedFileFormatVersion.kRefactoredClassId)
{
var stripped = reader.ReadByte();
objectInfo.stripped = reader.ReadByte();
}
m_Objects.Add(objectInfo);
}
if (header.m_Version >= 11)
if (header.m_Version >= SerializedFileFormatVersion.kHasScriptTypeIndex)
{
int scriptCount = reader.ReadInt32();
m_ScriptTypes = new List<LocalSerializedObjectIdentifier>(scriptCount);
@@ -166,7 +167,7 @@ namespace AssetStudio
{
var m_ScriptType = new LocalSerializedObjectIdentifier();
m_ScriptType.localSerializedFileIndex = reader.ReadInt32();
if (header.m_Version < 14)
if (header.m_Version < SerializedFileFormatVersion.kUnknown_14)
{
m_ScriptType.localIdentifierInFile = reader.ReadInt32();
}
@@ -184,11 +185,11 @@ namespace AssetStudio
for (int i = 0; i < externalsCount; i++)
{
var m_External = new FileIdentifier();
if (header.m_Version >= 6)
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_6)
{
var tempEmpty = reader.ReadStringToNull();
}
if (header.m_Version >= 5)
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_5)
{
m_External.guid = new Guid(reader.ReadBytes(16));
m_External.type = reader.ReadInt32();
@@ -198,19 +199,19 @@ namespace AssetStudio
m_Externals.Add(m_External);
}
if (header.m_Version >= 20)
if (header.m_Version >= SerializedFileFormatVersion.kSupportsRefObject)
{
int refTypesCount = reader.ReadInt32();
m_RefTypes = new List<SerializedType>(refTypesCount);
for (int i = 0; i < refTypesCount; i++)
{
m_RefTypes.Add(ReadSerializedType());
m_RefTypes.Add(ReadSerializedType(true));
}
}
if (header.m_Version >= 5)
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_5)
{
var userInformation = reader.ReadStringToNull();
userInformation = reader.ReadStringToNull();
}
//reader.AlignStream(16);
@@ -225,73 +226,84 @@ namespace AssetStudio
version = versionSplit.Select(int.Parse).ToArray();
}
private SerializedType ReadSerializedType()
private SerializedType ReadSerializedType(bool isRefType)
{
var type = new SerializedType();
type.classID = reader.ReadInt32();
if (header.m_Version >= 16)
if (header.m_Version >= SerializedFileFormatVersion.kRefactoredClassId)
{
type.m_IsStrippedType = reader.ReadBoolean();
}
if (header.m_Version >= 17)
if (header.m_Version >= SerializedFileFormatVersion.kRefactorTypeData)
{
type.m_ScriptTypeIndex = reader.ReadInt16();
}
if (header.m_Version >= 13)
if (header.m_Version >= SerializedFileFormatVersion.kHasTypeTreeHashes)
{
if ((header.m_Version < 16 && type.classID < 0) || (header.m_Version >= 16 && type.classID == 114))
if (isRefType && type.m_ScriptTypeIndex >= 0)
{
type.m_ScriptID = reader.ReadBytes(16); //Hash128
type.m_ScriptID = reader.ReadBytes(16);
}
type.m_OldTypeHash = reader.ReadBytes(16); //Hash128
else if ((header.m_Version < SerializedFileFormatVersion.kRefactoredClassId && type.classID < 0) || (header.m_Version >= SerializedFileFormatVersion.kRefactoredClassId && type.classID == 114))
{
type.m_ScriptID = reader.ReadBytes(16);
}
type.m_OldTypeHash = reader.ReadBytes(16);
}
if (m_EnableTypeTree)
{
var typeTree = new List<TypeTreeNode>();
if (header.m_Version >= 12 || header.m_Version == 10)
type.m_Type = new TypeTree();
type.m_Type.m_Nodes = new List<TypeTreeNode>();
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_12 || header.m_Version == SerializedFileFormatVersion.kUnknown_10)
{
TypeTreeBlobRead(typeTree);
TypeTreeBlobRead(type.m_Type);
}
else
{
ReadTypeTree(typeTree);
ReadTypeTree(type.m_Type);
}
if (header.m_Version >= 21)
if (header.m_Version >= SerializedFileFormatVersion.kStoresTypeDependencies)
{
type.m_TypeDependencies = reader.ReadInt32Array();
if (isRefType)
{
type.m_KlassName = reader.ReadStringToNull();
type.m_NameSpace = reader.ReadStringToNull();
type.m_AsmName = reader.ReadStringToNull();
}
else
{
type.m_TypeDependencies = reader.ReadInt32Array();
}
}
type.m_Nodes = typeTree;
}
return type;
}
private void ReadTypeTree(List<TypeTreeNode> typeTree, int level = 0)
private void ReadTypeTree(TypeTree m_Type, int level = 0)
{
var typeTreeNode = new TypeTreeNode();
typeTree.Add(typeTreeNode);
m_Type.m_Nodes.Add(typeTreeNode);
typeTreeNode.m_Level = level;
typeTreeNode.m_Type = reader.ReadStringToNull();
typeTreeNode.m_Name = reader.ReadStringToNull();
typeTreeNode.m_ByteSize = reader.ReadInt32();
if (header.m_Version == 2)
if (header.m_Version == SerializedFileFormatVersion.kUnknown_2)
{
var variableCount = reader.ReadInt32();
}
if (header.m_Version != 3)
if (header.m_Version != SerializedFileFormatVersion.kUnknown_3)
{
typeTreeNode.m_Index = reader.ReadInt32();
}
typeTreeNode.m_IsArray = reader.ReadInt32();
typeTreeNode.m_TypeFlags = reader.ReadInt32();
typeTreeNode.m_Version = reader.ReadInt32();
if (header.m_Version != 3)
if (header.m_Version != SerializedFileFormatVersion.kUnknown_3)
{
typeTreeNode.m_MetaFlag = reader.ReadInt32();
}
@@ -299,40 +311,40 @@ namespace AssetStudio
int childrenCount = reader.ReadInt32();
for (int i = 0; i < childrenCount; i++)
{
ReadTypeTree(typeTree, level + 1);
ReadTypeTree(m_Type, level + 1);
}
}
private void TypeTreeBlobRead(List<TypeTreeNode> typeTree)
private void TypeTreeBlobRead(TypeTree m_Type)
{
int numberOfNodes = reader.ReadInt32();
int stringBufferSize = reader.ReadInt32();
for (int i = 0; i < numberOfNodes; i++)
{
var typeTreeNode = new TypeTreeNode();
typeTree.Add(typeTreeNode);
m_Type.m_Nodes.Add(typeTreeNode);
typeTreeNode.m_Version = reader.ReadUInt16();
typeTreeNode.m_Level = reader.ReadByte();
typeTreeNode.m_IsArray = reader.ReadBoolean() ? 1 : 0;
typeTreeNode.m_TypeFlags = reader.ReadByte();
typeTreeNode.m_TypeStrOffset = reader.ReadUInt32();
typeTreeNode.m_NameStrOffset = reader.ReadUInt32();
typeTreeNode.m_ByteSize = reader.ReadInt32();
typeTreeNode.m_Index = reader.ReadInt32();
typeTreeNode.m_MetaFlag = reader.ReadInt32();
if (header.m_Version >= 19)
if (header.m_Version >= SerializedFileFormatVersion.kTypeTreeNodeWithTypeFlags)
{
typeTreeNode.m_RefTypeHash = reader.ReadUInt64();
}
}
var m_StringBuffer = reader.ReadBytes(stringBufferSize);
m_Type.m_StringBuffer = reader.ReadBytes(stringBufferSize);
using (var stringBufferReader = new BinaryReader(new MemoryStream(m_StringBuffer)))
using (var stringBufferReader = new BinaryReader(new MemoryStream(m_Type.m_StringBuffer)))
{
for (int i = 0; i < numberOfNodes; i++)
{
var typeTreeNode = typeTree[i];
typeTreeNode.m_Type = ReadString(stringBufferReader, typeTreeNode.m_TypeStrOffset);
typeTreeNode.m_Name = ReadString(stringBufferReader, typeTreeNode.m_NameStrOffset);
var m_Node = m_Type.m_Nodes[i];
m_Node.m_Type = ReadString(stringBufferReader, m_Node.m_TypeStrOffset);
m_Node.m_Name = ReadString(stringBufferReader, m_Node.m_NameStrOffset);
}
}
@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AssetStudio
{
public enum SerializedFileFormatVersion
{
kUnsupported = 1,
kUnknown_2 = 2,
kUnknown_3 = 3,
/// <summary>
/// 1.2.0 to 2.0.0
/// </summary>
kUnknown_5 = 5,
/// <summary>
/// 2.1.0 to 2.6.1
/// </summary>
kUnknown_6 = 6,
/// <summary>
/// 3.0.0b
/// </summary>
kUnknown_7 = 7,
/// <summary>
/// 3.0.0 to 3.4.2
/// </summary>
kUnknown_8 = 8,
/// <summary>
/// 3.5.0 to 4.7.2
/// </summary>
kUnknown_9 = 9,
/// <summary>
/// 5.0.0aunk1
/// </summary>
kUnknown_10 = 10,
/// <summary>
/// 5.0.0aunk2
/// </summary>
kHasScriptTypeIndex = 11,
/// <summary>
/// 5.0.0aunk3
/// </summary>
kUnknown_12 = 12,
/// <summary>
/// 5.0.0aunk4
/// </summary>
kHasTypeTreeHashes = 13,
/// <summary>
/// 5.0.0unk
/// </summary>
kUnknown_14 = 14,
/// <summary>
/// 5.0.1 to 5.4.0
/// </summary>
kSupportsStrippedObject = 15,
/// <summary>
/// 5.5.0a
/// </summary>
kRefactoredClassId = 16,
/// <summary>
/// 5.5.0unk to 2018.4
/// </summary>
kRefactorTypeData = 17,
/// <summary>
/// 2019.1a
/// </summary>
kRefactorShareableTypeTreeData = 18,
/// <summary>
/// 2019.1unk
/// </summary>
kTypeTreeNodeWithTypeFlags = 19,
/// <summary>
/// 2019.2
/// </summary>
kSupportsRefObject = 20,
/// <summary>
/// 2019.3 to 2019.4
/// </summary>
kStoresTypeDependencies = 21,
/// <summary>
/// 2020.1 to x
/// </summary>
kLargeFilesSupport = 22
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ namespace AssetStudio
{
public uint m_MetadataSize;
public long m_FileSize;
public uint m_Version;
public SerializedFileFormatVersion m_Version;
public long m_DataOffset;
public byte m_Endianess;
public byte[] m_Reserved;
+4 -1
View File
@@ -10,9 +10,12 @@ namespace AssetStudio
public int classID;
public bool m_IsStrippedType;
public short m_ScriptTypeIndex = -1;
public List<TypeTreeNode> m_Nodes;
public TypeTree m_Type;
public byte[] m_ScriptID; //Hash128
public byte[] m_OldTypeHash; //Hash128
public int[] m_TypeDependencies;
public string m_KlassName;
public string m_NameSpace;
public string m_AsmName;
}
}
+5 -4
View File
@@ -34,15 +34,16 @@ namespace AssetStudio
return newOutStream;
}
public static void StreamDecompress(Stream inStream, Stream outStream, long inSize, long outSize)
public static void StreamDecompress(Stream compressedStream, Stream decompressedStream, long compressedSize, long decompressedSize)
{
var basePosition = compressedStream.Position;
var decoder = new Decoder();
var properties = new byte[5];
if (inStream.Read(properties, 0, 5) != 5)
if (compressedStream.Read(properties, 0, 5) != 5)
throw new Exception("input .lzma is too short");
decoder.SetDecoderProperties(properties);
inSize -= 5L;
decoder.Code(inStream, outStream, inSize, outSize, null);
decoder.Code(compressedStream, decompressedStream, compressedSize - 5, decompressedSize, null);
compressedStream.Position = basePosition + compressedSize;
}
}
}
+1
View File
@@ -4,6 +4,7 @@ namespace AssetStudio
{
public class StreamFile
{
public string path;
public string fileName;
public Stream stream;
}
+14
View File
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AssetStudio
{
public class TypeTree
{
public List<TypeTreeNode> m_Nodes;
public byte[] m_StringBuffer;
}
}
+63 -48
View File
@@ -1,30 +1,38 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
namespace AssetStudio
{
public static class TypeTreeHelper
{
public static void ReadTypeString(StringBuilder sb, List<TypeTreeNode> members, BinaryReader reader)
public static string ReadTypeString(TypeTree m_Type, ObjectReader reader)
{
for (int i = 0; i < members.Count; i++)
reader.Reset();
var sb = new StringBuilder();
var m_Nodes = m_Type.m_Nodes;
for (int i = 0; i < m_Nodes.Count; i++)
{
ReadStringValue(sb, members, reader, ref i);
ReadStringValue(sb, m_Nodes, reader, ref i);
}
var readed = reader.Position - reader.byteStart;
if (readed != reader.byteSize)
{
Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
}
return sb.ToString();
}
private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> members, BinaryReader reader, ref int i)
private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> m_Nodes, BinaryReader reader, ref int i)
{
var member = members[i];
var level = member.m_Level;
var varTypeStr = member.m_Type;
var varNameStr = member.m_Name;
var m_Node = m_Nodes[i];
var level = m_Node.m_Level;
var varTypeStr = m_Node.m_Type;
var varNameStr = m_Node.m_Name;
object value = null;
var append = true;
var align = (member.m_MetaFlag & 0x4000) != 0;
var align = (m_Node.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr)
{
case "SInt8":
@@ -77,18 +85,18 @@ namespace AssetStudio
break;
case "map":
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
append = false;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
var size = reader.ReadInt32();
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
var map = GetMembers(members, i);
var map = GetNodes(m_Nodes, i);
i += map.Count - 1;
var first = GetMembers(map, 4);
var first = GetNodes(map, 4);
var next = 4 + first.Count;
var second = GetMembers(map, next);
var second = GetNodes(map, next);
for (int j = 0; j < size; j++)
{
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
@@ -112,16 +120,16 @@ namespace AssetStudio
}
default:
{
if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array
if (i < m_Nodes.Count - 1 && m_Nodes[i + 1].m_Type == "Array") //Array
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
append = false;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
var size = reader.ReadInt32();
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
var vector = GetMembers(members, i);
var vector = GetNodes(m_Nodes, i);
i += vector.Count - 1;
for (int j = 0; j < size; j++)
{
@@ -135,7 +143,7 @@ namespace AssetStudio
{
append = false;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
var @class = GetMembers(members, i);
var @class = GetNodes(m_Nodes, i);
i += @class.Count - 1;
for (int j = 1; j < @class.Count; j++)
{
@@ -151,24 +159,31 @@ namespace AssetStudio
reader.AlignStream();
}
public static UType ReadUType(List<TypeTreeNode> members, BinaryReader reader)
public static OrderedDictionary ReadType(TypeTree m_Types, ObjectReader reader)
{
var obj = new UType();
for (int i = 1; i < members.Count; i++)
reader.Reset();
var obj = new OrderedDictionary();
var m_Nodes = m_Types.m_Nodes;
for (int i = 1; i < m_Nodes.Count; i++)
{
var member = members[i];
var varNameStr = member.m_Name;
obj[varNameStr] = ReadValue(members, reader, ref i);
var m_Node = m_Nodes[i];
var varNameStr = m_Node.m_Name;
obj[varNameStr] = ReadValue(m_Nodes, reader, ref i);
}
var readed = reader.Position - reader.byteStart;
if (readed != reader.byteSize)
{
Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
}
return obj;
}
private static object ReadValue(List<TypeTreeNode> members, BinaryReader reader, ref int i)
private static object ReadValue(List<TypeTreeNode> m_Nodes, BinaryReader reader, ref int i)
{
var member = members[i];
var varTypeStr = member.m_Type;
var m_Node = m_Nodes[i];
var varTypeStr = m_Node.m_Type;
object value;
var align = (member.m_MetaFlag & 0x4000) != 0;
var align = (m_Node.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr)
{
case "SInt8":
@@ -219,13 +234,13 @@ namespace AssetStudio
break;
case "map":
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
var map = GetMembers(members, i);
var map = GetNodes(m_Nodes, i);
i += map.Count - 1;
var first = GetMembers(map, 4);
var first = GetNodes(map, 4);
var next = 4 + first.Count;
var second = GetMembers(map, next);
var second = GetNodes(map, next);
var size = reader.ReadInt32();
var dic = new List<KeyValuePair<object, object>>(size);
for (int j = 0; j < size; j++)
@@ -246,11 +261,11 @@ namespace AssetStudio
}
default:
{
if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array
if (i < m_Nodes.Count - 1 && m_Nodes[i + 1].m_Type == "Array") //Array
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
var vector = GetMembers(members, i);
var vector = GetNodes(m_Nodes, i);
i += vector.Count - 1;
var size = reader.ReadInt32();
var list = new List<object>(size);
@@ -264,9 +279,9 @@ namespace AssetStudio
}
else //Class
{
var @class = GetMembers(members, i);
var @class = GetNodes(m_Nodes, i);
i += @class.Count - 1;
var obj = new UType();
var obj = new OrderedDictionary();
for (int j = 1; j < @class.Count; j++)
{
var classmember = @class[j];
@@ -283,22 +298,22 @@ namespace AssetStudio
return value;
}
private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int index)
private static List<TypeTreeNode> GetNodes(List<TypeTreeNode> m_Nodes, int index)
{
var member2 = new List<TypeTreeNode>();
member2.Add(members[index]);
var level = members[index].m_Level;
for (int i = index + 1; i < members.Count; i++)
var nodes = new List<TypeTreeNode>();
nodes.Add(m_Nodes[index]);
var level = m_Nodes[index].m_Level;
for (int i = index + 1; i < m_Nodes.Count; i++)
{
var member = members[i];
var member = m_Nodes[i];
var level2 = member.m_Level;
if (level2 <= level)
{
return member2;
return nodes;
}
member2.Add(member);
nodes.Add(member);
}
return member2;
return nodes;
}
}
}
+11 -1
View File
@@ -11,12 +11,22 @@ namespace AssetStudio
public string m_Name;
public int m_ByteSize;
public int m_Index;
public int m_IsArray; //m_TypeFlags
public int m_TypeFlags; //m_IsArray
public int m_Version;
public int m_MetaFlag;
public int m_Level;
public uint m_TypeStrOffset;
public uint m_NameStrOffset;
public ulong m_RefTypeHash;
public TypeTreeNode() { }
public TypeTreeNode(string type, string name, int level, bool align)
{
m_Type = type;
m_Name = name;
m_Level = level;
m_MetaFlag = align ? 0x4000 : 0;
}
}
}
-108
View File
@@ -1,108 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AssetStudio
{
public class UType : IDictionary<string, object>
{
private List<string> keys;
private IDictionary<string, object> values;
public UType()
{
keys = new List<string>();
values = new Dictionary<string, object>();
}
public object this[string key]
{
get
{
if (!values.ContainsKey(key))
{
return null;
}
return values[key];
}
set
{
if (!values.ContainsKey(key))
{
keys.Add(key);
}
values[key] = value;
}
}
public ICollection<string> Keys => keys;
public ICollection<object> Values => values.Values;
public int Count => keys.Count;
public bool IsReadOnly => false;
public void Add(string key, object value)
{
keys.Add(key);
values.Add(key, value);
}
public void Add(KeyValuePair<string, object> item)
{
keys.Add(item.Key);
values.Add(item);
}
public void Clear()
{
keys.Clear();
values.Clear();
}
public bool Contains(KeyValuePair<string, object> item)
{
return values.Contains(item);
}
public bool ContainsKey(string key)
{
return values.ContainsKey(key);
}
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
values.CopyTo(array, arrayIndex);
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return values.GetEnumerator();
}
public bool Remove(string key)
{
keys.Remove(key);
return values.Remove(key);
}
public bool Remove(KeyValuePair<string, object> item)
{
keys.Remove(item.Key);
return values.Remove(item);
}
public bool TryGetValue(string key, out object value)
{
return values.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return values.GetEnumerator();
}
}
}
+1
View File
@@ -83,6 +83,7 @@ namespace AssetStudio
{
var data = dataList[i];
var file = new StreamFile();
file.path = data.path;
file.fileName = Path.GetFileName(data.path);
reader.BaseStream.Position = data.dataOffset;
file.stream = new MemoryStream(reader.ReadBytes(data.dataLength));
@@ -98,15 +98,17 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_AS_DLL;FBXSDK_SHARED;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_AS_DLL;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x86\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreSpecificDefaultLibraries>LIBCMT;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -115,16 +117,17 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_AS_DLL;FBXSDK_SHARED;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_AS_DLL;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
@@ -132,15 +135,17 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_AS_DLL;FBXSDK_SHARED;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_AS_DLL;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreSpecificDefaultLibraries>LIBCMT;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -149,16 +154,17 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_AS_DLL;FBXSDK_SHARED;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_AS_DLL;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
+31 -16
View File
@@ -941,22 +941,22 @@ AS_API(int32_t) AsFbxAnimGetCurrentBlendShapeChannelCount(AsFbxAnimContext* pAni
return 0;
}
auto lGeometry = dynamic_cast<FbxGeometry*>(pNode->GetNodeAttribute());
pAnimContext->lGeometry = lGeometry;
auto pMesh = pNode->GetMesh();
pAnimContext->pMesh = pMesh;
if (lGeometry == nullptr)
if (pMesh == nullptr)
{
return 0;
}
auto blendShapeDeformerCount = lGeometry->GetDeformerCount(FbxDeformer::eBlendShape);
auto blendShapeDeformerCount = pMesh->GetDeformerCount(FbxDeformer::eBlendShape);
if (blendShapeDeformerCount <= 0)
{
return 0;
}
auto lBlendShape = dynamic_cast<FbxBlendShape*>(lGeometry->GetDeformer(0, FbxDeformer::eBlendShape));
auto lBlendShape = (FbxBlendShape*)pMesh->GetDeformer(0, FbxDeformer::eBlendShape);
pAnimContext->lBlendShape = lBlendShape;
if (lBlendShape == nullptr)
@@ -991,12 +991,12 @@ AS_API(bool32_t) AsFbxAnimIsBlendShapeChannelMatch(AsFbxAnimContext* pAnimContex
AS_API(void) AsFbxAnimBeginBlendShapeAnimCurve(AsFbxAnimContext* pAnimContext, int32_t channelIndex)
{
if (pAnimContext == nullptr || pAnimContext->lGeometry == nullptr || pAnimContext->lAnimLayer == nullptr)
if (pAnimContext == nullptr || pAnimContext->pMesh == nullptr || pAnimContext->lAnimLayer == nullptr)
{
return;
}
pAnimContext->lAnimCurve = pAnimContext->lGeometry->GetShapeChannel(0, channelIndex, pAnimContext->lAnimLayer, true);
pAnimContext->lAnimCurve = pAnimContext->pMesh->GetShapeChannel(0, channelIndex, pAnimContext->lAnimLayer, true);
pAnimContext->lAnimCurve->KeyModifyBegin();
}
@@ -1093,7 +1093,7 @@ AS_API(void) AsFbxMorphAddBlendShapeChannel(AsFbxContext* pContext, AsFbxMorphCo
}
}
AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, float weight)
AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, float weight, const char* shapeName)
{
if (pContext == nullptr || pContext->pScene == nullptr)
{
@@ -1105,7 +1105,7 @@ AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMo
return;
}
auto lShape = FbxShape::Create(pContext->pScene, FbxString(weight));
auto lShape = FbxShape::Create(pContext->pScene, shapeName);
pMorphContext->lShape = lShape;
if (pMorphContext->lBlendShapeChannel != nullptr) {
@@ -1126,12 +1126,9 @@ AS_API(void) AsFbxMorphCopyBlendShapeControlPoints(AsFbxMorphContext* pMorphCont
pMorphContext->lShape->InitControlPoints(vectorCount);
auto dstControlPoints = pMorphContext->lShape->GetControlPoints();
for (int j = 0; j < vectorCount; j++)
{
auto vertex = srcControlPoints[j];
dstControlPoints[j] = FbxVector4(vertex);
pMorphContext->lShape->SetControlPointAt(FbxVector4(srcControlPoints[j]), j);;
}
}
@@ -1142,7 +1139,25 @@ AS_API(void) AsFbxMorphSetBlendShapeVertex(AsFbxMorphContext* pMorphContext, uin
return;
}
auto pControlPoints = pMorphContext->lShape->GetControlPoints();
pControlPoints[index] = FbxVector4(x, y, z, 0);
pMorphContext->lShape->SetControlPointAt(FbxVector4(x, y, z, 0), index);
}
AS_API(void) AsFbxMorphCopyBlendShapeControlPointsNormal(AsFbxMorphContext* pMorphContext)
{
if (pMorphContext == nullptr || pMorphContext->pMesh == nullptr || pMorphContext->lShape == nullptr)
{
return;
}
pMorphContext->lShape->InitNormals(pMorphContext->pMesh);
}
AS_API(void) AsFbxMorphSetBlendShapeVertexNormal(AsFbxMorphContext* pMorphContext, uint32_t index, float x, float y, float z)
{
if (pMorphContext == nullptr || pMorphContext->lShape == nullptr)
{
return;
}
pMorphContext->lShape->SetControlPointNormalAt(FbxVector4(x, y, z, 0), index);
}
+5 -1
View File
@@ -150,8 +150,12 @@ AS_API(void) AsFbxMorphDisposeContext(AsFbxMorphContext** ppMorphContext);
AS_API(void) AsFbxMorphAddBlendShapeChannel(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, const char* channelName);
AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, float weight);
AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, float weight, const char* shapeName);
AS_API(void) AsFbxMorphCopyBlendShapeControlPoints(AsFbxMorphContext* pMorphContext);
AS_API(void) AsFbxMorphSetBlendShapeVertex(AsFbxMorphContext* pMorphContext, uint32_t index, float x, float y, float z);
AS_API(void) AsFbxMorphCopyBlendShapeControlPointsNormal(AsFbxMorphContext* pMorphContext);
AS_API(void) AsFbxMorphSetBlendShapeVertexNormal(AsFbxMorphContext* pMorphContext, uint32_t index, float x, float y, float z);
+1 -1
View File
@@ -21,7 +21,7 @@ AsFbxAnimContext::AsFbxAnimContext(bool32_t eulerFilter)
lCurveTY = nullptr;
lCurveTZ = nullptr;
lGeometry = nullptr;
pMesh = nullptr;
lBlendShape = nullptr;
lAnimCurve = nullptr;
}
+1 -1
View File
@@ -22,7 +22,7 @@ struct AsFbxAnimContext
FbxAnimCurve* lCurveTY;
FbxAnimCurve* lCurveTZ;
FbxGeometry* lGeometry;
FbxMesh* pMesh;
FbxBlendShape* lBlendShape;
FbxAnimCurve* lAnimCurve;
-12
View File
@@ -4,18 +4,6 @@
#include <string>
#include <unordered_set>
namespace fbxsdk
{
class FbxManager;
class FbxScene;
class FbxExporter;
template<typename T, const int Alignment = 16>
class FbxArray;
class FbxFileTexture;
class FbxSurfacePhong;
class FbxPose;
}
struct AsFbxContext
{
@@ -298,8 +298,16 @@ namespace AssetStudio.FbxInterop
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphAddBlendShapeChannel(IntPtr pContext, IntPtr pMorphContext, IntPtr strChannelName);
private static void AsFbxMorphAddBlendShapeChannelShape(IntPtr pContext, IntPtr pMorphContext, float weight, string shapeName)
{
using (var shapeNameUtf8 = new Utf8StringHandle(shapeName))
{
AsFbxMorphAddBlendShapeChannelShape(pContext, pMorphContext, weight, shapeNameUtf8.DangerousGetHandle());
}
}
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphAddBlendShapeChannelShape(IntPtr pContext, IntPtr pMorphContext, float weight);
private static extern void AsFbxMorphAddBlendShapeChannelShape(IntPtr pContext, IntPtr pMorphContext, float weight, IntPtr strShapeName);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphCopyBlendShapeControlPoints(IntPtr pMorphContext);
@@ -307,5 +315,11 @@ namespace AssetStudio.FbxInterop
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphSetBlendShapeVertex(IntPtr pMorphContext, uint index, float x, float y, float z);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphCopyBlendShapeControlPointsNormal(IntPtr pMorphContext);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphSetBlendShapeVertexNormal(IntPtr pMorphContext, uint index, float x, float y, float z);
}
}
+15 -2
View File
@@ -611,9 +611,11 @@ namespace AssetStudio.FbxInterop
{
AsFbxMorphAddBlendShapeChannel(_pContext, pMorphContext, channel.Name);
foreach (var keyframe in channel.KeyframeList)
for (var i = 0; i < channel.KeyframeList.Count; i++)
{
AsFbxMorphAddBlendShapeChannelShape(_pContext, pMorphContext, keyframe.Weight);
var keyframe = channel.KeyframeList[i];
AsFbxMorphAddBlendShapeChannelShape(_pContext, pMorphContext, keyframe.Weight, i == 0 ? channel.Name : $"{channel.Name}_{i + 1}");
AsFbxMorphCopyBlendShapeControlPoints(pMorphContext);
@@ -622,6 +624,17 @@ namespace AssetStudio.FbxInterop
var v = vertex.Vertex.Vertex;
AsFbxMorphSetBlendShapeVertex(pMorphContext, vertex.Index, v.X, v.Y, v.Z);
}
if (keyframe.hasNormals)
{
AsFbxMorphCopyBlendShapeControlPointsNormal(pMorphContext);
foreach (var vertex in keyframe.VertexList)
{
var v = vertex.Vertex.Normal;
AsFbxMorphSetBlendShapeVertexNormal(pMorphContext, vertex.Index, v.X, v.Y, v.Z);
}
}
}
}
}
+3 -9
View File
@@ -39,6 +39,9 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="OpenTK, Version=3.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>..\packages\OpenTK.3.1.0\lib\net20\OpenTK.dll</HintPath>
</Reference>
@@ -84,7 +87,6 @@
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Studio.cs" />
<Compile Include="TGASharpLib.cs" />
<EmbeddedResource Include="AssetStudioGUIForm.resx">
<DependentUpon>AssetStudioGUIForm.cs</DependentUpon>
</EmbeddedResource>
@@ -127,18 +129,10 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x86\fmod.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x86\libfbxsdk.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x86\libfbxsdk.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x64\fmod.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x64\fmod.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x64\libfbxsdk.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x64\libfbxsdk.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj">
+141 -55
View File
@@ -64,6 +64,11 @@
this.toolStripMenuItem7 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem8 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem9 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.toolStripMenuItem10 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem11 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem13 = new System.Windows.Forms.ToolStripMenuItem();
this.filterTypeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.allToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.debugMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -87,6 +92,8 @@
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.progressbarPanel = new System.Windows.Forms.Panel();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.tabControl2 = new System.Windows.Forms.TabControl();
this.tabPage4 = new System.Windows.Forms.TabPage();
this.previewPanel = new System.Windows.Forms.Panel();
this.assetInfoLabel = new System.Windows.Forms.Label();
this.FMODpanel = new System.Windows.Forms.Panel();
@@ -101,15 +108,15 @@
this.FMODpauseButton = new System.Windows.Forms.Button();
this.FMODplayButton = new System.Windows.Forms.Button();
this.fontPreviewBox = new System.Windows.Forms.RichTextBox();
this.textPreviewBox = new System.Windows.Forms.TextBox();
this.glControl1 = new OpenTK.GLControl();
this.classPreviewPanel = new System.Windows.Forms.Panel();
this.textPreviewBox = new System.Windows.Forms.TextBox();
this.classTextBox = new System.Windows.Forms.TextBox();
this.tabPage5 = new System.Windows.Forms.TabPage();
this.dumpTextBox = new System.Windows.Forms.TextBox();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
this.timer = new System.Windows.Forms.Timer(this.components);
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportSelectedAssetsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -126,11 +133,13 @@
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.progressbarPanel.SuspendLayout();
this.tabControl2.SuspendLayout();
this.tabPage4.SuspendLayout();
this.previewPanel.SuspendLayout();
this.FMODpanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.FMODprogressBar)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.FMODvolumeBar)).BeginInit();
this.classPreviewPanel.SuspendLayout();
this.tabPage5.SuspendLayout();
this.statusStrip1.SuspendLayout();
this.contextMenuStrip1.SuspendLayout();
this.SuspendLayout();
@@ -310,7 +319,9 @@
this.exportAnimatorWithSelectedAnimationClipToolStripMenuItem,
this.toolStripSeparator4,
this.toolStripMenuItem2,
this.toolStripMenuItem3});
this.toolStripMenuItem3,
this.toolStripSeparator2,
this.toolStripMenuItem10});
this.exportToolStripMenuItem.Name = "exportToolStripMenuItem";
this.exportToolStripMenuItem.Size = new System.Drawing.Size(58, 21);
this.exportToolStripMenuItem.Text = "Export";
@@ -415,6 +426,42 @@
this.toolStripMenuItem9.Text = "Filtered assets";
this.toolStripMenuItem9.Click += new System.EventHandler(this.toolStripMenuItem9_Click);
//
// toolStripSeparator2
//
this.toolStripSeparator2.Name = "toolStripSeparator2";
this.toolStripSeparator2.Size = new System.Drawing.Size(396, 6);
//
// toolStripMenuItem10
//
this.toolStripMenuItem10.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripMenuItem11,
this.toolStripMenuItem12,
this.toolStripMenuItem13});
this.toolStripMenuItem10.Name = "toolStripMenuItem10";
this.toolStripMenuItem10.Size = new System.Drawing.Size(399, 34);
this.toolStripMenuItem10.Text = "Asset list to XML";
//
// toolStripMenuItem11
//
this.toolStripMenuItem11.Name = "toolStripMenuItem11";
this.toolStripMenuItem11.Size = new System.Drawing.Size(270, 34);
this.toolStripMenuItem11.Text = "All assets";
this.toolStripMenuItem11.Click += new System.EventHandler(this.toolStripMenuItem11_Click);
//
// toolStripMenuItem12
//
this.toolStripMenuItem12.Name = "toolStripMenuItem12";
this.toolStripMenuItem12.Size = new System.Drawing.Size(270, 34);
this.toolStripMenuItem12.Text = "Selected assets";
this.toolStripMenuItem12.Click += new System.EventHandler(this.toolStripMenuItem12_Click);
//
// toolStripMenuItem13
//
this.toolStripMenuItem13.Name = "toolStripMenuItem13";
this.toolStripMenuItem13.Size = new System.Drawing.Size(270, 34);
this.toolStripMenuItem13.Text = "Filtered assets";
this.toolStripMenuItem13.Click += new System.EventHandler(this.toolStripMenuItem13_Click);
//
// filterTypeToolStripMenuItem
//
this.filterTypeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -463,8 +510,7 @@
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.previewPanel);
this.splitContainer1.Panel2.Controls.Add(this.classPreviewPanel);
this.splitContainer1.Panel2.Controls.Add(this.tabControl2);
this.splitContainer1.Panel2.Controls.Add(this.statusStrip1);
this.splitContainer1.Panel2MinSize = 400;
this.splitContainer1.Size = new System.Drawing.Size(1264, 656);
@@ -653,6 +699,28 @@
this.progressBar1.Step = 1;
this.progressBar1.TabIndex = 1;
//
// tabControl2
//
this.tabControl2.Controls.Add(this.tabPage4);
this.tabControl2.Controls.Add(this.tabPage5);
this.tabControl2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl2.Location = new System.Drawing.Point(0, 0);
this.tabControl2.Name = "tabControl2";
this.tabControl2.SelectedIndex = 0;
this.tabControl2.Size = new System.Drawing.Size(776, 632);
this.tabControl2.TabIndex = 4;
this.tabControl2.SelectedIndexChanged += new System.EventHandler(this.tabControl2_SelectedIndexChanged);
//
// tabPage4
//
this.tabPage4.Controls.Add(this.previewPanel);
this.tabPage4.Location = new System.Drawing.Point(4, 22);
this.tabPage4.Name = "tabPage4";
this.tabPage4.Size = new System.Drawing.Size(768, 606);
this.tabPage4.TabIndex = 0;
this.tabPage4.Text = "Preview";
this.tabPage4.UseVisualStyleBackColor = true;
//
// previewPanel
//
this.previewPanel.BackColor = System.Drawing.SystemColors.ControlDark;
@@ -661,12 +729,13 @@
this.previewPanel.Controls.Add(this.assetInfoLabel);
this.previewPanel.Controls.Add(this.FMODpanel);
this.previewPanel.Controls.Add(this.fontPreviewBox);
this.previewPanel.Controls.Add(this.textPreviewBox);
this.previewPanel.Controls.Add(this.glControl1);
this.previewPanel.Controls.Add(this.textPreviewBox);
this.previewPanel.Controls.Add(this.classTextBox);
this.previewPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.previewPanel.Location = new System.Drawing.Point(0, 0);
this.previewPanel.Name = "previewPanel";
this.previewPanel.Size = new System.Drawing.Size(776, 632);
this.previewPanel.Size = new System.Drawing.Size(768, 606);
this.previewPanel.TabIndex = 1;
this.previewPanel.Resize += new System.EventHandler(this.preview_Resize);
//
@@ -696,7 +765,7 @@
this.FMODpanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.FMODpanel.Location = new System.Drawing.Point(0, 0);
this.FMODpanel.Name = "FMODpanel";
this.FMODpanel.Size = new System.Drawing.Size(776, 632);
this.FMODpanel.Size = new System.Drawing.Size(768, 606);
this.FMODpanel.TabIndex = 2;
this.FMODpanel.Visible = false;
//
@@ -704,7 +773,7 @@
//
this.FMODcopyright.AutoSize = true;
this.FMODcopyright.ForeColor = System.Drawing.SystemColors.ControlLight;
this.FMODcopyright.Location = new System.Drawing.Point(232, 350);
this.FMODcopyright.Location = new System.Drawing.Point(214, 337);
this.FMODcopyright.Name = "FMODcopyright";
this.FMODcopyright.Size = new System.Drawing.Size(341, 12);
this.FMODcopyright.TabIndex = 9;
@@ -714,7 +783,7 @@
//
this.FMODinfoLabel.AutoSize = true;
this.FMODinfoLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.FMODinfoLabel.Location = new System.Drawing.Point(287, 248);
this.FMODinfoLabel.Location = new System.Drawing.Point(269, 235);
this.FMODinfoLabel.Name = "FMODinfoLabel";
this.FMODinfoLabel.Size = new System.Drawing.Size(0, 12);
this.FMODinfoLabel.TabIndex = 8;
@@ -722,7 +791,7 @@
// FMODtimerLabel
//
this.FMODtimerLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.FMODtimerLabel.Location = new System.Drawing.Point(422, 248);
this.FMODtimerLabel.Location = new System.Drawing.Point(404, 235);
this.FMODtimerLabel.Name = "FMODtimerLabel";
this.FMODtimerLabel.Size = new System.Drawing.Size(155, 12);
this.FMODtimerLabel.TabIndex = 7;
@@ -732,7 +801,7 @@
// FMODstatusLabel
//
this.FMODstatusLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.FMODstatusLabel.Location = new System.Drawing.Point(231, 248);
this.FMODstatusLabel.Location = new System.Drawing.Point(213, 235);
this.FMODstatusLabel.Name = "FMODstatusLabel";
this.FMODstatusLabel.Size = new System.Drawing.Size(50, 12);
this.FMODstatusLabel.TabIndex = 6;
@@ -741,7 +810,7 @@
// FMODprogressBar
//
this.FMODprogressBar.AutoSize = false;
this.FMODprogressBar.Location = new System.Drawing.Point(231, 266);
this.FMODprogressBar.Location = new System.Drawing.Point(213, 253);
this.FMODprogressBar.Maximum = 1000;
this.FMODprogressBar.Name = "FMODprogressBar";
this.FMODprogressBar.Size = new System.Drawing.Size(350, 22);
@@ -754,7 +823,7 @@
// FMODvolumeBar
//
this.FMODvolumeBar.LargeChange = 2;
this.FMODvolumeBar.Location = new System.Drawing.Point(478, 293);
this.FMODvolumeBar.Location = new System.Drawing.Point(460, 280);
this.FMODvolumeBar.Name = "FMODvolumeBar";
this.FMODvolumeBar.Size = new System.Drawing.Size(104, 45);
this.FMODvolumeBar.TabIndex = 4;
@@ -765,7 +834,7 @@
// FMODloopButton
//
this.FMODloopButton.Appearance = System.Windows.Forms.Appearance.Button;
this.FMODloopButton.Location = new System.Drawing.Point(417, 293);
this.FMODloopButton.Location = new System.Drawing.Point(399, 280);
this.FMODloopButton.Name = "FMODloopButton";
this.FMODloopButton.Size = new System.Drawing.Size(55, 42);
this.FMODloopButton.TabIndex = 3;
@@ -776,7 +845,7 @@
//
// FMODstopButton
//
this.FMODstopButton.Location = new System.Drawing.Point(356, 293);
this.FMODstopButton.Location = new System.Drawing.Point(338, 280);
this.FMODstopButton.Name = "FMODstopButton";
this.FMODstopButton.Size = new System.Drawing.Size(55, 42);
this.FMODstopButton.TabIndex = 2;
@@ -786,7 +855,7 @@
//
// FMODpauseButton
//
this.FMODpauseButton.Location = new System.Drawing.Point(295, 293);
this.FMODpauseButton.Location = new System.Drawing.Point(277, 280);
this.FMODpauseButton.Name = "FMODpauseButton";
this.FMODpauseButton.Size = new System.Drawing.Size(55, 42);
this.FMODpauseButton.TabIndex = 1;
@@ -796,7 +865,7 @@
//
// FMODplayButton
//
this.FMODplayButton.Location = new System.Drawing.Point(234, 293);
this.FMODplayButton.Location = new System.Drawing.Point(216, 280);
this.FMODplayButton.Name = "FMODplayButton";
this.FMODplayButton.Size = new System.Drawing.Size(55, 42);
this.FMODplayButton.TabIndex = 0;
@@ -811,33 +880,19 @@
this.fontPreviewBox.Location = new System.Drawing.Point(0, 0);
this.fontPreviewBox.Name = "fontPreviewBox";
this.fontPreviewBox.ReadOnly = true;
this.fontPreviewBox.Size = new System.Drawing.Size(776, 632);
this.fontPreviewBox.Size = new System.Drawing.Size(768, 606);
this.fontPreviewBox.TabIndex = 0;
this.fontPreviewBox.Text = resources.GetString("fontPreviewBox.Text");
this.fontPreviewBox.Visible = false;
this.fontPreviewBox.WordWrap = false;
//
// textPreviewBox
//
this.textPreviewBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.textPreviewBox.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.textPreviewBox.Location = new System.Drawing.Point(0, 0);
this.textPreviewBox.Multiline = true;
this.textPreviewBox.Name = "textPreviewBox";
this.textPreviewBox.ReadOnly = true;
this.textPreviewBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textPreviewBox.Size = new System.Drawing.Size(776, 632);
this.textPreviewBox.TabIndex = 2;
this.textPreviewBox.Visible = false;
this.textPreviewBox.WordWrap = false;
//
// glControl1
//
this.glControl1.BackColor = System.Drawing.SystemColors.ControlDarkDark;
this.glControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.glControl1.Location = new System.Drawing.Point(0, 0);
this.glControl1.Name = "glControl1";
this.glControl1.Size = new System.Drawing.Size(776, 632);
this.glControl1.Size = new System.Drawing.Size(768, 606);
this.glControl1.TabIndex = 4;
this.glControl1.Visible = false;
this.glControl1.VSync = false;
@@ -848,15 +903,19 @@
this.glControl1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseUp);
this.glControl1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseWheel);
//
// classPreviewPanel
// textPreviewBox
//
this.classPreviewPanel.Controls.Add(this.classTextBox);
this.classPreviewPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.classPreviewPanel.Location = new System.Drawing.Point(0, 0);
this.classPreviewPanel.Name = "classPreviewPanel";
this.classPreviewPanel.Size = new System.Drawing.Size(776, 632);
this.classPreviewPanel.TabIndex = 3;
this.classPreviewPanel.Visible = false;
this.textPreviewBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.textPreviewBox.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.textPreviewBox.Location = new System.Drawing.Point(0, 0);
this.textPreviewBox.Multiline = true;
this.textPreviewBox.Name = "textPreviewBox";
this.textPreviewBox.ReadOnly = true;
this.textPreviewBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textPreviewBox.Size = new System.Drawing.Size(768, 606);
this.textPreviewBox.TabIndex = 2;
this.textPreviewBox.Visible = false;
this.textPreviewBox.WordWrap = false;
//
// classTextBox
//
@@ -866,10 +925,33 @@
this.classTextBox.Name = "classTextBox";
this.classTextBox.ReadOnly = true;
this.classTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.classTextBox.Size = new System.Drawing.Size(776, 632);
this.classTextBox.Size = new System.Drawing.Size(768, 606);
this.classTextBox.TabIndex = 3;
this.classTextBox.Visible = false;
this.classTextBox.WordWrap = false;
//
// tabPage5
//
this.tabPage5.Controls.Add(this.dumpTextBox);
this.tabPage5.Location = new System.Drawing.Point(4, 22);
this.tabPage5.Name = "tabPage5";
this.tabPage5.Size = new System.Drawing.Size(768, 606);
this.tabPage5.TabIndex = 1;
this.tabPage5.Text = "Dump";
this.tabPage5.UseVisualStyleBackColor = true;
//
// dumpTextBox
//
this.dumpTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.dumpTextBox.Location = new System.Drawing.Point(0, 0);
this.dumpTextBox.Multiline = true;
this.dumpTextBox.Name = "dumpTextBox";
this.dumpTextBox.ReadOnly = true;
this.dumpTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.dumpTextBox.Size = new System.Drawing.Size(768, 606);
this.dumpTextBox.TabIndex = 0;
this.dumpTextBox.WordWrap = false;
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -901,11 +983,6 @@
this.openFileDialog1.Multiselect = true;
this.openFileDialog1.RestoreDirectory = true;
//
// saveFileDialog1
//
this.saveFileDialog1.Filter = "FBX file|*.fbx";
this.saveFileDialog1.RestoreDirectory = true;
//
// contextMenuStrip1
//
this.contextMenuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
@@ -922,7 +999,7 @@
//
this.copyToolStripMenuItem.Name = "copyToolStripMenuItem";
this.copyToolStripMenuItem.Size = new System.Drawing.Size(326, 22);
this.copyToolStripMenuItem.Text = "Copy";
this.copyToolStripMenuItem.Text = "Copy text";
this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click);
//
// exportSelectedAssetsToolStripMenuItem
@@ -988,14 +1065,16 @@
this.tabPage2.PerformLayout();
this.tabPage3.ResumeLayout(false);
this.progressbarPanel.ResumeLayout(false);
this.tabControl2.ResumeLayout(false);
this.tabPage4.ResumeLayout(false);
this.previewPanel.ResumeLayout(false);
this.previewPanel.PerformLayout();
this.FMODpanel.ResumeLayout(false);
this.FMODpanel.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.FMODprogressBar)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.FMODvolumeBar)).EndInit();
this.classPreviewPanel.ResumeLayout(false);
this.classPreviewPanel.PerformLayout();
this.tabPage5.ResumeLayout(false);
this.tabPage5.PerformLayout();
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
this.contextMenuStrip1.ResumeLayout(false);
@@ -1052,7 +1131,6 @@
private System.Windows.Forms.ToolStripMenuItem extractFileToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem extractFolderToolStripMenuItem;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.SaveFileDialog saveFileDialog1;
private System.Windows.Forms.ToolStripMenuItem showExpOpt;
private GOHierarchy sceneTreeView;
private System.Windows.Forms.ToolStripMenuItem debugMenuItem;
@@ -1060,7 +1138,6 @@
private System.Windows.Forms.ListView classesListView;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.Panel classPreviewPanel;
private System.Windows.Forms.TextBox classTextBox;
private System.Windows.Forms.ToolStripMenuItem exportClassStructuresMenuItem;
private System.Windows.Forms.Label FMODcopyright;
@@ -1092,6 +1169,15 @@
private System.Windows.Forms.ColumnHeader columnHeaderContainer;
private System.Windows.Forms.ColumnHeader columnHeaderPathID;
private System.Windows.Forms.ToolStripMenuItem copyToolStripMenuItem;
private System.Windows.Forms.TabControl tabControl2;
private System.Windows.Forms.TabPage tabPage4;
private System.Windows.Forms.TabPage tabPage5;
private System.Windows.Forms.TextBox dumpTextBox;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem10;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem11;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem12;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem13;
}
}
+157 -75
View File
@@ -1,4 +1,5 @@
using AssetStudio;
using Newtonsoft.Json;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System;
@@ -27,7 +28,6 @@ namespace AssetStudioGUI
partial class AssetStudioGUIForm : Form
{
private AssetItem lastSelectedItem;
private AssetItem lastLoadedAsset;
private Bitmap imageTexture;
private string tempClipboard;
@@ -150,21 +150,36 @@ namespace AssetStudioGUI
}
}
private void extractFileToolStripMenuItem_Click(object sender, EventArgs e)
private async void extractFileToolStripMenuItem_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
ExtractFile(openFileDialog1.FileNames);
var saveFolderDialog = new OpenFolderDialog();
saveFolderDialog.Title = "Select the save folder";
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
{
var fileNames = openFileDialog1.FileNames;
var savePath = saveFolderDialog.Folder;
var extractedCount = await Task.Run(() => ExtractFile(fileNames, savePath));
StatusStripUpdate($"Finished extracting {extractedCount} files.");
}
}
}
private void extractFolderToolStripMenuItem_Click(object sender, EventArgs e)
private async void extractFolderToolStripMenuItem_Click(object sender, EventArgs e)
{
var openFolderDialog1 = new OpenFolderDialog();
if (openFolderDialog1.ShowDialog(this) == DialogResult.OK)
var openFolderDialog = new OpenFolderDialog();
if (openFolderDialog.ShowDialog(this) == DialogResult.OK)
{
var files = Directory.GetFiles(openFolderDialog1.Folder, "*.*", SearchOption.AllDirectories);
ExtractFile(files);
var saveFolderDialog = new OpenFolderDialog();
saveFolderDialog.Title = "Select the save folder";
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
{
var path = openFolderDialog.Folder;
var savePath = saveFolderDialog.Folder;
var extractedCount = await Task.Run(() => ExtractFolder(path, savePath));
StatusStripUpdate($"Finished extracting {extractedCount} files.");
}
}
}
@@ -287,31 +302,31 @@ namespace AssetStudioGUI
{
if (e.Control)
{
bool dirty = false;
var need = false;
switch (e.KeyCode)
{
case Keys.B:
textureChannels[0] = !textureChannels[0];
dirty = true;
need = true;
break;
case Keys.G:
textureChannels[1] = !textureChannels[1];
dirty = true;
need = true;
break;
case Keys.R:
textureChannels[2] = !textureChannels[2];
dirty = true;
need = true;
break;
case Keys.A:
textureChannels[3] = !textureChannels[3];
dirty = true;
need = true;
break;
}
if (dirty)
if (need)
{
PreviewAsset(lastLoadedAsset);
if (lastSelectedItem != null && assetInfoLabel.Text != null)
if (lastSelectedItem != null)
{
PreviewAsset(lastSelectedItem);
assetInfoLabel.Text = lastSelectedItem.InfoText;
}
}
@@ -332,7 +347,7 @@ namespace AssetStudioGUI
Progress.Reset();
foreach (TypeTreeItem item in classesListView.Items)
{
var versionPath = savePath + "\\" + item.Group.Header;
var versionPath = Path.Combine(savePath, item.Group.Header);
Directory.CreateDirectory(versionPath);
var saveFile = $"{versionPath}\\{item.SubItems[1].Text} {item.Text}.txt";
@@ -354,9 +369,9 @@ namespace AssetStudioGUI
private void enablePreview_Check(object sender, EventArgs e)
{
if (lastLoadedAsset != null)
if (lastSelectedItem != null)
{
switch (lastLoadedAsset.Type)
switch (lastSelectedItem.Type)
{
case ClassIDType.Texture2D:
case ClassIDType.Sprite:
@@ -395,7 +410,7 @@ namespace AssetStudioGUI
}
else if (FMODpanel.Visible)
{
PreviewAsset(lastLoadedAsset);
PreviewAsset(lastSelectedItem);
}
break;
@@ -406,8 +421,7 @@ namespace AssetStudioGUI
}
else if (lastSelectedItem != null && enablePreview.Checked)
{
lastLoadedAsset = lastSelectedItem;
PreviewAsset(lastLoadedAsset);
PreviewAsset(lastSelectedItem);
}
Properties.Settings.Default.enablePreview = enablePreview.Checked;
@@ -448,14 +462,8 @@ namespace AssetStudioGUI
treeSearch.Select();
break;
case 1:
classPreviewPanel.Visible = false;
previewPanel.Visible = true;
listSearch.Select();
break;
case 2:
previewPanel.Visible = false;
classPreviewPanel.Visible = true;
break;
}
}
@@ -617,13 +625,13 @@ namespace AssetStudioGUI
{
previewPanel.BackgroundImage = Properties.Resources.preview;
previewPanel.BackgroundImageLayout = ImageLayout.Center;
classTextBox.Visible = false;
assetInfoLabel.Visible = false;
assetInfoLabel.Text = null;
textPreviewBox.Visible = false;
fontPreviewBox.Visible = false;
FMODpanel.Visible = false;
glControl1.Visible = false;
lastLoadedAsset = null;
StatusStripUpdate("");
FMODreset();
@@ -632,21 +640,32 @@ namespace AssetStudioGUI
if (e.IsSelected)
{
if (tabControl2.SelectedIndex == 1)
{
dumpTextBox.Text = DumpAsset(lastSelectedItem.Asset);
}
if (enablePreview.Checked)
{
lastLoadedAsset = lastSelectedItem;
PreviewAsset(lastLoadedAsset);
}
if (displayInfo.Checked && assetInfoLabel.Text != null)//only display the label if asset has info text
{
assetInfoLabel.Text = lastSelectedItem.InfoText;
assetInfoLabel.Visible = true;
PreviewAsset(lastSelectedItem);
if (displayInfo.Checked && lastSelectedItem.InfoText != null)
{
assetInfoLabel.Text = lastSelectedItem.InfoText;
assetInfoLabel.Visible = true;
}
}
}
}
private void classesListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
classTextBox.Visible = true;
assetInfoLabel.Visible = false;
assetInfoLabel.Text = null;
textPreviewBox.Visible = false;
fontPreviewBox.Visible = false;
FMODpanel.Visible = false;
glControl1.Visible = false;
StatusStripUpdate("");
if (e.IsSelected)
{
classTextBox.Text = ((TypeTreeItem)classesListView.SelectedItems[0]).ToString();
@@ -880,10 +899,15 @@ namespace AssetStudioGUI
var result = system.createSound(m_AudioData, FMOD.MODE.OPENMEMORY | loopMode, ref exinfo, out sound);
if (ERRCHECK(result)) return;
result = sound.getSubSound(0, out var subsound);
if (result == FMOD.RESULT.OK)
sound.getNumSubSounds(out var numsubsounds);
if (numsubsounds > 0)
{
sound = subsound;
result = sound.getSubSound(0, out var subsound);
if (result == FMOD.RESULT.OK)
{
sound = subsound;
}
}
result = sound.getLength(out FMODlenms, FMOD.TIMEUNIT.MS);
@@ -910,12 +934,20 @@ namespace AssetStudioGUI
private void PreviewTextAsset(TextAsset m_TextAsset)
{
var text = Encoding.UTF8.GetString(m_TextAsset.m_Script);
PreviewText(text.Replace("\n", "\r\n"));
text = text.Replace("\n", "\r\n").Replace("\0", "");
PreviewText(text);
}
private void PreviewMonoBehaviour(MonoBehaviour m_MonoBehaviour)
{
PreviewText(m_MonoBehaviour.Dump() ?? GetScriptString(m_MonoBehaviour.reader));
var obj = m_MonoBehaviour.ToType();
if (obj == null)
{
var type = MonoBehaviourToTypeTree(m_MonoBehaviour);
obj = m_MonoBehaviour.ToType(type);
}
var str = JsonConvert.SerializeObject(obj, Formatting.Indented);
PreviewText(str);
}
private void PreviewFont(Font m_Font)
@@ -1177,6 +1209,7 @@ namespace AssetStudioGUI
{
Text = $"AssetStudioGUI v{Application.ProductVersion}";
assetsManager.Clear();
assemblyLoader.Clear();
exportableAssets.Clear();
visibleAssets.Clear();
sceneTreeView.Nodes.Clear();
@@ -1193,7 +1226,6 @@ namespace AssetStudioGUI
fontPreviewBox.Visible = false;
glControl1.Visible = false;
lastSelectedItem = null;
lastLoadedAsset = null;
sortColumn = -1;
reverseSort = false;
enableFiltering = false;
@@ -1206,12 +1238,6 @@ namespace AssetStudioGUI
}
FMODreset();
if (scriptDumper != null)
{
scriptDumper.Dispose();
scriptDumper = null;
}
}
private void assetListView_MouseClick(object sender, MouseEventArgs e)
@@ -1248,7 +1274,7 @@ namespace AssetStudioGUI
private void exportSelectedAssetsToolStripMenuItem_Click(object sender, EventArgs e)
{
ExportAssets(2, ExportType.Convert);
ExportAssets(ExportFilter.Selected, ExportType.Convert);
}
private void showOriginalFileToolStripMenuItem_Click(object sender, EventArgs e)
@@ -1278,10 +1304,10 @@ namespace AssetStudioGUI
if (animator != null)
{
var saveFolderDialog1 = new OpenFolderDialog();
if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK)
var saveFolderDialog = new OpenFolderDialog();
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
{
var exportPath = saveFolderDialog1.Folder + "\\Animator\\";
var exportPath = saveFolderDialog.Folder + "\\Animator\\";
ExportAnimatorWithAnimationClip(animator, animationList, exportPath);
}
}
@@ -1301,10 +1327,10 @@ namespace AssetStudioGUI
{
if (sceneTreeView.Nodes.Count > 0)
{
var saveFolderDialog1 = new OpenFolderDialog();
if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK)
var saveFolderDialog = new OpenFolderDialog();
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
{
var exportPath = saveFolderDialog1.Folder + "\\GameObject\\";
var exportPath = saveFolderDialog.Folder + "\\GameObject\\";
List<AssetItem> animationList = null;
if (animation)
{
@@ -1372,57 +1398,72 @@ namespace AssetStudioGUI
private void exportAllAssetsMenuItem_Click(object sender, EventArgs e)
{
ExportAssets(1, ExportType.Convert);
ExportAssets(ExportFilter.All, ExportType.Convert);
}
private void exportSelectedAssetsMenuItem_Click(object sender, EventArgs e)
{
ExportAssets(2, ExportType.Convert);
ExportAssets(ExportFilter.Selected, ExportType.Convert);
}
private void exportFilteredAssetsMenuItem_Click(object sender, EventArgs e)
{
ExportAssets(3, ExportType.Convert);
ExportAssets(ExportFilter.Filtered, ExportType.Convert);
}
private void toolStripMenuItem4_Click(object sender, EventArgs e)
{
ExportAssets(1, ExportType.Raw);
ExportAssets(ExportFilter.All, ExportType.Raw);
}
private void toolStripMenuItem5_Click(object sender, EventArgs e)
{
ExportAssets(2, ExportType.Raw);
ExportAssets(ExportFilter.Selected, ExportType.Raw);
}
private void toolStripMenuItem6_Click(object sender, EventArgs e)
{
ExportAssets(3, ExportType.Raw);
ExportAssets(ExportFilter.Filtered, ExportType.Raw);
}
private void toolStripMenuItem7_Click(object sender, EventArgs e)
{
ExportAssets(1, ExportType.Dump);
ExportAssets(ExportFilter.All, ExportType.Dump);
}
private void toolStripMenuItem8_Click(object sender, EventArgs e)
{
ExportAssets(2, ExportType.Dump);
ExportAssets(ExportFilter.Selected, ExportType.Dump);
}
private void toolStripMenuItem9_Click(object sender, EventArgs e)
{
ExportAssets(3, ExportType.Dump);
ExportAssets(ExportFilter.Filtered, ExportType.Dump);
}
private void toolStripMenuItem11_Click(object sender, EventArgs e)
{
ExportAssetsList(ExportFilter.All);
}
private void toolStripMenuItem12_Click(object sender, EventArgs e)
{
ExportAssetsList(ExportFilter.Selected);
}
private void toolStripMenuItem13_Click(object sender, EventArgs e)
{
ExportAssetsList(ExportFilter.Filtered);
}
private void exportAllObjectssplitToolStripMenuItem1_Click(object sender, EventArgs e)
{
if (sceneTreeView.Nodes.Count > 0)
{
var saveFolderDialog1 = new OpenFolderDialog();
if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK)
var saveFolderDialog = new OpenFolderDialog();
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
{
var savePath = saveFolderDialog1.Folder + "\\";
var savePath = saveFolderDialog.Folder + Path.DirectorySeparatorChar;
ExportSplitObjects(savePath, sceneTreeView.Nodes);
}
}
@@ -1475,29 +1516,62 @@ namespace AssetStudioGUI
assetListView.EndUpdate();
}
private void ExportAssets(int type, ExportType exportType)
private void ExportAssets(ExportFilter type, ExportType exportType)
{
if (exportableAssets.Count > 0)
{
var saveFolderDialog1 = new OpenFolderDialog();
if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK)
var saveFolderDialog = new OpenFolderDialog();
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
{
timer.Stop();
List<AssetItem> toExportAssets = null;
switch (type)
{
case 1: //All Assets
case ExportFilter.All:
toExportAssets = exportableAssets;
break;
case 2: //Selected Assets
case ExportFilter.Selected:
toExportAssets = GetSelectedAssets();
break;
case 3: //Filtered Assets
case ExportFilter.Filtered:
toExportAssets = visibleAssets;
break;
}
Studio.ExportAssets(saveFolderDialog1.Folder, toExportAssets, exportType);
Studio.ExportAssets(saveFolderDialog.Folder, toExportAssets, exportType);
}
}
else
{
StatusStripUpdate("No exportable assets loaded");
}
}
private void ExportAssetsList(ExportFilter type)
{
// XXX: Only exporting as XML for now, but would JSON(/CSV/other) be useful too?
if (exportableAssets.Count > 0)
{
var saveFolderDialog = new OpenFolderDialog();
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
{
timer.Stop();
List<AssetItem> toExportAssets = null;
switch (type)
{
case ExportFilter.All:
toExportAssets = exportableAssets;
break;
case ExportFilter.Selected:
toExportAssets = GetSelectedAssets();
break;
case ExportFilter.Filtered:
toExportAssets = visibleAssets;
break;
}
Studio.ExportAssetsList(saveFolderDialog.Folder, toExportAssets, ExportListType.XML);
}
}
else
@@ -1522,7 +1596,7 @@ namespace AssetStudioGUI
Application.Exit();
}
result = system.init(1, FMOD.INITFLAGS.NORMAL, IntPtr.Zero);
result = system.init(2, FMOD.INITFLAGS.NORMAL, IntPtr.Zero);
if (ERRCHECK(result)) { return; }
result = system.getMasterSoundGroup(out masterSoundGroup);
@@ -1934,6 +2008,14 @@ namespace AssetStudioGUI
glControl1.SwapBuffers();
}
private void tabControl2_SelectedIndexChanged(object sender, EventArgs e)
{
if (tabControl2.SelectedIndex == 1 && lastSelectedItem != null)
{
dumpTextBox.Text = DumpAsset(lastSelectedItem.Asset);
}
}
private void glControl1_MouseWheel(object sender, MouseEventArgs e)
{
if (glControl1.Visible)
+3 -6
View File
@@ -120,9 +120,6 @@
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>312, 17</value>
</metadata>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>432, 17</value>
</metadata>
<data name="fontPreviewBox.Text" xml:space="preserve">
<value>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ
1234567890.:,;'\"(!?)+-*/=
@@ -141,15 +138,15 @@ The quick brown fox jumps over the lazy dog. 1234567890
The quick brown fox jumps over the lazy dog. 1234567890</value>
</data>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>432, 17</value>
</metadata>
<metadata name="timer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>553, 17</value>
</metadata>
<metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>636, 17</value>
</metadata>
<metadata name="saveFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>784, 17</value>
</metadata>
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>147, 17</value>
</metadata>
+5 -5
View File
@@ -7,19 +7,19 @@ namespace AssetStudioGUI
{
internal class TypeTreeItem : ListViewItem
{
private List<TypeTreeNode> m_Nodes;
private TypeTree m_Type;
public TypeTreeItem(int typeID, List<TypeTreeNode> m_Nodes)
public TypeTreeItem(int typeID, TypeTree m_Type)
{
this.m_Nodes = m_Nodes;
Text = m_Nodes[0].m_Type + " " + m_Nodes[0].m_Name;
this.m_Type = m_Type;
Text = m_Type.m_Nodes[0].m_Type + " " + m_Type.m_Nodes[0].m_Name;
SubItems.Add(typeID.ToString());
}
public override string ToString()
{
var sb = new StringBuilder();
foreach (var i in m_Nodes)
foreach (var i in m_Type.m_Nodes)
{
sb.AppendFormat("{0}{1} {2} {3} {4}\r\n", new string('\t', i.m_Level), i.m_Type, i.m_Name, i.m_ByteSize, (i.m_MetaFlag & 0x4000) != 0);
}
+82 -68
View File
@@ -4,13 +4,14 @@ using System.IO;
using System.Linq;
using System.Text;
using AssetStudio;
using Newtonsoft.Json;
using TGASharpLib;
namespace AssetStudioGUI
{
internal static class Exporter
{
public static bool ExportTexture2D(AssetItem item, string exportPathName)
public static bool ExportTexture2D(AssetItem item, string exportPath)
{
var m_Texture2D = (Texture2D)item.Asset;
if (Properties.Settings.Default.convertTexture)
@@ -36,25 +37,25 @@ namespace AssetStudioGUI
tga = true;
break;
}
var exportFullName = exportPathName + item.Text + "." + ext.ToLower();
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, "." + ext.ToLower(), out var exportFullPath))
return false;
if (tga)
{
var file = new TGA(bitmap);
file.Save(exportFullName);
file.Save(exportFullPath);
}
else
bitmap.Save(exportFullName, format);
{
bitmap.Save(exportFullPath, format);
}
bitmap.Dispose();
return true;
}
else
{
var exportFullName = exportPathName + item.Text + ".tex";
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullName, m_Texture2D.image_data.GetData());
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
return true;
}
}
@@ -68,44 +69,29 @@ namespace AssetStudioGUI
var converter = new AudioClipConverter(m_AudioClip);
if (Properties.Settings.Default.convertAudio && converter.IsSupport)
{
var exportFullName = exportPath + item.Text + ".wav";
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, ".wav", out var exportFullPath))
return false;
var buffer = converter.ConvertToWav();
if (buffer == null)
return false;
File.WriteAllBytes(exportFullName, buffer);
File.WriteAllBytes(exportFullPath, buffer);
}
else
{
var exportFullName = exportPath + item.Text + converter.GetExtensionName();
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, converter.GetExtensionName(), out var exportFullPath))
return false;
File.WriteAllBytes(exportFullName, m_AudioData);
File.WriteAllBytes(exportFullPath, m_AudioData);
}
return true;
}
public static bool ExportShader(AssetItem item, string exportPath)
{
var exportFullName = exportPath + item.Text + ".shader";
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, ".shader", out var exportFullPath))
return false;
var m_Shader = (Shader)item.Asset;
if (m_Shader.compressedBlob != null) //5.5 and up
{
var strs = ShaderConverter.ConvertMultiple(m_Shader);
for (int i = 0; i < strs.Length; i++)
{
var platformName = ShaderConverter.GetPlatformString(m_Shader.platforms[i]);
File.WriteAllText($"{exportPath}{item.Text}_{platformName}.shader", strs[i]);
}
}
else
{
var str = ShaderConverter.Convert(m_Shader);
File.WriteAllText(exportFullName, str);
}
var str = m_Shader.Convert();
File.WriteAllText(exportFullPath, str);
return true;
}
@@ -120,21 +106,25 @@ namespace AssetStudioGUI
extension = Path.GetExtension(item.Container);
}
}
var exportFullName = exportPath + item.Text + extension;
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
return false;
File.WriteAllBytes(exportFullName, m_TextAsset.m_Script);
File.WriteAllBytes(exportFullPath, m_TextAsset.m_Script);
return true;
}
public static bool ExportMonoBehaviour(AssetItem item, string exportPath)
{
var exportFullName = exportPath + item.Text + ".txt";
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
return false;
var m_MonoBehaviour = (MonoBehaviour)item.Asset;
var str = m_MonoBehaviour.Dump() ?? Studio.GetScriptString(item.Asset.reader);
File.WriteAllText(exportFullName, str);
var type = m_MonoBehaviour.ToType();
if (type == null)
{
var m_Type = Studio.MonoBehaviourToTypeTree(m_MonoBehaviour);
type = m_MonoBehaviour.ToType(m_Type);
}
var str = JsonConvert.SerializeObject(type, Formatting.Indented);
File.WriteAllText(exportFullPath, str);
return true;
}
@@ -148,10 +138,9 @@ namespace AssetStudioGUI
{
extension = ".otf";
}
var exportFullName = exportPath + item.Text + extension;
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
return false;
File.WriteAllBytes(exportFullName, m_Font.m_FontData);
File.WriteAllBytes(exportFullPath, m_Font.m_FontData);
return true;
}
return false;
@@ -162,8 +151,7 @@ namespace AssetStudioGUI
var m_Mesh = (Mesh)item.Asset;
if (m_Mesh.m_VertexCount <= 0)
return false;
var exportFullName = exportPath + item.Text + ".obj";
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, ".obj", out var exportFullPath))
return false;
var sb = new StringBuilder();
sb.AppendLine("g " + m_Mesh.m_Name);
@@ -235,7 +223,7 @@ namespace AssetStudioGUI
#endregion
sb.Replace("NaN", "0");
File.WriteAllText(exportFullName, sb.ToString());
File.WriteAllText(exportFullPath, sb.ToString());
return true;
}
@@ -245,10 +233,9 @@ namespace AssetStudioGUI
var m_VideoData = m_VideoClip.m_VideoData.GetData();
if (m_VideoData != null && m_VideoData.Length != 0)
{
var exportFullName = exportPath + item.Text + Path.GetExtension(m_VideoClip.m_OriginalPath);
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, Path.GetExtension(m_VideoClip.m_OriginalPath), out var exportFullPath))
return false;
File.WriteAllBytes(exportFullName, m_VideoData);
File.WriteAllBytes(exportFullPath, m_VideoData);
return true;
}
return false;
@@ -257,10 +244,9 @@ namespace AssetStudioGUI
public static bool ExportMovieTexture(AssetItem item, string exportPath)
{
var m_MovieTexture = (MovieTexture)item.Asset;
var exportFullName = exportPath + item.Text + ".ogv";
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, ".ogv", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullName, m_MovieTexture.m_MovieData);
File.WriteAllBytes(exportFullPath, m_MovieTexture.m_MovieData);
return true;
}
@@ -284,8 +270,7 @@ namespace AssetStudioGUI
tga = true;
break;
}
var exportFullName = exportPath + item.Text + "." + type.ToLower();
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, "." + type.ToLower(), out var exportFullPath))
return false;
var bitmap = ((Sprite)item.Asset).GetImage();
if (bitmap != null)
@@ -293,10 +278,12 @@ namespace AssetStudioGUI
if (tga)
{
var file = new TGA(bitmap);
file.Save(exportFullName);
file.Save(exportFullPath);
}
else
bitmap.Save(exportFullName, format);
{
bitmap.Save(exportFullPath, format);
}
bitmap.Dispose();
return true;
}
@@ -305,43 +292,60 @@ namespace AssetStudioGUI
public static bool ExportRawFile(AssetItem item, string exportPath)
{
var exportFullName = exportPath + item.Text + ".dat";
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullName, item.Asset.GetRawData());
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
return true;
}
private static bool ExportFileExists(string filename)
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath)
{
if (File.Exists(filename))
var fileName = FixFileName(item.Text);
fullPath = Path.Combine(dir, fileName + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
Directory.CreateDirectory(Path.GetDirectoryName(filename));
return false;
}
public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
{
var exportFullPath = Path.Combine(exportPath, item.Text, item.Text + ".fbx");
if (File.Exists(exportFullPath))
{
exportFullPath = Path.Combine(exportPath, item.Text + item.UniqueID, item.Text + ".fbx");
}
var m_Animator = (Animator)item.Asset;
var convert = animationList != null ? new ModelConverter(m_Animator, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(m_Animator);
exportPath = $"{exportPath}{item.Text}\\{item.Text}.fbx";
ExportFbx(convert, exportPath);
var convert = animationList != null
? new ModelConverter(m_Animator, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(m_Animator, Properties.Settings.Default.convertType);
ExportFbx(convert, exportFullPath);
return true;
}
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
{
var convert = animationList != null ? new ModelConverter(gameObject, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(gameObject);
exportPath = exportPath + Studio.FixFileName(gameObject.m_Name) + ".fbx";
var convert = animationList != null
? new ModelConverter(gameObject, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(gameObject, Properties.Settings.Default.convertType);
exportPath = exportPath + FixFileName(gameObject.m_Name) + ".fbx";
ExportFbx(convert, exportPath);
}
public static void ExportGameObjectMerge(List<GameObject> gameObject, string exportPath, List<AssetItem> animationList = null)
{
var rootName = Path.GetFileNameWithoutExtension(exportPath);
var convert = animationList != null ? new ModelConverter(rootName, gameObject, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(rootName, gameObject);
var convert = animationList != null
? new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType);
ExportFbx(convert, exportPath);
}
@@ -364,13 +368,17 @@ namespace AssetStudioGUI
public static bool ExportDumpFile(AssetItem item, string exportPath)
{
var exportFullName = exportPath + item.Text + ".txt";
if (ExportFileExists(exportFullName))
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
return false;
var str = item.Asset.Dump();
if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour)
{
var m_Type = Studio.MonoBehaviourToTypeTree(m_MonoBehaviour);
str = m_MonoBehaviour.Dump(m_Type);
}
if (str != null)
{
File.WriteAllText(exportFullName, str);
File.WriteAllText(exportFullPath, str);
return true;
}
return false;
@@ -408,5 +416,11 @@ namespace AssetStudioGUI
return ExportRawFile(item, exportPath);
}
}
public static string FixFileName(string str)
{
if (str.Length >= 260) return Path.GetRandomFileName();
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
}
}
+13 -6
View File
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AssetStudio;
using AssetStudio;
using System;
using System.Windows.Forms;
namespace AssetStudioGUI
{
@@ -17,7 +15,16 @@ namespace AssetStudioGUI
public void Log(LoggerEvent loggerEvent, string message)
{
action(message);
switch (loggerEvent)
{
case LoggerEvent.Error:
MessageBox.Show(message);
break;
default:
action(message);
break;
}
}
}
}
Binary file not shown.
Binary file not shown.
+169 -80
View File
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.Xml.Linq;
using static AssetStudioGUI.Exporter;
using Object = AssetStudio.Object;
@@ -19,58 +20,89 @@ namespace AssetStudioGUI
Dump
}
internal enum ExportFilter
{
All,
Selected,
Filtered
}
internal enum ExportListType
{
XML
}
internal static class Studio
{
public static AssetsManager assetsManager = new AssetsManager();
public static ScriptDumper scriptDumper = new ScriptDumper();
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
public static List<AssetItem> exportableAssets = new List<AssetItem>();
public static List<AssetItem> visibleAssets = new List<AssetItem>();
internal static Action<string> StatusStripUpdate = x => { };
public static void ExtractFile(string[] fileNames)
public static int ExtractFolder(string path, string savePath)
{
ThreadPool.QueueUserWorkItem(state =>
int extractedCount = 0;
Progress.Reset();
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; i++)
{
int extractedCount = 0;
Progress.Reset();
for (var i = 0; i < fileNames.Length; i++)
{
var fileName = fileNames[i];
var type = ImportHelper.CheckFileType(fileName, out var reader);
if (type == FileType.BundleFile)
extractedCount += ExtractBundleFile(fileName, reader);
else if (type == FileType.WebFile)
extractedCount += ExtractWebDataFile(fileName, reader);
else
reader.Dispose();
Progress.Report(i + 1, fileNames.Length);
}
StatusStripUpdate($"Finished extracting {extractedCount} files.");
});
var file = files[i];
var fileOriPath = Path.GetDirectoryName(file);
var fileSavePath = fileOriPath.Replace(path, savePath);
extractedCount += ExtractFile(file, fileSavePath);
Progress.Report(i + 1, files.Length);
}
return extractedCount;
}
private static int ExtractBundleFile(string bundleFileName, EndianBinaryReader reader)
public static int ExtractFile(string[] fileNames, string savePath)
{
StatusStripUpdate($"Decompressing {Path.GetFileName(bundleFileName)} ...");
var bundleFile = new BundleFile(reader, bundleFileName);
int extractedCount = 0;
Progress.Reset();
for (var i = 0; i < fileNames.Length; i++)
{
var fileName = fileNames[i];
extractedCount += ExtractFile(fileName, savePath);
Progress.Report(i + 1, fileNames.Length);
}
return extractedCount;
}
public static int ExtractFile(string fileName, string savePath)
{
int extractedCount = 0;
var type = ImportHelper.CheckFileType(fileName, out var reader);
if (type == FileType.BundleFile)
extractedCount += ExtractBundleFile(fileName, reader, savePath);
else if (type == FileType.WebFile)
extractedCount += ExtractWebDataFile(fileName, reader, savePath);
else
reader.Dispose();
return extractedCount;
}
private static int ExtractBundleFile(string bundleFilePath, EndianBinaryReader reader, string savePath)
{
StatusStripUpdate($"Decompressing {Path.GetFileName(bundleFilePath)} ...");
var bundleFile = new BundleFile(reader, bundleFilePath);
reader.Dispose();
if (bundleFile.fileList.Length > 0)
{
var extractPath = bundleFileName + "_unpacked\\";
var extractPath = Path.Combine(savePath, Path.GetFileName(bundleFilePath) + "_unpacked");
return ExtractStreamFile(extractPath, bundleFile.fileList);
}
return 0;
}
private static int ExtractWebDataFile(string webFileName, EndianBinaryReader reader)
private static int ExtractWebDataFile(string webFilePath, EndianBinaryReader reader, string savePath)
{
StatusStripUpdate($"Decompressing {Path.GetFileName(webFileName)} ...");
StatusStripUpdate($"Decompressing {Path.GetFileName(webFilePath)} ...");
var webFile = new WebFile(reader);
reader.Dispose();
if (webFile.fileList.Length > 0)
{
var extractPath = webFileName + "_unpacked\\";
var extractPath = Path.Combine(savePath, Path.GetFileName(webFilePath) + "_unpacked");
return ExtractStreamFile(extractPath, webFile.fileList);
}
return 0;
@@ -81,14 +113,18 @@ namespace AssetStudioGUI
int extractedCount = 0;
foreach (var file in fileList)
{
var filePath = extractPath + file.fileName;
if (!Directory.Exists(extractPath))
var filePath = Path.Combine(extractPath, file.path);
var fileDirectory = Path.GetDirectoryName(filePath);
if (!Directory.Exists(fileDirectory))
{
Directory.CreateDirectory(extractPath);
Directory.CreateDirectory(fileDirectory);
}
if (!File.Exists(filePath) && file.stream is MemoryStream stream)
if (!File.Exists(filePath))
{
File.WriteAllBytes(filePath, stream.ToArray());
using (var fileStream = File.Create(filePath))
{
file.stream.CopyTo(fileStream);
}
extractedCount += 1;
}
file.stream.Dispose();
@@ -101,15 +137,13 @@ namespace AssetStudioGUI
StatusStripUpdate("Building asset list...");
string productName = null;
var assetsNameHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
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;
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
var tempExportableAssets = new List<AssetItem>();
Dictionary<long, string> containers = null;
foreach (var asset in assetsFile.Objects)
{
var assetItem = new AssetItem(asset);
@@ -135,7 +169,7 @@ namespace AssetStudioGUI
break;
case VideoClip m_VideoClip:
if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath))
assetItem.FullSize = asset.byteSize + (long)m_VideoClip.m_Size;
assetItem.FullSize = asset.byteSize + (long)m_VideoClip.m_ExternalResources.m_Size;
assetItem.Text = m_VideoClip.m_Name;
exportable = true;
break;
@@ -174,13 +208,24 @@ namespace AssetStudioGUI
productName = m_PlayerSettings.productName;
break;
case AssetBundle m_AssetBundle:
containers = new Dictionary<long, string>();
foreach (var m_Container in m_AssetBundle.m_Container)
{
containers[m_Container.Value.asset.m_PathID] = m_Container.Key;
var preloadIndex = m_Container.Value.preloadIndex;
var preloadSize = m_Container.Value.preloadSize;
var preloadEnd = preloadIndex + preloadSize;
for (int k = preloadIndex; k < preloadEnd; k++)
{
containers.Add((m_AssetBundle.m_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)
{
containers.Add((m_Container.Value, m_Container.Key));
}
break;
case NamedObject m_NamedObject:
assetItem.Text = m_NamedObject.m_Name;
break;
@@ -189,39 +234,27 @@ namespace AssetStudioGUI
{
assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
}
//处理同名文件
if (!assetsNameHash.Add(assetItem.TypeString + assetItem.Text))
{
assetItem.Text += assetItem.UniqueID;
}
//处理非法文件名
assetItem.Text = FixFileName(assetItem.Text);
if (Properties.Settings.Default.displayAll || exportable)
{
tempExportableAssets.Add(assetItem);
exportableAssets.Add(assetItem);
}
Progress.Report(++i, objectCount);
}
foreach (var item in tempExportableAssets)
{
if (containers != null)
{
if (containers.TryGetValue(item.Asset.m_PathID, out var container))
{
if (!string.IsNullOrEmpty(container))
{
item.Container = container;
}
}
}
item.SetSubItems();
}
exportableAssets.AddRange(tempExportableAssets);
tempExportableAssets.Clear();
containers?.Clear();
}
foreach ((var pptr, var container) in containers)
{
if (pptr.TryGet(out var obj))
{
objectAssetItemDic[obj].Container = container;
}
}
foreach (var tmp in exportableAssets)
{
tmp.SetSubItems();
}
containers.Clear();
visibleAssets = exportableAssets;
assetsNameHash.Clear();
StatusStripUpdate("Building tree structure...");
@@ -308,27 +341,27 @@ namespace AssetStudioGUI
{
if (typeMap.TryGetValue(assetsFile.unityVersion, out var curVer))
{
foreach (var type in assetsFile.m_Types.Where(x => x.m_Nodes != null))
foreach (var type in assetsFile.m_Types.Where(x => x.m_Type != null))
{
var key = type.classID;
if (type.m_ScriptTypeIndex >= 0)
{
key = -1 - type.m_ScriptTypeIndex;
}
curVer[key] = new TypeTreeItem(key, type.m_Nodes);
curVer[key] = new TypeTreeItem(key, type.m_Type);
}
}
else
{
var items = new SortedDictionary<int, TypeTreeItem>();
foreach (var type in assetsFile.m_Types.Where(x => x.m_Nodes != null))
foreach (var type in assetsFile.m_Types.Where(x => x.m_Type != null))
{
var key = type.classID;
if (type.m_ScriptTypeIndex >= 0)
{
key = -1 - type.m_ScriptTypeIndex;
}
items[key] = new TypeTreeItem(key, type.m_Nodes);
items[key] = new TypeTreeItem(key, type.m_Type);
}
typeMap.Add(assetsFile.unityVersion, items);
}
@@ -337,12 +370,6 @@ namespace AssetStudioGUI
return typeMap;
}
public static string FixFileName(string str)
{
if (str.Length >= 260) return Path.GetRandomFileName();
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
public static void ExportAssets(string savePath, List<AssetItem> toExportAssets, ExportType exportType)
{
ThreadPool.QueueUserWorkItem(state =>
@@ -372,7 +399,14 @@ namespace AssetStudioGUI
}
break;
case 2: //source file
exportPath = Path.Combine(savePath, asset.SourceFile.fullName + "_export");
if (string.IsNullOrEmpty(asset.SourceFile.originalPath))
{
exportPath = Path.Combine(savePath, asset.SourceFile.fileName + "_export");
}
else
{
exportPath = Path.Combine(savePath, Path.GetFileName(asset.SourceFile.originalPath) + "_export", asset.SourceFile.fileName);
}
break;
default:
exportPath = savePath;
@@ -428,6 +462,51 @@ namespace AssetStudioGUI
});
}
public static void ExportAssetsList(string savePath, List<AssetItem> toExportAssets, ExportListType exportListType)
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Progress.Reset();
switch (exportListType)
{
case ExportListType.XML:
var filename = Path.Combine(savePath, "assets.xml");
var doc = new XDocument(
new XElement("Assets",
new XAttribute("filename", filename),
new XAttribute("createdAt", DateTime.UtcNow.ToString("s")),
toExportAssets.Select(
asset => new XElement("Asset",
new XElement("Name", asset.Text),
new XElement("Container", asset.Container),
new XElement("Type", new XAttribute("id", (int)asset.Type), asset.TypeString),
new XElement("PathID", asset.m_PathID),
new XElement("Source", asset.SourceFile.fullName),
new XElement("Size", asset.FullSize)
)
)
)
);
doc.Save(filename);
break;
}
var statusText = $"Finished exporting asset list with {toExportAssets.Count()} items.";
StatusStripUpdate(statusText);
if (Properties.Settings.Default.openAfterExport && toExportAssets.Count() > 0)
{
Process.Start(savePath);
}
});
}
public static void ExportSplitObjects(string savePath, TreeNodeCollection nodes)
{
ThreadPool.QueueUserWorkItem(state =>
@@ -601,23 +680,33 @@ namespace AssetStudioGUI
}
}
public static string GetScriptString(ObjectReader reader)
public static TypeTree MonoBehaviourToTypeTree(MonoBehaviour m_MonoBehaviour)
{
if (scriptDumper == null)
if (!assemblyLoader.Loaded)
{
var openFolderDialog = new OpenFolderDialog();
openFolderDialog.Title = "Select Assembly Folder";
if (openFolderDialog.ShowDialog() == DialogResult.OK)
{
scriptDumper = new ScriptDumper(openFolderDialog.Folder);
assemblyLoader.Load(openFolderDialog.Folder);
}
else
{
scriptDumper = new ScriptDumper();
assemblyLoader.Loaded = true;
}
}
return m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
}
return scriptDumper.DumpScript(reader);
public static string DumpAsset(Object obj)
{
var str = obj.Dump();
if (str == null && obj is MonoBehaviour m_MonoBehaviour)
{
var type = MonoBehaviourToTypeTree(m_MonoBehaviour);
str = m_MonoBehaviour.Dump(type);
}
return str;
}
}
}
+1
View File
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net472" />
<package id="OpenTK" version="3.1.0" targetFramework="net472" />
<package id="OpenTK.GLControl" version="3.1.0" targetFramework="net472" />
</packages>
+65
View File
@@ -0,0 +1,65 @@
using Mono.Cecil;
using System.Collections.Generic;
using System.IO;
namespace AssetStudio
{
public class AssemblyLoader
{
public bool Loaded;
private Dictionary<string, ModuleDefinition> moduleDic = new Dictionary<string, ModuleDefinition>();
public void Load(string path)
{
var files = Directory.GetFiles(path, "*.dll");
var resolver = new MyAssemblyResolver();
var readerParameters = new ReaderParameters();
readerParameters.AssemblyResolver = resolver;
try
{
foreach (var file in files)
{
var assembly = AssemblyDefinition.ReadAssembly(file, readerParameters);
resolver.Register(assembly);
moduleDic.Add(assembly.MainModule.Name, assembly.MainModule);
}
}
catch
{
// ignored
}
Loaded = true;
}
public TypeDefinition GetTypeDefinition(string assemblyName, string fullName)
{
if (moduleDic.TryGetValue(assemblyName, out var module))
{
var typeDef = module.GetType(fullName);
if (typeDef == null && assemblyName == "UnityEngine.dll")
{
foreach (var pair in moduleDic)
{
typeDef = pair.Value.GetType(fullName);
if (typeDef != null)
{
break;
}
}
}
return typeDef;
}
return null;
}
public void Clear()
{
foreach (var pair in moduleDic)
{
pair.Value.Dispose();
}
moduleDic.Clear();
Loaded = false;
}
}
}
+29 -4
View File
@@ -34,9 +34,6 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="dnlib">
<HintPath>Libraries\dnlib.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
@@ -46,17 +43,45 @@
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="Unity.Cecil">
<HintPath>Libraries\Unity.Cecil.dll</HintPath>
</Reference>
<Reference Include="Unity.CecilTools">
<HintPath>Libraries\Unity.CecilTools.dll</HintPath>
</Reference>
<Reference Include="Unity.SerializationLogic">
<HintPath>Libraries\Unity.SerializationLogic.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyLoader.cs" />
<Compile Include="AudioClipConverter.cs" />
<Compile Include="CSspv\Disassembler.cs" />
<Compile Include="CSspv\EnumValuesExtensions.cs" />
<Compile Include="CSspv\Instruction.cs" />
<Compile Include="CSspv\Module.cs" />
<Compile Include="CSspv\OperandType.cs" />
<Compile Include="CSspv\ParsedInstruction.cs" />
<Compile Include="CSspv\Reader.cs" />
<Compile Include="CSspv\SpirV.Core.Grammar.cs" />
<Compile Include="CSspv\SpirV.Meta.cs" />
<Compile Include="CSspv\Types.cs" />
<Compile Include="FMOD Studio API\fmod.cs" />
<Compile Include="FMOD Studio API\fmod_dsp.cs" />
<Compile Include="FMOD Studio API\fmod_errors.cs" />
<Compile Include="ModelConverter.cs" />
<Compile Include="ModelExporter.cs" />
<Compile Include="MonoBehaviourConverter.cs" />
<Compile Include="SerializedTypeHelper.cs" />
<Compile Include="TGASharpLib.cs" />
<Compile Include="TypeDefinitionConverter.cs" />
<Compile Include="MyAssemblyResolver.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ScriptDumper.cs" />
<Compile Include="ShaderConverter.cs" />
<Compile Include="Smolv\OpData.cs" />
<Compile Include="Smolv\SmolvDecoder.cs" />
<Compile Include="Smolv\SpvOp.cs" />
<Compile Include="SpirVShaderConverter.cs" />
<Compile Include="SpriteHelper.cs" />
<Compile Include="Texture2DConverter.cs" />
<Compile Include="Texture2DExtensions.cs" />
+41 -23
View File
@@ -1,4 +1,5 @@
using System;
using FMOD;
using System;
using System.Runtime.InteropServices;
using System.Text;
@@ -18,33 +19,53 @@ namespace AssetStudio
var m_AudioData = m_AudioClip.m_AudioData.GetData();
if (m_AudioData == null || m_AudioData.Length == 0)
return null;
var exinfo = new FMOD.CREATESOUNDEXINFO();
var result = FMOD.Factory.System_Create(out var system);
if (result != FMOD.RESULT.OK)
var exinfo = new CREATESOUNDEXINFO();
var result = Factory.System_Create(out var system);
if (result != RESULT.OK)
return null;
result = system.init(1, FMOD.INITFLAGS.NORMAL, IntPtr.Zero);
if (result != FMOD.RESULT.OK)
result = system.init(1, INITFLAGS.NORMAL, IntPtr.Zero);
if (result != RESULT.OK)
return null;
exinfo.cbsize = Marshal.SizeOf(exinfo);
exinfo.length = (uint)m_AudioClip.m_Size;
result = system.createSound(m_AudioData, FMOD.MODE.OPENMEMORY, ref exinfo, out var sound);
if (result != FMOD.RESULT.OK)
result = system.createSound(m_AudioData, MODE.OPENMEMORY, ref exinfo, out var sound);
if (result != RESULT.OK)
return null;
result = sound.getSubSound(0, out var subsound);
if (result != FMOD.RESULT.OK)
result = sound.getNumSubSounds(out var numsubsounds);
if (result != RESULT.OK)
return null;
result = subsound.getFormat(out var type, out var format, out int channels, out int bits);
if (result != FMOD.RESULT.OK)
byte[] buff;
if (numsubsounds > 0)
{
result = sound.getSubSound(0, out var subsound);
if (result != RESULT.OK)
return null;
buff = SoundToWav(subsound);
subsound.release();
}
else
{
buff = SoundToWav(sound);
}
sound.release();
system.release();
return buff;
}
public byte[] SoundToWav(Sound sound)
{
var result = sound.getFormat(out _, out _, out int channels, out int bits);
if (result != RESULT.OK)
return null;
result = subsound.getDefaults(out var frequency, out int priority);
if (result != FMOD.RESULT.OK)
result = sound.getDefaults(out var frequency, out _);
if (result != RESULT.OK)
return null;
var sampleRate = (int)frequency;
result = subsound.getLength(out var length, FMOD.TIMEUNIT.PCMBYTES);
if (result != FMOD.RESULT.OK)
result = sound.getLength(out var length, TIMEUNIT.PCMBYTES);
if (result != RESULT.OK)
return null;
result = subsound.@lock(0, length, out var ptr1, out var ptr2, out var len1, out var len2);
if (result != FMOD.RESULT.OK)
result = sound.@lock(0, length, out var ptr1, out var ptr2, out var len1, out var len2);
if (result != RESULT.OK)
return null;
byte[] buffer = new byte[len1 + 44];
//添加wav头
@@ -61,12 +82,9 @@ namespace AssetStudio
Encoding.UTF8.GetBytes("data").CopyTo(buffer, 36);
BitConverter.GetBytes(len1).CopyTo(buffer, 40);
Marshal.Copy(ptr1, buffer, 44, (int)len1);
result = subsound.unlock(ptr1, ptr2, len1, len2);
if (result != FMOD.RESULT.OK)
result = sound.unlock(ptr1, ptr2, len1, len2);
if (result != RESULT.OK)
return null;
subsound.release();
sound.release();
system.release();
return buffer;
}
+221
View File
@@ -0,0 +1,221 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SpirV
{
public struct ModuleHeader
{
public Version Version { get; set; }
public string GeneratorVendor { get; set; }
public string GeneratorName { get; set; }
public int GeneratorVersion { get; set; }
public uint Bound { get; set; }
public uint Reserved { get; set; }
}
[Flags]
public enum DisassemblyOptions
{
None,
ShowTypes,
ShowNames,
Default = ShowTypes | ShowNames
}
public class Disassembler
{
public string Disassemble (Module module)
{
return Disassemble(module, DisassemblyOptions.Default);
}
public string Disassemble(Module module, DisassemblyOptions options)
{
m_sb.AppendLine("; SPIR-V");
m_sb.Append("; Version: ").Append(module.Header.Version).AppendLine();
if (module.Header.GeneratorName == null)
{
m_sb.Append("; Generator: unknown; ").Append(module.Header.GeneratorVersion).AppendLine();
}
else
{
m_sb.Append("; Generator: ").Append(module.Header.GeneratorVendor).Append(' ').
Append(module.Header.GeneratorName).Append("; ").Append(module.Header.GeneratorVersion).AppendLine();
}
m_sb.Append("; Bound: ").Append(module.Header.Bound).AppendLine();
m_sb.Append("; Schema: ").Append(module.Header.Reserved).AppendLine();
string[] lines = new string[module.Instructions.Count + 1];
lines[0] = m_sb.ToString();
m_sb.Clear();
for (int i = 0; i < module.Instructions.Count; i++)
{
ParsedInstruction instruction = module.Instructions[i];
PrintInstruction(m_sb, instruction, options);
lines[i + 1] = m_sb.ToString();
m_sb.Clear();
}
int longestPrefix = 0;
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
longestPrefix = Math.Max(longestPrefix, line.IndexOf('='));
if (longestPrefix > 50)
{
longestPrefix = 50;
break;
}
}
m_sb.Append(lines[0]);
for (int i = 1; i < lines.Length; i++)
{
string line = lines[i];
int index = line.IndexOf('=');
if (index == -1)
{
m_sb.Append(' ', longestPrefix + 4);
m_sb.Append(line);
}
else
{
int pad = Math.Max(0, longestPrefix - index);
m_sb.Append(' ', pad);
m_sb.Append(line, 0, index);
m_sb.Append('=');
m_sb.Append(line, index + 1, line.Length - index - 1);
}
m_sb.AppendLine();
}
string result = m_sb.ToString();
m_sb.Clear();
return result;
}
private static void PrintInstruction(StringBuilder sb, ParsedInstruction instruction, DisassemblyOptions options)
{
if (instruction.Operands.Count == 0)
{
sb.Append(instruction.Instruction.Name);
return;
}
int currentOperand = 0;
if (instruction.Instruction.Operands[currentOperand].Type is IdResultType)
{
if (options.HasFlag(DisassemblyOptions.ShowTypes))
{
instruction.ResultType.ToString(sb).Append(' ');
}
++currentOperand;
}
if (currentOperand < instruction.Operands.Count && instruction.Instruction.Operands[currentOperand].Type is IdResult)
{
if (!options.HasFlag(DisassemblyOptions.ShowNames) || string.IsNullOrWhiteSpace(instruction.Name))
{
PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options);
}
else
{
sb.Append(instruction.Name);
}
sb.Append(" = ");
++currentOperand;
}
sb.Append(instruction.Instruction.Name);
sb.Append(' ');
for (; currentOperand < instruction.Operands.Count; ++currentOperand)
{
PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options);
sb.Append(' ');
}
}
private static void PrintOperandValue(StringBuilder sb, object value, DisassemblyOptions options)
{
switch (value)
{
case System.Type t:
sb.Append(t.Name);
break;
case string s:
{
sb.Append('"');
sb.Append(s);
sb.Append('"');
}
break;
case ObjectReference or:
{
if (options.HasFlag(DisassemblyOptions.ShowNames) && or.Reference != null && !string.IsNullOrWhiteSpace(or.Reference.Name))
{
sb.Append(or.Reference.Name);
}
else
{
or.ToString(sb);
}
}
break;
case IBitEnumOperandValue beov:
PrintBitEnumValue(sb, beov, options);
break;
case IValueEnumOperandValue veov:
PrintValueEnumValue(sb, veov, options);
break;
case VaryingOperandValue varOpVal:
varOpVal.ToString(sb);
break;
default:
sb.Append(value);
break;
}
}
private static void PrintBitEnumValue(StringBuilder sb, IBitEnumOperandValue enumOperandValue, DisassemblyOptions options)
{
foreach (uint key in enumOperandValue.Values.Keys)
{
sb.Append(enumOperandValue.EnumerationType.GetEnumName(key));
IReadOnlyList<object> value = enumOperandValue.Values[key];
if (value.Count != 0)
{
sb.Append(' ');
foreach (object v in value)
{
PrintOperandValue(sb, v, options);
}
}
}
}
private static void PrintValueEnumValue(StringBuilder sb, IValueEnumOperandValue valueOperandValue, DisassemblyOptions options)
{
sb.Append(valueOperandValue.Key);
if (valueOperandValue.Value is IList<object> valueList && valueList.Count > 0)
{
sb.Append(' ');
foreach (object v in valueList)
{
PrintOperandValue(sb, v, options);
}
}
}
private readonly StringBuilder m_sb = new StringBuilder();
}
}
@@ -0,0 +1,42 @@
#if NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 || NETSTANDARD1_5 || NETSTANDARD1_6
using System;
using System.Linq;
using System.Reflection;
namespace SpirV
{
public static class EnumValuesExtensions
{
public static Array GetEnumValues(this System.Type _this)
{
TypeInfo typeInfo = _this.GetTypeInfo ();
if (!typeInfo.IsEnum) {
throw new ArgumentException ("GetEnumValues: Type '" + _this.Name + "' is not an enum");
}
return
(
from field in typeInfo.DeclaredFields
where field.IsLiteral
select field.GetValue (null)
)
.ToArray();
}
public static string GetEnumName(this System.Type _this, object value)
{
TypeInfo typeInfo = _this.GetTypeInfo ();
if (!typeInfo.IsEnum) {
throw new ArgumentException ("GetEnumName: Type '" + _this.Name + "' is not an enum");
}
return
(
from field in typeInfo.DeclaredFields
where field.IsLiteral && (uint)field.GetValue(null) == (uint)value
select field.Name
)
.First();
}
}
}
#endif
+51
View File
@@ -0,0 +1,51 @@
using System.Collections.Generic;
namespace SpirV
{
public enum OperandQuantifier
{
/// <summary>
/// 1
/// </summary>
Default,
/// <summary>
/// 0 or 1
/// </summary>
Optional,
/// <summary>
/// 0+
/// </summary>
Varying
}
public class Operand
{
public Operand(OperandType kind, string name, OperandQuantifier quantifier)
{
Name = name;
Type = kind;
Quantifier = quantifier;
}
public string Name { get; }
public OperandType Type { get; }
public OperandQuantifier Quantifier { get; }
}
public class Instruction
{
public Instruction (string name)
: this (name, new List<Operand> ())
{
}
public Instruction (string name, IReadOnlyList<Operand> operands)
{
Operands = operands;
Name = name;
}
public string Name { get; }
public IReadOnlyList<Operand> Operands { get; }
}
}
+25
View File
@@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2017, Matthäus G. Chajdas
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+426
View File
@@ -0,0 +1,426 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace SpirV
{
public class Module
{
[StructLayout(LayoutKind.Explicit)]
private struct FloatUIntUnion
{
[FieldOffset(0)]
public uint Int;
[FieldOffset(0)]
public float Float;
}
[StructLayout(LayoutKind.Explicit)]
private struct DoubleULongUnion
{
[FieldOffset(0)]
public ulong Long;
[FieldOffset(0)]
public double Double;
}
public Module(ModuleHeader header, IReadOnlyList<ParsedInstruction> instructions)
{
Header = header;
Instructions = instructions;
Read(Instructions, objects_);
}
public static bool IsDebugInstruction(ParsedInstruction instruction)
{
return debugInstructions_.Contains(instruction.Instruction.Name);
}
private static void Read(IReadOnlyList<ParsedInstruction> instructions, Dictionary<uint, ParsedInstruction> objects)
{
// Debug instructions can be only processed after everything
// else has been parsed, as they may reference types which haven't
// been seen in the file yet
List<ParsedInstruction> debugInstructions = new List<ParsedInstruction>();
// Entry points contain forward references
// Those need to be resolved afterwards
List<ParsedInstruction> entryPoints = new List<ParsedInstruction>();
foreach (var instruction in instructions)
{
if (IsDebugInstruction(instruction))
{
debugInstructions.Add(instruction);
continue;
}
if (instruction.Instruction is OpEntryPoint)
{
entryPoints.Add(instruction);
continue;
}
if (instruction.Instruction.Name.StartsWith("OpType", StringComparison.Ordinal))
{
ProcessTypeInstruction(instruction, objects);
}
instruction.ResolveResultType(objects);
if (instruction.HasResult)
{
objects[instruction.ResultId] = instruction;
}
switch (instruction.Instruction)
{
// Constants require that the result type has been resolved
case OpSpecConstant sc:
case OpConstant oc:
{
Type t = instruction.ResultType;
Debug.Assert (t != null);
Debug.Assert (t is ScalarType);
object constant = ConvertConstant(instruction.ResultType as ScalarType, instruction.Words, 3);
instruction.Operands[2].Value = constant;
instruction.Value = constant;
}
break;
}
}
foreach (ParsedInstruction instruction in debugInstructions)
{
switch (instruction.Instruction)
{
case OpMemberName mn:
{
StructType t = (StructType)objects[instruction.Words[1]].ResultType;
t.SetMemberName((uint)instruction.Operands[1].Value, (string)instruction.Operands[2].Value);
}
break;
case OpName n:
{
// We skip naming objects we don't know about
ParsedInstruction t = objects[instruction.Words[1]];
t.Name = (string)instruction.Operands[1].Value;
}
break;
}
}
foreach (ParsedInstruction instruction in instructions)
{
instruction.ResolveReferences(objects);
}
}
public static Module ReadFrom(Stream stream)
{
BinaryReader br = new BinaryReader(stream);
Reader reader = new Reader(br);
uint versionNumber = reader.ReadDWord();
int majorVersion = (int)(versionNumber >> 16);
int minorVersion = (int)((versionNumber >> 8) & 0xFF);
Version version = new Version(majorVersion, minorVersion);
uint generatorMagicNumber = reader.ReadDWord();
int generatorToolId = (int)(generatorMagicNumber >> 16);
string generatorVendor = "unknown";
string generatorName = null;
if (Meta.Tools.ContainsKey(generatorToolId))
{
Meta.ToolInfo toolInfo = Meta.Tools[generatorToolId];
generatorVendor = toolInfo.Vendor;
if (toolInfo.Name != null)
{
generatorName = toolInfo.Name;
}
}
// Read header
ModuleHeader header = new ModuleHeader();
header.Version = version;
header.GeneratorName = generatorName;
header.GeneratorVendor = generatorVendor;
header.GeneratorVersion = (int)(generatorMagicNumber & 0xFFFF);
header.Bound = reader.ReadDWord();
header.Reserved = reader.ReadDWord();
List<ParsedInstruction> instructions = new List<ParsedInstruction>();
while (!reader.EndOfStream)
{
uint instructionStart = reader.ReadDWord ();
ushort wordCount = (ushort)(instructionStart >> 16);
int opCode = (int)(instructionStart & 0xFFFF);
uint[] words = new uint[wordCount];
words[0] = instructionStart;
for (ushort i = 1; i < wordCount; ++i)
{
words[i] = reader.ReadDWord();
}
ParsedInstruction instruction = new ParsedInstruction(opCode, words);
instructions.Add(instruction);
}
return new Module(header, instructions);
}
/// <summary>
/// Collect types from OpType* instructions
/// </summary>
private static void ProcessTypeInstruction(ParsedInstruction i, IReadOnlyDictionary<uint, ParsedInstruction> objects)
{
switch (i.Instruction)
{
case OpTypeInt t:
{
i.ResultType = new IntegerType((int)i.Words[2], i.Words[3] == 1u);
}
break;
case OpTypeFloat t:
{
i.ResultType = new FloatingPointType((int)i.Words[2]);
}
break;
case OpTypeVector t:
{
i.ResultType = new VectorType((ScalarType)objects[i.Words[2]].ResultType, (int)i.Words[3]);
}
break;
case OpTypeMatrix t:
{
i.ResultType = new MatrixType((VectorType)objects[i.Words[2]].ResultType, (int)i.Words[3]);
}
break;
case OpTypeArray t:
{
object constant = objects[i.Words[3]].Value;
int size = 0;
switch (constant)
{
case ushort u16:
size = u16;
break;
case uint u32:
size = (int)u32;
break;
case ulong u64:
size = (int)u64;
break;
case short i16:
size = i16;
break;
case int i32:
size = i32;
break;
case long i64:
size = (int)i64;
break;
}
i.ResultType = new ArrayType(objects[i.Words[2]].ResultType, size);
}
break;
case OpTypeRuntimeArray t:
{
i.ResultType = new RuntimeArrayType((Type)objects[i.Words[2]].ResultType);
}
break;
case OpTypeBool t:
{
i.ResultType = new BoolType();
}
break;
case OpTypeOpaque t:
{
i.ResultType = new OpaqueType();
}
break;
case OpTypeVoid t:
{
i.ResultType = new VoidType();
}
break;
case OpTypeImage t:
{
Type sampledType = objects[i.Operands[1].GetId ()].ResultType;
Dim dim = i.Operands[2].GetSingleEnumValue<Dim>();
uint depth = (uint)i.Operands[3].Value;
bool isArray = (uint)i.Operands[4].Value != 0;
bool isMultiSampled = (uint)i.Operands[5].Value != 0;
uint sampled = (uint)i.Operands[6].Value;
ImageFormat imageFormat = i.Operands[7].GetSingleEnumValue<ImageFormat>();
i.ResultType = new ImageType(sampledType,
dim,
(int)depth, isArray, isMultiSampled,
(int)sampled, imageFormat,
i.Operands.Count > 8 ? i.Operands[8].GetSingleEnumValue<AccessQualifier>() : AccessQualifier.ReadOnly);
}
break;
case OpTypeSampler st:
{
i.ResultType = new SamplerType();
break;
}
case OpTypeSampledImage t:
{
i.ResultType = new SampledImageType((ImageType)objects[i.Words[2]].ResultType);
}
break;
case OpTypeFunction t:
{
List<Type> parameterTypes = new List<Type>();
for (int j = 3; j < i.Words.Count; ++j)
{
parameterTypes.Add(objects[i.Words[j]].ResultType);
}
i.ResultType = new FunctionType(objects[i.Words[2]].ResultType, parameterTypes);
}
break;
case OpTypeForwardPointer t:
{
// We create a normal pointer, but with unspecified type
// This will get resolved later on
i.ResultType = new PointerType((StorageClass)i.Words[2]);
}
break;
case OpTypePointer t:
{
if (objects.ContainsKey(i.Words[1]))
{
// If there is something present, it must have been
// a forward reference. The storage type must
// match
PointerType pt = (PointerType)i.ResultType;
Debug.Assert (pt != null);
Debug.Assert (pt.StorageClass == (StorageClass)i.Words[2]);
pt.ResolveForwardReference (objects[i.Words[3]].ResultType);
}
else
{
i.ResultType = new PointerType((StorageClass)i.Words[2], objects[i.Words[3]].ResultType);
}
}
break;
case OpTypeStruct t:
{
List<Type> memberTypes = new List<Type>();
for (int j = 2; j < i.Words.Count; ++j)
{
memberTypes.Add(objects[i.Words[j]].ResultType);
}
i.ResultType = new StructType(memberTypes);
}
break;
}
}
private static object ConvertConstant(ScalarType type, IReadOnlyList<uint> words, int index)
{
switch (type)
{
case IntegerType i:
{
if (i.Signed)
{
if (i.Width == 16)
{
return unchecked((short)(words[index]));
}
else if (i.Width == 32)
{
return unchecked((int)(words[index]));
}
else if (i.Width == 64)
{
return unchecked((long)(words[index] | (ulong)(words[index + 1]) << 32));
}
}
else
{
if (i.Width == 16)
{
return unchecked((ushort)(words[index]));
}
else if (i.Width == 32)
{
return words[index];
}
else if (i.Width == 64)
{
return words[index] | (ulong)(words[index + 1]) << 32;
}
}
throw new Exception ("Cannot construct integer literal.");
}
case FloatingPointType f:
{
if (f.Width == 32)
{
return new FloatUIntUnion { Int = words[0] }.Float;
}
else if (f.Width == 64)
{
return new DoubleULongUnion { Long = (words[index] | (ulong)(words[index + 1]) << 32) }.Double;
}
else
{
throw new Exception("Cannot construct floating point literal.");
}
}
}
return null;
}
public ModuleHeader Header { get; }
public IReadOnlyList<ParsedInstruction> Instructions { get; }
private static HashSet<string> debugInstructions_ = new HashSet<string>
{
"OpSourceContinued",
"OpSource",
"OpSourceExtension",
"OpName",
"OpMemberName",
"OpString",
"OpLine",
"OpNoLine",
"OpModuleProcessed"
};
private readonly Dictionary<uint, ParsedInstruction> objects_ = new Dictionary<uint, ParsedInstruction>();
}
}
+302
View File
@@ -0,0 +1,302 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Reflection;
namespace SpirV
{
public class OperandType
{
public virtual bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
// This returns the dynamic type
value = GetType();
wordsUsed = 1;
return true;
}
}
public class Literal : OperandType
{
}
public class LiteralNumber : Literal
{
}
// The SPIR-V JSON file uses only literal integers
public class LiteralInteger : LiteralNumber
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
value = words[index];
wordsUsed = 1;
return true;
}
}
public class LiteralString : Literal
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
// This is just a fail-safe -- the loop below must terminate
wordsUsed = 1;
int bytesUsed = 0;
byte[] bytes = new byte[(words.Count - index) * 4];
for (int i = index; i < words.Count; ++i)
{
uint word = words[i];
byte b0 = (byte)(word & 0xFF);
if (b0 == 0)
{
break;
}
else
{
bytes[bytesUsed++] = b0;
}
byte b1 = (byte)((word >> 8) & 0xFF);
if (b1 == 0)
{
break;
}
else
{
bytes[bytesUsed++] = b1;
}
byte b2 = (byte)((word >> 16) & 0xFF);
if (b2 == 0)
{
break;
}
else
{
bytes[bytesUsed++] = b2;
}
byte b3 = (byte)(word >> 24);
if (b3 == 0)
{
break;
}
else
{
bytes[bytesUsed++] = b3;
}
wordsUsed++;
}
value = Encoding.UTF8.GetString(bytes, 0, bytesUsed);
return true;
}
}
public class LiteralContextDependentNumber : Literal
{
// This is handled during parsing by ConvertConstant
}
public class LiteralExtInstInteger : Literal
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
value = words[index];
wordsUsed = 1;
return true;
}
}
public class LiteralSpecConstantOpInteger : Literal
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
List<ObjectReference> result = new List<ObjectReference>();
for (int i = index; i < words.Count; i++)
{
ObjectReference objRef = new ObjectReference(words[i]);
result.Add(objRef);
}
value = result;
wordsUsed = words.Count - index;
return true;
}
}
public class Parameter
{
public virtual IReadOnlyList<OperandType> OperandTypes { get; }
}
public class ParameterFactory
{
public virtual Parameter CreateParameter(object value)
{
return null;
}
}
public class EnumType<T> : EnumType<T, ParameterFactory>
where T : Enum
{
};
public class EnumType<T, U> : OperandType
where T : Enum
where U : ParameterFactory, new ()
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
int wordsUsedForParameters = 0;
if (typeof(T).GetTypeInfo().GetCustomAttributes<FlagsAttribute>().Any())
{
Dictionary<uint, IReadOnlyList<object>> result = new Dictionary<uint, IReadOnlyList<object>>();
foreach (object enumValue in EnumerationType.GetEnumValues())
{
uint bit = (uint)enumValue;
// bit == 0 and words[0] == 0 handles the 0x0 = None cases
if ((words[index] & bit) != 0 || (bit == 0 && words[index] == 0))
{
Parameter p = parameterFactory_.CreateParameter(bit);
if (p == null)
{
result.Add(bit, Array.Empty<object>());
}
else
{
object[] resultItems = new object[p.OperandTypes.Count];
for (int j = 0; j < p.OperandTypes.Count; ++j)
{
p.OperandTypes[j].ReadValue(words, 1 + wordsUsedForParameters, out object pValue, out int pWordsUsed);
wordsUsedForParameters += pWordsUsed;
resultItems[j] = pValue;
}
result.Add(bit, resultItems);
}
}
}
value = new BitEnumOperandValue<T>(result);
}
else
{
object[] resultItems;
Parameter p = parameterFactory_.CreateParameter(words[index]);
if (p == null)
{
resultItems = Array.Empty<object>();
}
else
{
resultItems = new object[p.OperandTypes.Count];
for (int j = 0; j < p.OperandTypes.Count; ++j)
{
p.OperandTypes[j].ReadValue(words, 1 + wordsUsedForParameters, out object pValue, out int pWordsUsed);
wordsUsedForParameters += pWordsUsed;
resultItems[j] = pValue;
}
}
value = new ValueEnumOperandValue<T>((T)(object)words[index], resultItems);
}
wordsUsed = wordsUsedForParameters + 1;
return true;
}
public System.Type EnumerationType => typeof(T);
private U parameterFactory_ = new U();
}
public class IdScope : OperandType
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
value = (Scope)words[index];
wordsUsed = 1;
return true;
}
}
public class IdMemorySemantics : OperandType
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
value = (MemorySemantics)words[index];
wordsUsed = 1;
return true;
}
}
public class IdType : OperandType
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
value = words[index];
wordsUsed = 1;
return true;
}
}
public class IdResult : IdType
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
value = new ObjectReference(words[index]);
wordsUsed = 1;
return true;
}
}
public class IdResultType : IdType
{
}
public class IdRef : IdType
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
value = new ObjectReference(words[index]);
wordsUsed = 1;
return true;
}
}
public class PairIdRefIdRef : OperandType
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
ObjectReference variable = new ObjectReference(words[index]);
ObjectReference parent = new ObjectReference(words[index + 1]);
value = new { Variable = variable, Parent = parent };
wordsUsed = 2;
return true;
}
}
public class PairIdRefLiteralInteger : OperandType
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
ObjectReference type = new ObjectReference(words[index]);
uint word = words[index + 1];
value = new { Type = type, Member = word };
wordsUsed = 2;
return true;
}
}
public class PairLiteralIntegerIdRef : OperandType
{
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
{
uint selector = words[index];
ObjectReference label = new ObjectReference(words[index + 1]);
value = new { Selector = selector, Label = label };
wordsUsed = 2;
return true;
}
}
}
@@ -0,0 +1,265 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SpirV
{
public class ParsedOperand
{
public ParsedOperand(IReadOnlyList<uint> words, int index, int count, object value, Operand operand)
{
uint[] array = new uint[count];
for (int i = 0; i < count; i++)
{
array[i] = words[index + i];
}
Words = array;
Value = value;
Operand = operand;
}
public T GetSingleEnumValue<T>()
where T : Enum
{
IValueEnumOperandValue v = (IValueEnumOperandValue)Value;
if (v.Value.Count == 0)
{
// If there's no value at all, the enum is probably something like ImageFormat.
// In which case we just return the enum value
return (T)v.Key;
}
else
{
// This means the enum has a value attached to it, so we return the attached value
return (T)((IValueEnumOperandValue)Value).Value[0];
}
}
public uint GetId()
{
return ((ObjectReference)Value).Id;
}
public T GetBitEnumValue<T>()
where T : Enum
{
var v = Value as IBitEnumOperandValue;
uint result = 0;
foreach (var k in v.Values.Keys)
{
result |= k;
}
return (T)(object)result;
}
public IReadOnlyList<uint> Words { get; }
public object Value { get; set; }
public Operand Operand { get; }
}
public class VaryingOperandValue
{
public VaryingOperandValue(IReadOnlyList<object> values)
{
Values = values;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
ToString(sb);
return sb.ToString();
}
public StringBuilder ToString(StringBuilder sb)
{
for (int i = 0; i < Values.Count; ++i)
{
if (Values[i] is ObjectReference objRef)
{
objRef.ToString(sb);
}
else
{
sb.Append(Values[i]);
}
if (i < (Values.Count - 1))
{
sb.Append(' ');
}
}
return sb;
}
public IReadOnlyList<object> Values { get; }
}
public interface IEnumOperandValue
{
System.Type EnumerationType { get; }
}
public interface IBitEnumOperandValue : IEnumOperandValue
{
IReadOnlyDictionary<uint, IReadOnlyList<object>> Values { get; }
}
public interface IValueEnumOperandValue : IEnumOperandValue
{
object Key { get; }
IReadOnlyList<object> Value { get; }
}
public class ValueEnumOperandValue<T> : IValueEnumOperandValue
where T : Enum
{
public ValueEnumOperandValue(T key, IReadOnlyList<object> value)
{
Key = key;
Value = value;
}
public System.Type EnumerationType => typeof(T);
public object Key { get; }
public IReadOnlyList<object> Value { get; }
}
public class BitEnumOperandValue<T> : IBitEnumOperandValue
where T : Enum
{
public BitEnumOperandValue(Dictionary<uint, IReadOnlyList<object>> values)
{
Values = values;
}
public IReadOnlyDictionary<uint, IReadOnlyList<object>> Values { get; }
public System.Type EnumerationType => typeof(T);
}
public class ObjectReference
{
public ObjectReference(uint id)
{
Id = id;
}
public void Resolve(IReadOnlyDictionary<uint, ParsedInstruction> objects)
{
Reference = objects[Id];
}
public override string ToString()
{
return $"%{Id}";
}
public StringBuilder ToString(StringBuilder sb)
{
return sb.Append('%').Append(Id);
}
public uint Id { get; }
public ParsedInstruction Reference { get; private set; }
}
public class ParsedInstruction
{
public ParsedInstruction(int opCode, IReadOnlyList<uint> words)
{
Words = words;
Instruction = Instructions.OpcodeToInstruction[opCode];
ParseOperands();
}
private void ParseOperands()
{
if (Instruction.Operands.Count == 0)
{
return;
}
// Word 0 describes this instruction so we can ignore it
int currentWord = 1;
int currentOperand = 0;
List<object> varyingOperandValues = new List<object>();
int varyingWordStart = 0;
Operand varyingOperand = null;
while (currentWord < Words.Count)
{
Operand operand = Instruction.Operands[currentOperand];
operand.Type.ReadValue(Words, currentWord, out object value, out int wordsUsed);
if (operand.Quantifier == OperandQuantifier.Varying)
{
varyingOperandValues.Add(value);
varyingWordStart = currentWord;
varyingOperand = operand;
}
else
{
int wordCount = Math.Min(Words.Count - currentWord, wordsUsed);
ParsedOperand parsedOperand = new ParsedOperand(Words, currentWord, wordCount, value, operand);
Operands.Add(parsedOperand);
}
currentWord += wordsUsed;
if (operand.Quantifier != OperandQuantifier.Varying)
{
++currentOperand;
}
}
if (varyingOperand != null)
{
VaryingOperandValue varOperantValue = new VaryingOperandValue(varyingOperandValues);
ParsedOperand parsedOperand = new ParsedOperand(Words, currentWord, Words.Count - currentWord, varOperantValue, varyingOperand);
Operands.Add(parsedOperand);
}
}
public void ResolveResultType(IReadOnlyDictionary<uint, ParsedInstruction> objects)
{
if (Instruction.Operands.Count > 0 && Instruction.Operands[0].Type is IdResultType)
{
ResultType = objects[(uint)Operands[0].Value].ResultType;
}
}
public void ResolveReferences (IReadOnlyDictionary<uint, ParsedInstruction> objects)
{
foreach (var operand in Operands)
{
if (operand.Value is ObjectReference objectReference)
{
objectReference.Resolve (objects);
}
}
}
public Type ResultType { get; set; }
public uint ResultId
{
get
{
for (int i = 0; i < Instruction.Operands.Count; ++i)
{
if (Instruction.Operands[i].Type is IdResult)
{
return Operands[i].GetId();
}
}
return 0;
}
}
public bool HasResult => ResultId != 0;
public IReadOnlyList<uint> Words { get; }
public Instruction Instruction { get; }
public IList<ParsedOperand> Operands { get; } = new List<ParsedOperand>();
public string Name { get; set; }
public object Value { get; set; }
}
}
+50
View File
@@ -0,0 +1,50 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
namespace SpirV
{
internal sealed class Reader
{
public Reader(BinaryReader reader)
{
reader_ = reader;
uint magicNumber = reader_.ReadUInt32();
if (magicNumber == Meta.MagicNumber)
{
littleEndian_ = true;
}
else if (Reverse(magicNumber) == Meta.MagicNumber)
{
littleEndian_ = false;
}
else
{
throw new Exception("Invalid magic number");
}
}
public uint ReadDWord()
{
if (littleEndian_)
{
return reader_.ReadUInt32 ();
}
else
{
return Reverse(reader_.ReadUInt32());
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Reverse(uint u)
{
return (u << 24) | (u & 0xFF00U) << 8 | (u >> 8) & 0xFF00U | (u >> 24);
}
public bool EndOfStream => reader_.BaseStream.Position == reader_.BaseStream.Length;
private readonly BinaryReader reader_;
private readonly bool littleEndian_;
}
}
File diff suppressed because one or more lines are too long
+54
View File
@@ -0,0 +1,54 @@
using System.Collections.Generic;
namespace SpirV
{
internal class Meta
{
public class ToolInfo
{
public ToolInfo(string vendor)
{
Vendor = vendor;
}
public ToolInfo(string vendor, string name)
{
Vendor = vendor;
Name = name;
}
public string Name { get; }
public string Vendor { get; }
}
public static uint MagicNumber => 119734787U;
public static uint Version => 66048U;
public static uint Revision => 2U;
public static uint OpCodeMask => 65535U;
public static uint WordCountShift => 16U;
public static IReadOnlyDictionary<int, ToolInfo> Tools => toolInfos_;
private readonly static Dictionary<int, ToolInfo> toolInfos_ = new Dictionary<int, ToolInfo>
{
{ 0, new ToolInfo("Khronos") },
{ 1, new ToolInfo("LunarG") },
{ 2, new ToolInfo("Valve") },
{ 3, new ToolInfo("Codeplay") },
{ 4, new ToolInfo("NVIDIA") },
{ 5, new ToolInfo("ARM") },
{ 6, new ToolInfo("Khronos", "LLVM/SPIR-V Translator") },
{ 7, new ToolInfo("Khronos", "SPIR-V Tools Assembler") },
{ 8, new ToolInfo("Khronos", "Glslang Reference Front End") },
{ 9, new ToolInfo("Qualcomm") },
{ 10, new ToolInfo("AMD") },
{ 11, new ToolInfo("Intel") },
{ 12, new ToolInfo("Imagination") },
{ 13, new ToolInfo("Google", "Shaderc over Glslang") },
{ 14, new ToolInfo("Google", "spiregg") },
{ 15, new ToolInfo("Google", "rspirv") },
{ 16, new ToolInfo("X-LEGEND", "Mesa-IR/SPIR-V Translator") },
{ 17, new ToolInfo("Khronos", "SPIR-V Tools Linker") },
};
}
}
+428
View File
@@ -0,0 +1,428 @@
using System.Collections.Generic;
using System.Text;
namespace SpirV
{
public class Type
{
public virtual StringBuilder ToString(StringBuilder sb)
{
return sb;
}
}
public class VoidType : Type
{
public override string ToString()
{
return "void";
}
public override StringBuilder ToString(StringBuilder sb)
{
return sb.Append("void");
}
}
public class ScalarType : Type
{
}
public class BoolType : ScalarType
{
public override string ToString()
{
return "bool";
}
public override StringBuilder ToString(StringBuilder sb)
{
return sb.Append("bool");
}
}
public class IntegerType : ScalarType
{
public IntegerType (int width, bool signed)
{
Width = width;
Signed = signed;
}
public override string ToString()
{
if (Signed)
{
return $"i{Width}";
}
else
{
return $"u{Width}";
}
}
public override StringBuilder ToString(StringBuilder sb)
{
if (Signed)
{
sb.Append('i').Append(Width);
}
else
{
sb.Append('u').Append(Width);
}
return sb;
}
public int Width { get; }
public bool Signed { get; }
}
public class FloatingPointType : ScalarType
{
public FloatingPointType (int width)
{
Width = width;
}
public override string ToString()
{
return $"f{Width}";
}
public override StringBuilder ToString(StringBuilder sb)
{
return sb.Append('f').Append(Width);
}
public int Width { get; }
}
public class VectorType : Type
{
public VectorType (ScalarType scalarType, int componentCount)
{
ComponentType = scalarType;
ComponentCount = componentCount;
}
public override string ToString()
{
return $"{ComponentType}_{ComponentCount}";
}
public override StringBuilder ToString(StringBuilder sb)
{
return ComponentType.ToString(sb).Append('_').Append(ComponentCount);
}
public ScalarType ComponentType { get; }
public int ComponentCount { get; }
}
public class MatrixType : Type
{
public MatrixType (VectorType vectorType, int columnCount)
{
ColumnType = vectorType;
ColumnCount = columnCount;
}
public override string ToString ()
{
return $"{ColumnType}x{ColumnCount}";
}
public override StringBuilder ToString(StringBuilder sb)
{
return sb.Append(ColumnType).Append('x').Append(ColumnCount);
}
public VectorType ColumnType { get; }
public int ColumnCount { get; }
public int RowCount => ColumnType.ComponentCount;
}
public class ImageType : Type
{
public ImageType (Type sampledType, Dim dim, int depth, bool isArray, bool isMultisampled, int sampleCount,
ImageFormat imageFormat, AccessQualifier accessQualifier)
{
SampledType = sampledType;
Dim = dim;
Depth = depth;
IsArray = isArray;
IsMultisampled = isMultisampled;
SampleCount = sampleCount;
Format = imageFormat;
AccessQualifier = accessQualifier;
}
public override string ToString ()
{
StringBuilder sb = new StringBuilder ();
ToString(sb);
return sb.ToString();
}
public override StringBuilder ToString(StringBuilder sb)
{
switch (AccessQualifier)
{
case AccessQualifier.ReadWrite:
sb.Append("read_write ");
break;
case AccessQualifier.WriteOnly:
sb.Append("write_only ");
break;
case AccessQualifier.ReadOnly:
sb.Append("read_only ");
break;
}
sb.Append("Texture");
switch (Dim)
{
case Dim.Dim1D:
sb.Append("1D");
break;
case Dim.Dim2D:
sb.Append("2D");
break;
case Dim.Dim3D:
sb.Append("3D");
break;
case Dim.Cube:
sb.Append("Cube");
break;
}
if (IsMultisampled)
{
sb.Append("MS");
}
if (IsArray)
{
sb.Append("Array");
}
return sb;
}
public Type SampledType { get; }
public Dim Dim { get; }
public int Depth { get; }
public bool IsArray { get; }
public bool IsMultisampled { get; }
public int SampleCount { get; }
public ImageFormat Format { get; }
public AccessQualifier AccessQualifier { get; }
}
public class SamplerType : Type
{
public override string ToString()
{
return "sampler";
}
public override StringBuilder ToString(StringBuilder sb)
{
return sb.Append("sampler");
}
}
public class SampledImageType : Type
{
public SampledImageType (ImageType imageType)
{
ImageType = imageType;
}
public override string ToString()
{
return $"{ImageType}Sampled";
}
public override StringBuilder ToString(StringBuilder sb)
{
return ImageType.ToString(sb).Append("Sampled");
}
public ImageType ImageType { get; }
}
public class ArrayType : Type
{
public ArrayType (Type elementType, int elementCount)
{
ElementType = elementType;
ElementCount = elementCount;
}
public override string ToString()
{
return $"{ElementType}[{ElementCount}]";
}
public override StringBuilder ToString(StringBuilder sb)
{
return ElementType.ToString(sb).Append('[').Append(ElementCount).Append(']');
}
public int ElementCount { get; }
public Type ElementType { get; }
}
public class RuntimeArrayType : Type
{
public RuntimeArrayType(Type elementType)
{
ElementType = elementType;
}
public Type ElementType { get; }
}
public class StructType : Type
{
public StructType(IReadOnlyList<Type> memberTypes)
{
MemberTypes = memberTypes;
memberNames_ = new List<string>();
for (int i = 0; i < memberTypes.Count; ++i)
{
memberNames_.Add(string.Empty);
}
}
public void SetMemberName(uint member, string name)
{
memberNames_[(int)member] = name;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
ToString(sb);
return sb.ToString();
}
public override StringBuilder ToString(StringBuilder sb)
{
sb.Append("struct {");
for (int i = 0; i < MemberTypes.Count; ++i)
{
Type memberType = MemberTypes[i];
memberType.ToString(sb);
if (!string.IsNullOrEmpty(memberNames_[i]))
{
sb.Append(' ');
sb.Append(MemberNames[i]);
}
sb.Append(';');
if (i < (MemberTypes.Count - 1))
{
sb.Append(' ');
}
}
sb.Append('}');
return sb;
}
public IReadOnlyList<Type> MemberTypes { get; }
public IReadOnlyList<string> MemberNames => memberNames_;
private List<string> memberNames_;
}
public class OpaqueType : Type
{
}
public class PointerType : Type
{
public PointerType(StorageClass storageClass, Type type)
{
StorageClass = storageClass;
Type = type;
}
public PointerType(StorageClass storageClass)
{
StorageClass = storageClass;
}
public void ResolveForwardReference(Type t)
{
Type = t;
}
public override string ToString()
{
if (Type == null)
{
return $"{StorageClass} *";
}
else
{
return $"{StorageClass} {Type}*";
}
}
public override StringBuilder ToString(StringBuilder sb)
{
sb.Append(StorageClass.ToString()).Append(' ');
if (Type != null)
{
Type.ToString(sb);
}
sb.Append('*');
return sb;
}
public StorageClass StorageClass { get; }
public Type Type { get; private set; }
}
public class FunctionType : Type
{
public FunctionType(Type returnType, IReadOnlyList<Type> parameterTypes)
{
ReturnType = returnType;
ParameterTypes = parameterTypes;
}
public Type ReturnType { get; }
public IReadOnlyList<Type> ParameterTypes { get; }
}
public class EventType : Type
{
}
public class DeviceEventType : Type
{
}
public class ReserveIdType : Type
{
}
public class QueueType : Type
{
}
public class PipeType : Type
{
}
public class PipeStorage : Type
{
}
public class NamedBarrier : Type
{
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+35 -14
View File
@@ -4,6 +4,7 @@ using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using TGASharpLib;
namespace AssetStudio
{
@@ -16,6 +17,7 @@ namespace AssetStudio
public List<ImportedKeyframedAnimation> AnimationList { get; protected set; } = new List<ImportedKeyframedAnimation>();
public List<ImportedMorph> MorphList { get; protected set; } = new List<ImportedMorph>();
private string imageFormat;
private Avatar avatar;
private HashSet<AnimationClip> animationClipHashSet = new HashSet<AnimationClip>();
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
@@ -23,8 +25,9 @@ namespace AssetStudio
private Dictionary<Transform, ImportedFrame> transformDictionary = new Dictionary<Transform, ImportedFrame>();
Dictionary<uint, string> morphChannelNames = new Dictionary<uint, string>();
public ModelConverter(GameObject m_GameObject, AnimationClip[] animationList = null)
public ModelConverter(GameObject m_GameObject, string imageFormat, AnimationClip[] animationList = null)
{
this.imageFormat = imageFormat;
if (m_GameObject.m_Animator != null)
{
InitWithAnimator(m_GameObject.m_Animator);
@@ -47,8 +50,9 @@ namespace AssetStudio
ConvertAnimations();
}
public ModelConverter(string rootName, List<GameObject> m_GameObjects, AnimationClip[] animationList = null)
public ModelConverter(string rootName, List<GameObject> m_GameObjects, string imageFormat, AnimationClip[] animationList = null)
{
this.imageFormat = imageFormat;
RootFrame = CreateFrame(rootName, Vector3.Zero, new Quaternion(0, 0, 0, 0), Vector3.One);
foreach (var m_GameObject in m_GameObjects)
{
@@ -76,8 +80,9 @@ namespace AssetStudio
ConvertAnimations();
}
public ModelConverter(Animator m_Animator, AnimationClip[] animationList = null)
public ModelConverter(Animator m_Animator, string imageFormat, AnimationClip[] animationList = null)
{
this.imageFormat = imageFormat;
InitWithAnimator(m_Animator);
if (animationList == null)
{
@@ -435,17 +440,17 @@ namespace AssetStudio
}
}
}
else
{
//Logger.Error("");
}
}
else
if (boneType == 0)
{
//尝试使用m_BoneNameHashes 4.3 and up
if (mesh.m_BindPose.Length > 0 && (mesh.m_BindPose.Length == mesh.m_BoneNameHashes?.Length))
{
boneType = 2;
var verifiedBoneCount = mesh.m_BoneNameHashes.Count(x => FixBonePath(GetPathFromHash(x)) != null);
if (verifiedBoneCount > 0)
{
boneType = 2;
}
}
}
@@ -500,7 +505,7 @@ namespace AssetStudio
crc.Update(bytes, 0, (uint)bytes.Length);
morphChannelNames[crc.GetDigest()] = blendShapeName;
channel.Name = shapeChannel.name;
channel.Name = shapeChannel.name.Split('.').Last();
channel.KeyframeList = new List<ImportedMorphKeyframe>(shapeChannel.frameCount);
var frameEnd = shapeChannel.frameIndex + shapeChannel.frameCount;
for (int frameIdx = shapeChannel.frameIndex; frameIdx < frameEnd; frameIdx++)
@@ -689,15 +694,16 @@ namespace AssetStudio
texture.Dest = dest;
var ext = $".{imageFormat.ToLower()}";
if (textureNameDictionary.TryGetValue(m_Texture2D, out var textureName))
{
texture.Name = textureName;
}
else if (ImportedHelpers.FindTexture(m_Texture2D.m_Name + ".png", TextureList) != null) //已有相同名字的图片
else if (ImportedHelpers.FindTexture(m_Texture2D.m_Name + ext, TextureList) != null) //已有相同名字的图片
{
for (int i = 1; ; i++)
{
var name = m_Texture2D.m_Name + $" ({i}).png";
var name = m_Texture2D.m_Name + $" ({i}){ext}";
if (ImportedHelpers.FindTexture(name, TextureList) == null)
{
texture.Name = name;
@@ -708,7 +714,7 @@ namespace AssetStudio
}
else
{
texture.Name = m_Texture2D.m_Name + ".png";
texture.Name = m_Texture2D.m_Name + ext;
textureNameDictionary.Add(m_Texture2D, texture.Name);
}
@@ -739,7 +745,22 @@ namespace AssetStudio
{
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
switch (imageFormat)
{
case "BMP":
bitmap.Save(stream, ImageFormat.Bmp);
break;
case "PNG":
bitmap.Save(stream, ImageFormat.Png);
break;
case "JPEG":
bitmap.Save(stream, ImageFormat.Jpeg);
break;
case "TGA":
var tga = new TGA(bitmap);
tga.Save(stream);
break;
}
iTex = new ImportedTexture(stream, name);
TextureList.Add(iTex);
bitmap.Dispose();
@@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace AssetStudio
{
public static class MonoBehaviourConverter
{
public static TypeTree ConvertToTypeTree(this MonoBehaviour m_MonoBehaviour, AssemblyLoader assemblyLoader)
{
var m_Type = new TypeTree();
m_Type.m_Nodes = new List<TypeTreeNode>();
var helper = new SerializedTypeHelper(m_MonoBehaviour.version);
helper.AddMonoBehaviour(m_Type.m_Nodes, 0);
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{
var typeDef = assemblyLoader.GetTypeDefinition(m_Script.m_AssemblyName, string.IsNullOrEmpty(m_Script.m_Namespace) ? m_Script.m_ClassName : $"{m_Script.m_Namespace}.{m_Script.m_ClassName}");
if (typeDef != null)
{
var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, helper, 1);
m_Type.m_Nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNodes());
}
}
return m_Type;
}
}
}
+12
View File
@@ -0,0 +1,12 @@
using Mono.Cecil;
namespace AssetStudio
{
public class MyAssemblyResolver : DefaultAssemblyResolver
{
public void Register(AssemblyDefinition assembly)
{
RegisterAssembly(assembly);
}
}
}
-492
View File
@@ -1,492 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using dnlib.DotNet;
namespace AssetStudio
{
//TODO to json file
public sealed class ScriptDumper : IDisposable
{
private Dictionary<string, ModuleDef> moduleDic = new Dictionary<string, ModuleDef>();
public ScriptDumper() { }
public ScriptDumper(string path)
{
var files = Directory.GetFiles(path, "*.dll");
var moduleContext = new ModuleContext();
var asmResolver = new AssemblyResolver(moduleContext);
var resolver = new Resolver(asmResolver);
moduleContext.AssemblyResolver = asmResolver;
moduleContext.Resolver = resolver;
try
{
foreach (var file in files)
{
var module = ModuleDefMD.Load(file, moduleContext);
asmResolver.AddToCache(module);
moduleDic.Add(Path.GetFileName(file), module);
}
}
catch
{
// ignored
}
}
public string DumpScript(ObjectReader reader)
{
var m_MonoBehaviour = new MonoBehaviour(reader);
var sb = CreateMonoBehaviourHeader(m_MonoBehaviour);
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{
if (!moduleDic.TryGetValue(m_Script.m_AssemblyName, out var module))
{
return sb.ToString();
}
var typeDef = module.Assembly.Find(m_Script.m_Namespace != "" ? $"{m_Script.m_Namespace}.{m_Script.m_ClassName}" : m_Script.m_ClassName, false);
if (typeDef != null)
{
try
{
DumpType(typeDef.ToTypeSig(), sb, reader, null, -1, true);
var readed = reader.Position - reader.byteStart;
if (readed != reader.byteSize)
{
Logger.Error($"Error while dump type, read {readed} bytes but expected {reader.byteSize} bytes");
}
}
catch
{
sb = CreateMonoBehaviourHeader(m_MonoBehaviour);
Logger.Error("Error while dump type");
}
}
}
return sb.ToString();
}
public void Dispose()
{
if (moduleDic != null)
{
foreach (var pair in moduleDic)
{
pair.Value.Dispose();
}
moduleDic.Clear();
moduleDic = null;
}
}
private static StringBuilder CreateMonoBehaviourHeader(MonoBehaviour m_MonoBehaviour)
{
var sb = new StringBuilder();
sb.AppendLine("PPtr<GameObject> m_GameObject");
sb.AppendLine($"\tint m_FileID = {m_MonoBehaviour.m_GameObject.m_FileID}");
sb.AppendLine($"\tint64 m_PathID = {m_MonoBehaviour.m_GameObject.m_PathID}");
sb.AppendLine($"UInt8 m_Enabled = {m_MonoBehaviour.m_Enabled}");
sb.AppendLine("PPtr<MonoScript> m_Script");
sb.AppendLine($"\tint m_FileID = {m_MonoBehaviour.m_Script.m_FileID}");
sb.AppendLine($"\tint64 m_PathID = {m_MonoBehaviour.m_Script.m_PathID}");
sb.AppendLine($"string m_Name = \"{m_MonoBehaviour.m_Name}\"");
return sb;
}
private static void DumpType(TypeSig typeSig, StringBuilder sb, ObjectReader reader, string name, int indent, bool isRoot = false, bool align = true)
{
var typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow();
if (typeSig.IsPrimitive)
{
object value = null;
switch (typeSig.TypeName)
{
case "Boolean":
value = reader.ReadBoolean();
break;
case "Byte":
value = reader.ReadByte();
break;
case "SByte":
value = reader.ReadSByte();
break;
case "Int16":
value = reader.ReadInt16();
break;
case "UInt16":
value = reader.ReadUInt16();
break;
case "Int32":
value = reader.ReadInt32();
break;
case "UInt32":
value = reader.ReadUInt32();
break;
case "Int64":
value = reader.ReadInt64();
break;
case "UInt64":
value = reader.ReadUInt64();
break;
case "Single":
value = reader.ReadSingle();
break;
case "Double":
value = reader.ReadDouble();
break;
case "Char":
value = reader.ReadChar();
break;
}
if (align)
reader.AlignStream();
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {value}");
return;
}
if (typeSig.FullName == "System.String")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = \"{reader.ReadAlignedString()}\"");
return;
}
if (typeSig.FullName == "System.Object")
{
return;
}
if (typeDef.IsDelegate)
{
return;
}
if (typeSig is ArraySigBase)
{
if (!typeDef.IsEnum && !IsBaseType(typeDef) && !IsAssignFromUnityObject(typeDef) && !IsEngineType(typeDef) && !typeDef.IsSerializable)
{
return;
}
var size = reader.ReadInt32();
sb.AppendLine($"{new string('\t', indent)}{typeSig.TypeName} {name}");
sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}");
for (int i = 0; i < size; i++)
{
sb.AppendLine($"{new string('\t', indent + 2)}[{i}]");
DumpType(typeDef.ToTypeSig(), sb, reader, "data", indent + 2);
}
return;
}
if (!isRoot && typeSig is GenericInstSig genericInstSig)
{
if (genericInstSig.GenericArguments.Count == 1)
{
var genericType = genericInstSig.GenericType.ToTypeDefOrRef().ResolveTypeDefThrow();
var type = genericInstSig.GenericArguments[0].ToTypeDefOrRef().ResolveTypeDefThrow();
if (genericInstSig.GenericArguments[0] is ArraySigBase)
{
return;
}
if (!type.IsEnum && !IsBaseType(type) && !IsAssignFromUnityObject(type) && !IsEngineType(type) && !type.IsSerializable)
{
return;
}
sb.AppendLine($"{new string('\t', indent)}{typeSig.TypeName} {name}");
if (genericType.Interfaces.Any(x => x.Interface.FullName == "System.Collections.Generic.ICollection`1<T>")) //System.Collections.Generic.IEnumerable`1<T>
{
var size = reader.ReadInt32();
sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}");
for (int i = 0; i < size; i++)
{
sb.AppendLine($"{new string('\t', indent + 2)}[{i}]");
DumpType(genericInstSig.GenericArguments[0], sb, reader, "data", indent + 2, false, false);
}
reader.AlignStream();
}
else
{
DumpType(genericType.ToTypeSig(), sb, reader, "data", indent + 1);
}
}
return;
}
if (indent != -1 && IsAssignFromUnityObject(typeDef))
{
var pptr = new PPtr<Object>(reader);
sb.AppendLine($"{new string('\t', indent)}PPtr<{typeDef.Name}> {name} = {{fileID: {pptr.m_FileID}, pathID: {pptr.m_PathID}}}");
return;
}
if (typeDef.IsEnum)
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {reader.ReadUInt32()}");
return;
}
if (!isRoot && !IsEngineType(typeDef) && !typeDef.IsSerializable)
{
return;
}
if (typeDef.FullName == "UnityEngine.AnimationCurve")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
sb.AppendLine($"{new string('\t', indent + 1)}<truncated>");
var animationCurve = new AnimationCurve<float>(reader, reader.ReadSingle);
return;
}
if (typeDef.FullName == "UnityEngine.Bounds")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
sb.AppendLine($"{new string('\t', indent + 1)}<truncated>");
new AABB(reader);
return;
}
if (typeDef.FullName == "UnityEngine.BoundsInt")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
sb.AppendLine($"{new string('\t', indent + 1)}<truncated>");
reader.Position += 24;
return;
}
if (typeDef.FullName == "UnityEngine.Color32")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
var prefix = new string('\t', indent + 1);
sb.AppendLine($"{prefix}byte r = {reader.ReadByte()}");
sb.AppendLine($"{prefix}byte g = {reader.ReadByte()}");
sb.AppendLine($"{prefix}byte b = {reader.ReadByte()}");
sb.AppendLine($"{prefix}byte a = {reader.ReadByte()}");
reader.AlignStream();
return;
}
if (typeDef.FullName == "UnityEngine.Gradient")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
sb.AppendLine($"{new string('\t', indent + 1)}<truncated>");
if (reader.version[0] == 5 && reader.version[1] < 5)
reader.Position += 68;
else if (reader.version[0] == 5 && reader.version[1] < 6)
reader.Position += 72;
else
reader.Position += 168;
return;
}
if (typeDef.FullName == "UnityEngine.GUIStyle") //TODO
{
throw new NotSupportedException();
}
if (typeDef.FullName == "UnityEngine.LayerMask")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
sb.AppendLine($"{new string('\t', indent + 1)}uint m_Bits = {reader.ReadUInt32()}");
return;
}
if (typeDef.FullName == "UnityEngine.PropertyName")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
sb.AppendLine($"{new string('\t', indent + 1)}int id = {reader.ReadInt32()}");
return;
}
if (typeDef.FullName == "UnityEngine.Rect")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
var prefix = new string('\t', indent + 1);
sb.AppendLine($"{prefix}float x = {reader.ReadSingle()}");
sb.AppendLine($"{prefix}float y = {reader.ReadSingle()}");
sb.AppendLine($"{prefix}float width = {reader.ReadSingle()}");
sb.AppendLine($"{prefix}float height = {reader.ReadSingle()}");
return;
}
if (typeDef.FullName == "UnityEngine.RectInt")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
var prefix = new string('\t', indent + 1);
sb.AppendLine($"{prefix}int x = {reader.ReadInt32()}");
sb.AppendLine($"{prefix}int y = {reader.ReadInt32()}");
sb.AppendLine($"{prefix}int width = {reader.ReadInt32()}");
sb.AppendLine($"{prefix}int height = {reader.ReadInt32()}");
return;
}
if (typeDef.FullName == "UnityEngine.RectOffset")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
var prefix = new string('\t', indent + 1);
sb.AppendLine($"{prefix}float left = {reader.ReadSingle()}");
sb.AppendLine($"{prefix}float right = {reader.ReadSingle()}");
sb.AppendLine($"{prefix}float top = {reader.ReadSingle()}");
sb.AppendLine($"{prefix}float bottom = {reader.ReadSingle()}");
return;
}
if (typeDef.FullName == "UnityEngine.Vector2Int")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
var prefix = new string('\t', indent + 1);
sb.AppendLine($"{prefix}int x = {reader.ReadInt32()}");
sb.AppendLine($"{prefix}int y = {reader.ReadInt32()}");
return;
}
if (typeDef.FullName == "UnityEngine.Vector3Int")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
var prefix = new string('\t', indent + 1);
sb.AppendLine($"{prefix}int x = {reader.ReadInt32()}");
sb.AppendLine($"{prefix}int y = {reader.ReadInt32()}");
sb.AppendLine($"{prefix}int z = {reader.ReadInt32()}");
return;
}
if (typeDef.IsClass || typeDef.IsValueType)
{
if (name != null && indent != -1)
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
}
if (indent == -1 && typeDef.BaseType.FullName != "UnityEngine.Object")
{
DumpType(typeDef.BaseType.ToTypeSig(), sb, reader, null, indent, true);
}
if (indent != -1 && typeDef.BaseType.FullName != "System.Object")
{
DumpType(typeDef.BaseType.ToTypeSig(), sb, reader, null, indent, true);
}
foreach (var fieldDef in typeDef.Fields)
{
var flag = false;
var access = fieldDef.Access & FieldAttributes.FieldAccessMask;
if (access != FieldAttributes.Public)
{
if (fieldDef.CustomAttributes.Any(x => x.TypeFullName == "UnityEngine.SerializeField"))
{
flag = true;
}
}
else if ((fieldDef.Attributes & FieldAttributes.Static) == 0 && (fieldDef.Attributes & FieldAttributes.InitOnly) == 0 && (fieldDef.Attributes & FieldAttributes.NotSerialized) == 0)
{
flag = true;
}
if (flag)
{
if (fieldDef.FieldType.IsGenericParameter)
{
for (var i = 0; i < typeDef.GenericParameters.Count; i++)
{
var g = typeDef.GenericParameters[i];
if (g.FullName == fieldDef.FieldType.FullName)
{
var type = ((GenericInstSig)typeSig).GenericArguments[i];
DumpType(type, sb, reader, fieldDef.Name, indent + 1);
break;
}
}
}
else if (fieldDef.FieldType is GenericInstSig genericSig && genericSig.GenericArguments.Count == 1 && genericSig.GenericArguments[0].IsGenericParameter)
{
for (var i = 0; i < typeDef.GenericParameters.Count; i++)
{
var g = typeDef.GenericParameters[i];
if (g.FullName == genericSig.GenericArguments[0].FullName)
{
var type = ((GenericInstSig)typeSig).GenericArguments[i];
var fieldTypeDef = fieldDef.FieldType.ToTypeDefOrRef().ResolveTypeDefThrow();
if (fieldTypeDef.Interfaces.Any(x => x.Interface.FullName == "System.Collections.Generic.ICollection`1<T>")) //System.Collections.Generic.IEnumerable`1<T>
{
var size = reader.ReadInt32();
sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}");
for (int j = 0; j < size; j++)
{
sb.AppendLine($"{new string('\t', indent + 2)}[{i}]");
DumpType(type, sb, reader, "data", indent + 2, false, false);
}
}
else
{
DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1);
}
}
}
}
else
{
DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1);
}
}
}
}
}
private static bool IsAssignFromUnityObject(TypeDef typeDef)
{
if (typeDef.FullName == "UnityEngine.Object")
{
return true;
}
if (typeDef.BaseType != null)
{
if (typeDef.BaseType.FullName == "UnityEngine.Object")
{
return true;
}
while (true)
{
typeDef = typeDef.BaseType.ResolveTypeDefThrow();
if (typeDef.BaseType == null)
{
break;
}
if (typeDef.BaseType.FullName == "UnityEngine.Object")
{
return true;
}
}
}
return false;
}
private static bool IsBaseType(IFullName typeDef)
{
switch (typeDef.FullName)
{
case "System.Boolean":
case "System.Byte":
case "System.SByte":
case "System.Int16":
case "System.UInt16":
case "System.Int32":
case "System.UInt32":
case "System.Int64":
case "System.UInt64":
case "System.Single":
case "System.Double":
case "System.String":
return true;
default:
return false;
}
}
private static bool IsEngineType(IFullName typeDef)
{
switch (typeDef.FullName)
{
case "UnityEngine.AnimationCurve":
case "UnityEngine.Bounds":
case "UnityEngine.BoundsInt":
case "UnityEngine.Color":
case "UnityEngine.Color32":
case "UnityEngine.Gradient":
case "UnityEngine.GUIStyle":
case "UnityEngine.LayerMask":
case "UnityEngine.Matrix4x4":
case "UnityEngine.PropertyName":
case "UnityEngine.Quaternion":
case "UnityEngine.Rect":
case "UnityEngine.RectInt":
case "UnityEngine.RectOffset":
case "UnityEngine.Vector2":
case "UnityEngine.Vector2Int":
case "UnityEngine.Vector3":
case "UnityEngine.Vector3Int":
case "UnityEngine.Vector4":
return true;
default:
return false;
}
}
}
}
+281
View File
@@ -0,0 +1,281 @@
using System.Collections.Generic;
namespace AssetStudio
{
public class SerializedTypeHelper
{
private readonly int[] version;
public SerializedTypeHelper(int[] version)
{
this.version = version;
}
public void AddMonoBehaviour(List<TypeTreeNode> nodes, int indent)
{
nodes.Add(new TypeTreeNode("MonoBehaviour", "Base", indent, false));
AddPPtr(nodes, "GameObject", "m_GameObject", indent + 1);
nodes.Add(new TypeTreeNode("UInt8", "m_Enabled", indent + 1, true));
AddPPtr(nodes, "MonoScript", "m_Script", indent + 1);
AddString(nodes, "m_Name", indent + 1);
}
public void AddPPtr(List<TypeTreeNode> nodes, string type, string name, int indent)
{
nodes.Add(new TypeTreeNode($"PPtr<{type}>", name, indent, false));
nodes.Add(new TypeTreeNode("int", "m_FileID", indent + 1, false));
if (version[0] >= 5) //5.0 and up
{
nodes.Add(new TypeTreeNode("SInt64", "m_PathID", indent + 1, false));
}
else
{
nodes.Add(new TypeTreeNode("int", "m_PathID", indent + 1, false));
}
}
public void AddString(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("string", name, indent, false));
nodes.Add(new TypeTreeNode("Array", "Array", indent + 1, true));
nodes.Add(new TypeTreeNode("int", "size", indent + 2, false));
nodes.Add(new TypeTreeNode("char", "data", indent + 2, false));
}
public void AddArray(List<TypeTreeNode> nodes, int indent)
{
nodes.Add(new TypeTreeNode("Array", "Array", indent, false));
nodes.Add(new TypeTreeNode("int", "size", indent + 1, false));
}
public void AddAnimationCurve(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("AnimationCurve", name, indent, false));
nodes.Add(new TypeTreeNode("vector", "m_Curve", indent + 1, false));
AddArray(nodes, indent + 2); //TODO 2017 and up Array align but no effect
nodes.Add(new TypeTreeNode("Keyframe", "data", indent + 3, false));
nodes.Add(new TypeTreeNode("float", "time", indent + 4, false));
nodes.Add(new TypeTreeNode("float", "value", indent + 4, false));
nodes.Add(new TypeTreeNode("float", "inSlope", indent + 4, false));
nodes.Add(new TypeTreeNode("float", "outSlope", indent + 4, false));
if (version[0] >= 2018) //2018 and up
{
nodes.Add(new TypeTreeNode("int", "weightedMode", indent + 4, false));
nodes.Add(new TypeTreeNode("float", "inWeight", indent + 4, false));
nodes.Add(new TypeTreeNode("float", "outWeight", indent + 4, false));
}
nodes.Add(new TypeTreeNode("int", "m_PreInfinity", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_PostInfinity", indent + 1, false));
if (version[0] > 5 || (version[0] == 5 && version[1] >= 3)) //5.3 and up
{
nodes.Add(new TypeTreeNode("int", "m_RotationOrder", indent + 1, false));
}
}
public void AddGradient(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("Gradient", name, indent, false));
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
{
AddColorRGBA(nodes, "key0", indent + 1);
AddColorRGBA(nodes, "key1", indent + 1);
AddColorRGBA(nodes, "key2", indent + 1);
AddColorRGBA(nodes, "key3", indent + 1);
AddColorRGBA(nodes, "key4", indent + 1);
AddColorRGBA(nodes, "key5", indent + 1);
AddColorRGBA(nodes, "key6", indent + 1);
AddColorRGBA(nodes, "key7", indent + 1);
}
else
{
AddColor32(nodes, "key0", indent + 1);
AddColor32(nodes, "key1", indent + 1);
AddColor32(nodes, "key2", indent + 1);
AddColor32(nodes, "key3", indent + 1);
AddColor32(nodes, "key4", indent + 1);
AddColor32(nodes, "key5", indent + 1);
AddColor32(nodes, "key6", indent + 1);
AddColor32(nodes, "key7", indent + 1);
}
nodes.Add(new TypeTreeNode("UInt16", "ctime0", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "ctime1", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "ctime2", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "ctime3", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "ctime4", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "ctime5", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "ctime6", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "ctime7", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime0", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime1", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime2", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime3", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime4", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime5", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime6", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime7", indent + 1, false));
if (version[0] > 5 || (version[0] == 5 && version[1] >= 5)) //5.5 and up
{
nodes.Add(new TypeTreeNode("int", "m_Mode", indent + 1, false));
}
nodes.Add(new TypeTreeNode("UInt8", "m_NumColorKeys", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt8", "m_NumAlphaKeys", indent + 1, true));
}
public void AddGUIStyle(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("GUIStyle", name, indent, false));
AddString(nodes, "m_Name", indent + 1);
AddGUIStyleState(nodes, "m_Normal", indent + 1);
AddGUIStyleState(nodes, "m_Hover", indent + 1);
AddGUIStyleState(nodes, "m_Active", indent + 1);
AddGUIStyleState(nodes, "m_Focused", indent + 1);
AddGUIStyleState(nodes, "m_OnNormal", indent + 1);
AddGUIStyleState(nodes, "m_OnHover", indent + 1);
AddGUIStyleState(nodes, "m_OnActive", indent + 1);
AddGUIStyleState(nodes, "m_OnFocused", indent + 1);
AddRectOffset(nodes, "m_Border", indent + 1);
if (version[0] >= 4) //4 and up
{
AddRectOffset(nodes, "m_Margin", indent + 1);
AddRectOffset(nodes, "m_Padding", indent + 1);
}
else
{
AddRectOffset(nodes, "m_Padding", indent + 1);
AddRectOffset(nodes, "m_Margin", indent + 1);
}
AddRectOffset(nodes, "m_Overflow", indent + 1);
AddPPtr(nodes, "Font", "m_Font", indent + 1);
if (version[0] >= 4) //4 and up
{
nodes.Add(new TypeTreeNode("int", "m_FontSize", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_FontStyle", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_Alignment", indent + 1, false));
nodes.Add(new TypeTreeNode("bool", "m_WordWrap", indent + 1, false));
nodes.Add(new TypeTreeNode("bool", "m_RichText", indent + 1, true));
nodes.Add(new TypeTreeNode("int", "m_TextClipping", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_ImagePosition", indent + 1, false));
AddVector2f(nodes, "m_ContentOffset", indent + 1);
nodes.Add(new TypeTreeNode("float", "m_FixedWidth", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "m_FixedHeight", indent + 1, false));
nodes.Add(new TypeTreeNode("bool", "m_StretchWidth", indent + 1, false));
nodes.Add(new TypeTreeNode("bool", "m_StretchHeight", indent + 1, true));
}
else
{
nodes.Add(new TypeTreeNode("int", "m_ImagePosition", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_Alignment", indent + 1, false));
nodes.Add(new TypeTreeNode("bool", "m_WordWrap", indent + 1, true));
nodes.Add(new TypeTreeNode("int", "m_TextClipping", indent + 1, false));
AddVector2f(nodes, "m_ContentOffset", indent + 1);
AddVector2f(nodes, "m_ClipOffset", indent + 1);
nodes.Add(new TypeTreeNode("float", "m_FixedWidth", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "m_FixedHeight", indent + 1, false));
if (version[0] >= 3) //3 and up
{
nodes.Add(new TypeTreeNode("int", "m_FontSize", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_FontStyle", indent + 1, false));
}
nodes.Add(new TypeTreeNode("bool", "m_StretchWidth", indent + 1, true));
nodes.Add(new TypeTreeNode("bool", "m_StretchHeight", indent + 1, true));
}
}
public void AddGUIStyleState(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("GUIStyleState", name, indent, false));
AddPPtr(nodes, "Texture2D", "m_Background", indent + 1);
AddColorRGBA(nodes, "m_TextColor", indent + 1);
}
public void AddVector2f(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("Vector2f", name, indent, false));
nodes.Add(new TypeTreeNode("float", "x", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "y", indent + 1, false));
}
public void AddRectOffset(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("RectOffset", name, indent, false));
nodes.Add(new TypeTreeNode("int", "m_Left", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_Right", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_Top", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_Bottom", indent + 1, false));
}
public void AddColorRGBA(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("ColorRGBA", name, indent, false));
nodes.Add(new TypeTreeNode("float", "r", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "g", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "b", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "a", indent + 1, false));
}
public void AddColor32(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("ColorRGBA", name, indent, false));
nodes.Add(new TypeTreeNode("unsigned int", "rgba", indent + 1, false));
}
public void AddMatrix4x4(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("Matrix4x4f", name, indent, false));
nodes.Add(new TypeTreeNode("float", "e00", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e01", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e02", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e03", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e10", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e11", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e12", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e13", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e20", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e21", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e22", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e23", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e30", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e31", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e32", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "e33", indent + 1, false));
}
public void AddSphericalHarmonicsL2(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("SphericalHarmonicsL2", name, indent, false));
nodes.Add(new TypeTreeNode("float", "sh[ 0]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[ 1]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[ 2]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[ 3]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[ 4]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[ 5]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[ 6]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[ 7]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[ 8]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[ 9]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[10]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[11]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[12]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[13]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[14]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[15]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[16]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[17]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[18]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[19]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[20]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[21]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[22]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[23]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[24]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[25]", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "sh[26]", indent + 1, false));
}
public void AddPropertyName(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("PropertyName", name, indent, false));
AddString(nodes, "id", indent + 1);
}
}
}
+112 -62
View File
@@ -9,7 +9,7 @@ namespace AssetStudio
{
public static class ShaderConverter
{
public static string Convert(Shader shader)
public static string Convert(this Shader shader)
{
if (shader.m_SubProgramBlob != null) //5.3 - 5.4
{
@@ -21,47 +21,40 @@ namespace AssetStudio
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
{
var program = new ShaderProgram(blobReader, shader.version);
return program.Export(Encoding.UTF8.GetString(shader.m_Script));
return header + program.Export(Encoding.UTF8.GetString(shader.m_Script));
}
}
if (shader.compressedBlob != null) //5.5 and up
{
return ConvertMultiple(shader)[0];
return header + ConvertSerializedShader(shader);
}
return header + Encoding.UTF8.GetString(shader.m_Script);
}
public static string[] ConvertMultiple(Shader shader)
private static string ConvertSerializedShader(Shader shader)
{
if (shader.compressedBlob != null) //5.5 and up
var shaderPrograms = new ShaderProgram[shader.platforms.Length];
for (var i = 0; i < shader.platforms.Length; i++)
{
var strs = new string[shader.platforms.Length];
for (var i = 0; i < shader.platforms.Length; i++)
var compressedBytes = new byte[shader.compressedLengths[i]];
Buffer.BlockCopy(shader.compressedBlob, (int)shader.offsets[i], compressedBytes, 0, (int)shader.compressedLengths[i]);
var decompressedBytes = new byte[shader.decompressedLengths[i]];
using (var decoder = new Lz4DecoderStream(new MemoryStream(compressedBytes)))
{
var compressedBytes = new byte[shader.compressedLengths[i]];
Buffer.BlockCopy(shader.compressedBlob, (int)shader.offsets[i], compressedBytes, 0, (int)shader.compressedLengths[i]);
var decompressedBytes = new byte[shader.decompressedLengths[i]];
using (var decoder = new Lz4DecoderStream(new MemoryStream(compressedBytes)))
{
decoder.Read(decompressedBytes, 0, (int)shader.decompressedLengths[i]);
}
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
{
var program = new ShaderProgram(blobReader, shader.version);
var m_Script = ConvertSerializedShader(shader.m_ParsedForm, shader.platforms[i]);
strs[i] = header + program.Export(m_Script);
}
decoder.Read(decompressedBytes, 0, (int)shader.decompressedLengths[i]);
}
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
{
shaderPrograms[i] = new ShaderProgram(blobReader, shader.version);
}
return strs;
}
return null;
return ConvertSerializedShader(shader.m_ParsedForm, shader.platforms, shaderPrograms);
}
private static string ConvertSerializedShader(SerializedShader m_ParsedForm, ShaderCompilerPlatform platform)
private static string ConvertSerializedShader(SerializedShader m_ParsedForm, ShaderCompilerPlatform[] platforms, ShaderProgram[] shaderPrograms)
{
var sb = new StringBuilder();
sb.Append($"Shader \"{m_ParsedForm.m_Name}\" {{\n");
@@ -70,7 +63,7 @@ namespace AssetStudio
foreach (var m_SubShader in m_ParsedForm.m_SubShaders)
{
sb.Append(ConvertSerializedSubShader(m_SubShader, platform));
sb.Append(ConvertSerializedSubShader(m_SubShader, platforms, shaderPrograms));
}
if (!string.IsNullOrEmpty(m_ParsedForm.m_FallbackName))
@@ -87,7 +80,7 @@ namespace AssetStudio
return sb.ToString();
}
private static string ConvertSerializedSubShader(SerializedSubShader m_SubShader, ShaderCompilerPlatform platform)
private static string ConvertSerializedSubShader(SerializedSubShader m_SubShader, ShaderCompilerPlatform[] platforms, ShaderProgram[] shaderPrograms)
{
var sb = new StringBuilder();
sb.Append("SubShader {\n");
@@ -100,13 +93,13 @@ namespace AssetStudio
foreach (var m_Passe in m_SubShader.m_Passes)
{
sb.Append(ConvertSerializedPass(m_Passe, platform));
sb.Append(ConvertSerializedPass(m_Passe, platforms, shaderPrograms));
}
sb.Append("}\n");
return sb.ToString();
}
private static string ConvertSerializedPass(SerializedPass m_Passe, ShaderCompilerPlatform platform)
private static string ConvertSerializedPass(SerializedPass m_Passe, ShaderCompilerPlatform[] platforms, ShaderProgram[] shaderPrograms)
{
var sb = new StringBuilder();
switch (m_Passe.m_Type)
@@ -143,35 +136,42 @@ namespace AssetStudio
if (m_Passe.progVertex.m_SubPrograms.Length > 0)
{
sb.Append("Program \"vp\" {\n");
sb.Append(ConvertSerializedSubPrograms(m_Passe.progVertex.m_SubPrograms, platform));
sb.Append(ConvertSerializedSubPrograms(m_Passe.progVertex.m_SubPrograms, platforms, shaderPrograms));
sb.Append("}\n");
}
if (m_Passe.progFragment.m_SubPrograms.Length > 0)
{
sb.Append("Program \"fp\" {\n");
sb.Append(ConvertSerializedSubPrograms(m_Passe.progFragment.m_SubPrograms, platform));
sb.Append(ConvertSerializedSubPrograms(m_Passe.progFragment.m_SubPrograms, platforms, shaderPrograms));
sb.Append("}\n");
}
if (m_Passe.progGeometry.m_SubPrograms.Length > 0)
{
sb.Append("Program \"gp\" {\n");
sb.Append(ConvertSerializedSubPrograms(m_Passe.progGeometry.m_SubPrograms, platform));
sb.Append(ConvertSerializedSubPrograms(m_Passe.progGeometry.m_SubPrograms, platforms, shaderPrograms));
sb.Append("}\n");
}
if (m_Passe.progHull.m_SubPrograms.Length > 0)
{
sb.Append("Program \"hp\" {\n");
sb.Append(ConvertSerializedSubPrograms(m_Passe.progHull.m_SubPrograms, platform));
sb.Append(ConvertSerializedSubPrograms(m_Passe.progHull.m_SubPrograms, platforms, shaderPrograms));
sb.Append("}\n");
}
if (m_Passe.progDomain.m_SubPrograms.Length > 0)
{
sb.Append("Program \"dp\" {\n");
sb.Append(ConvertSerializedSubPrograms(m_Passe.progDomain.m_SubPrograms, platform));
sb.Append(ConvertSerializedSubPrograms(m_Passe.progDomain.m_SubPrograms, platforms, shaderPrograms));
sb.Append("}\n");
}
if (m_Passe.progRayTracing?.m_SubPrograms.Length > 0)
{
sb.Append("Program \"rtp\" {\n");
sb.Append(ConvertSerializedSubPrograms(m_Passe.progRayTracing.m_SubPrograms, platforms, shaderPrograms));
sb.Append("}\n");
}
}
@@ -180,7 +180,7 @@ namespace AssetStudio
return sb.ToString();
}
private static string ConvertSerializedSubPrograms(SerializedSubProgram[] m_SubPrograms, ShaderCompilerPlatform platform)
private static string ConvertSerializedSubPrograms(SerializedSubProgram[] m_SubPrograms, ShaderCompilerPlatform[] platforms, ShaderProgram[] shaderPrograms)
{
var sb = new StringBuilder();
var groups = m_SubPrograms.GroupBy(x => x.m_BlobIndex);
@@ -189,22 +189,26 @@ namespace AssetStudio
var programs = group.GroupBy(x => x.m_GpuProgramType);
foreach (var program in programs)
{
if (CheckGpuProgramUsable(platform, program.Key))
for (int i = 0; i < platforms.Length; i++)
{
var subPrograms = program.ToList();
var isTier = subPrograms.Count > 1;
foreach (var subProgram in subPrograms)
var platform = platforms[i];
if (CheckGpuProgramUsable(platform, program.Key))
{
sb.Append($"SubProgram \"{GetPlatformString(platform)} ");
if (isTier)
var subPrograms = program.ToList();
var isTier = subPrograms.Count > 1;
foreach (var subProgram in subPrograms)
{
sb.Append($"hw_tier{subProgram.m_ShaderHardwareTier:00} ");
sb.Append($"SubProgram \"{GetPlatformString(platform)} ");
if (isTier)
{
sb.Append($"hw_tier{subProgram.m_ShaderHardwareTier:00} ");
}
sb.Append("\" {\n");
sb.Append(shaderPrograms[i].m_SubPrograms[subProgram.m_BlobIndex].Export());
sb.Append("\n}\n");
}
sb.Append("\" {\n");
sb.Append($"GpuProgramIndex {subProgram.m_BlobIndex}\n");
sb.Append("}\n");
break;
}
break;
}
}
}
@@ -439,9 +443,17 @@ namespace AssetStudio
|| programType == ShaderGpuProgramType.kShaderGpuProgramDX9PixelSM20
|| programType == ShaderGpuProgramType.kShaderGpuProgramDX9PixelSM30;
case ShaderCompilerPlatform.kShaderCompPlatformXbox360:
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
case ShaderCompilerPlatform.kShaderCompPlatformPS3:
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
case ShaderCompilerPlatform.kShaderCompPlatformD3D11:
return programType == ShaderGpuProgramType.kShaderGpuProgramDX11VertexSM40
|| programType == ShaderGpuProgramType.kShaderGpuProgramDX11VertexSM50
@@ -465,11 +477,23 @@ namespace AssetStudio
|| programType == ShaderGpuProgramType.kShaderGpuProgramGLES31
|| programType == ShaderGpuProgramType.kShaderGpuProgramGLES3;
case ShaderCompilerPlatform.kShaderCompPlatformPSP2:
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
case ShaderCompilerPlatform.kShaderCompPlatformPS4:
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
case ShaderCompilerPlatform.kShaderCompPlatformXboxOne:
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
case ShaderCompilerPlatform.kShaderCompPlatformPSM: //Unknown
throw new NotSupportedException();
case ShaderCompilerPlatform.kShaderCompPlatformMetal:
@@ -480,15 +504,31 @@ namespace AssetStudio
|| programType == ShaderGpuProgramType.kShaderGpuProgramGLCore41
|| programType == ShaderGpuProgramType.kShaderGpuProgramGLCore43;
case ShaderCompilerPlatform.kShaderCompPlatformN3DS:
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
case ShaderCompilerPlatform.kShaderCompPlatformWiiU:
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
case ShaderCompilerPlatform.kShaderCompPlatformVulkan:
return programType == ShaderGpuProgramType.kShaderGpuProgramSPIRV;
case ShaderCompilerPlatform.kShaderCompPlatformSwitch:
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
case ShaderCompilerPlatform.kShaderCompPlatformXboxOneD3D12:
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
default:
throw new NotSupportedException();
}
@@ -554,7 +594,7 @@ namespace AssetStudio
public class ShaderProgram
{
private ShaderSubProgram[] m_SubPrograms;
public ShaderSubProgram[] m_SubPrograms;
public ShaderProgram(BinaryReader reader, int[] version)
{
@@ -607,7 +647,7 @@ namespace AssetStudio
//201609010 - Unity 5.6, 2017.1 & 2017.2
//201708220 - Unity 2017.3, Unity 2017.4 & Unity 2018.1
//201802150 - Unity 2018.2 & Unity 2018.3
//201806140 - Unity 2019.1
//201806140 - Unity 2019.1~2020.1
m_Version = reader.ReadInt32();
m_ProgramType = (ShaderGpuProgramType)reader.ReadInt32();
reader.BaseStream.Position += 12;
@@ -630,7 +670,7 @@ namespace AssetStudio
m_LocalKeywords[i] = reader.ReadAlignedString();
}
}
m_ProgramCode = reader.ReadBytes(reader.ReadInt32());
m_ProgramCode = reader.ReadUInt8Array();
reader.AlignStream();
//TODO
@@ -694,14 +734,14 @@ namespace AssetStudio
case ShaderGpuProgramType.kShaderGpuProgramDX11HullSM50:
case ShaderGpuProgramType.kShaderGpuProgramDX11DomainSM50:
{
int start = 6;
/*int start = 6;
if (m_Version == 201509030) // 5.3
{
start = 5;
}
var buff = new byte[m_ProgramCode.Length - start];
Buffer.BlockCopy(m_ProgramCode, start, buff, 0, buff.Length);
/*var shaderBytecode = new ShaderBytecode(buff);
var shaderBytecode = new ShaderBytecode(buff);
sb.Append(shaderBytecode.Disassemble());*/
sb.Append("// shader disassembly not supported on DXBC");
break;
@@ -722,10 +762,20 @@ namespace AssetStudio
}
break;
case ShaderGpuProgramType.kShaderGpuProgramSPIRV:
sb.Append("// shader disassembly not supported on SPIR-V\n");
sb.Append("// https://github.com/KhronosGroup/SPIRV-Cross");
try
{
sb.Append(SpirVShaderConverter.Convert(m_ProgramCode));
}
catch (Exception e)
{
sb.Append($"// disassembly error {e.Message}\n");
}
break;
case ShaderGpuProgramType.kShaderGpuProgramConsole:
case ShaderGpuProgramType.kShaderGpuProgramConsoleVS:
case ShaderGpuProgramType.kShaderGpuProgramConsoleFS:
case ShaderGpuProgramType.kShaderGpuProgramConsoleHS:
case ShaderGpuProgramType.kShaderGpuProgramConsoleDS:
case ShaderGpuProgramType.kShaderGpuProgramConsoleGS:
sb.Append(Encoding.UTF8.GetString(m_ProgramCode));
break;
default:
+365
View File
@@ -0,0 +1,365 @@
namespace Smolv
{
public struct OpData
{
public OpData(byte hasResult, byte hasType, sbyte deltaFromResult, byte varrest)
{
this.hasResult = hasResult;
this.hasType = hasType;
this.deltaFromResult = deltaFromResult;
this.varrest = varrest;
}
/// <summary>
/// Does it have result ID?
/// </summary>
public byte hasResult;
/// <summary>
/// Does it have type ID?
/// </summary>
public byte hasType;
/// <summary>
/// How many words after (optional) type+result to write out as deltas from result?
/// </summary>
public sbyte deltaFromResult;
/// <summary>
/// Should the rest of words be written in varint encoding?
/// </summary>
public byte varrest;
public static readonly OpData[] SpirvOpData =
{
new OpData(0, 0, 0, 0), // Nop
new OpData(1, 1, 0, 0), // Undef
new OpData(0, 0, 0, 0), // SourceContinued
new OpData(0, 0, 0, 1), // Source
new OpData(0, 0, 0, 0), // SourceExtension
new OpData(0, 0, 0, 0), // Name
new OpData(0, 0, 0, 0), // MemberName
new OpData(0, 0, 0, 0), // String
new OpData(0, 0, 0, 1), // Line
new OpData(1, 1, 0, 0), // #9
new OpData(0, 0, 0, 0), // Extension
new OpData(1, 0, 0, 0), // ExtInstImport
new OpData(1, 1, 0, 1), // ExtInst
new OpData(1, 1, 2, 1), // VectorShuffleCompact - new in SMOLV
new OpData(0, 0, 0, 1), // MemoryModel
new OpData(0, 0, 0, 1), // EntryPoint
new OpData(0, 0, 0, 1), // ExecutionMode
new OpData(0, 0, 0, 1), // Capability
new OpData(1, 1, 0, 0), // #18
new OpData(1, 0, 0, 1), // TypeVoid
new OpData(1, 0, 0, 1), // TypeBool
new OpData(1, 0, 0, 1), // TypeInt
new OpData(1, 0, 0, 1), // TypeFloat
new OpData(1, 0, 0, 1), // TypeVector
new OpData(1, 0, 0, 1), // TypeMatrix
new OpData(1, 0, 0, 1), // TypeImage
new OpData(1, 0, 0, 1), // TypeSampler
new OpData(1, 0, 0, 1), // TypeSampledImage
new OpData(1, 0, 0, 1), // TypeArray
new OpData(1, 0, 0, 1), // TypeRuntimeArray
new OpData(1, 0, 0, 1), // TypeStruct
new OpData(1, 0, 0, 1), // TypeOpaque
new OpData(1, 0, 0, 1), // TypePointer
new OpData(1, 0, 0, 1), // TypeFunction
new OpData(1, 0, 0, 1), // TypeEvent
new OpData(1, 0, 0, 1), // TypeDeviceEvent
new OpData(1, 0, 0, 1), // TypeReserveId
new OpData(1, 0, 0, 1), // TypeQueue
new OpData(1, 0, 0, 1), // TypePipe
new OpData(0, 0, 0, 1), // TypeForwardPointer
new OpData(1, 1, 0, 0), // #40
new OpData(1, 1, 0, 0), // ConstantTrue
new OpData(1, 1, 0, 0), // ConstantFalse
new OpData(1, 1, 0, 0), // Constant
new OpData(1, 1, 9, 0), // ConstantComposite
new OpData(1, 1, 0, 1), // ConstantSampler
new OpData(1, 1, 0, 0), // ConstantNull
new OpData(1, 1, 0, 0), // #47
new OpData(1, 1, 0, 0), // SpecConstantTrue
new OpData(1, 1, 0, 0), // SpecConstantFalse
new OpData(1, 1, 0, 0), // SpecConstant
new OpData(1, 1, 9, 0), // SpecConstantComposite
new OpData(1, 1, 0, 0), // SpecConstantOp
new OpData(1, 1, 0, 0), // #53
new OpData(1, 1, 0, 1), // Function
new OpData(1, 1, 0, 0), // FunctionParameter
new OpData(0, 0, 0, 0), // FunctionEnd
new OpData(1, 1, 9, 0), // FunctionCall
new OpData(1, 1, 0, 0), // #58
new OpData(1, 1, 0, 1), // Variable
new OpData(1, 1, 0, 0), // ImageTexelPointer
new OpData(1, 1, 1, 1), // Load
new OpData(0, 0, 2, 1), // Store
new OpData(0, 0, 0, 0), // CopyMemory
new OpData(0, 0, 0, 0), // CopyMemorySized
new OpData(1, 1, 0, 1), // AccessChain
new OpData(1, 1, 0, 0), // InBoundsAccessChain
new OpData(1, 1, 0, 0), // PtrAccessChain
new OpData(1, 1, 0, 0), // ArrayLength
new OpData(1, 1, 0, 0), // GenericPtrMemSemantics
new OpData(1, 1, 0, 0), // InBoundsPtrAccessChain
new OpData(0, 0, 0, 1), // Decorate
new OpData(0, 0, 0, 1), // MemberDecorate
new OpData(1, 0, 0, 0), // DecorationGroup
new OpData(0, 0, 0, 0), // GroupDecorate
new OpData(0, 0, 0, 0), // GroupMemberDecorate
new OpData(1, 1, 0, 0), // #76
new OpData(1, 1, 1, 1), // VectorExtractDynamic
new OpData(1, 1, 2, 1), // VectorInsertDynamic
new OpData(1, 1, 2, 1), // VectorShuffle
new OpData(1, 1, 9, 0), // CompositeConstruct
new OpData(1, 1, 1, 1), // CompositeExtract
new OpData(1, 1, 2, 1), // CompositeInsert
new OpData(1, 1, 1, 0), // CopyObject
new OpData(1, 1, 0, 0), // Transpose
new OpData(1, 1, 0, 0), // #85
new OpData(1, 1, 0, 0), // SampledImage
new OpData(1, 1, 2, 1), // ImageSampleImplicitLod
new OpData(1, 1, 2, 1), // ImageSampleExplicitLod
new OpData(1, 1, 3, 1), // ImageSampleDrefImplicitLod
new OpData(1, 1, 3, 1), // ImageSampleDrefExplicitLod
new OpData(1, 1, 2, 1), // ImageSampleProjImplicitLod
new OpData(1, 1, 2, 1), // ImageSampleProjExplicitLod
new OpData(1, 1, 3, 1), // ImageSampleProjDrefImplicitLod
new OpData(1, 1, 3, 1), // ImageSampleProjDrefExplicitLod
new OpData(1, 1, 2, 1), // ImageFetch
new OpData(1, 1, 3, 1), // ImageGather
new OpData(1, 1, 3, 1), // ImageDrefGather
new OpData(1, 1, 2, 1), // ImageRead
new OpData(0, 0, 3, 1), // ImageWrite
new OpData(1, 1, 1, 0), // Image
new OpData(1, 1, 1, 0), // ImageQueryFormat
new OpData(1, 1, 1, 0), // ImageQueryOrder
new OpData(1, 1, 2, 0), // ImageQuerySizeLod
new OpData(1, 1, 1, 0), // ImageQuerySize
new OpData(1, 1, 2, 0), // ImageQueryLod
new OpData(1, 1, 1, 0), // ImageQueryLevels
new OpData(1, 1, 1, 0), // ImageQuerySamples
new OpData(1, 1, 0, 0), // #108
new OpData(1, 1, 1, 0), // ConvertFToU
new OpData(1, 1, 1, 0), // ConvertFToS
new OpData(1, 1, 1, 0), // ConvertSToF
new OpData(1, 1, 1, 0), // ConvertUToF
new OpData(1, 1, 1, 0), // UConvert
new OpData(1, 1, 1, 0), // SConvert
new OpData(1, 1, 1, 0), // FConvert
new OpData(1, 1, 1, 0), // QuantizeToF16
new OpData(1, 1, 1, 0), // ConvertPtrToU
new OpData(1, 1, 1, 0), // SatConvertSToU
new OpData(1, 1, 1, 0), // SatConvertUToS
new OpData(1, 1, 1, 0), // ConvertUToPtr
new OpData(1, 1, 1, 0), // PtrCastToGeneric
new OpData(1, 1, 1, 0), // GenericCastToPtr
new OpData(1, 1, 1, 1), // GenericCastToPtrExplicit
new OpData(1, 1, 1, 0), // Bitcast
new OpData(1, 1, 0, 0), // #125
new OpData(1, 1, 1, 0), // SNegate
new OpData(1, 1, 1, 0), // FNegate
new OpData(1, 1, 2, 0), // IAdd
new OpData(1, 1, 2, 0), // FAdd
new OpData(1, 1, 2, 0), // ISub
new OpData(1, 1, 2, 0), // FSub
new OpData(1, 1, 2, 0), // IMul
new OpData(1, 1, 2, 0), // FMul
new OpData(1, 1, 2, 0), // UDiv
new OpData(1, 1, 2, 0), // SDiv
new OpData(1, 1, 2, 0), // FDiv
new OpData(1, 1, 2, 0), // UMod
new OpData(1, 1, 2, 0), // SRem
new OpData(1, 1, 2, 0), // SMod
new OpData(1, 1, 2, 0), // FRem
new OpData(1, 1, 2, 0), // FMod
new OpData(1, 1, 2, 0), // VectorTimesScalar
new OpData(1, 1, 2, 0), // MatrixTimesScalar
new OpData(1, 1, 2, 0), // VectorTimesMatrix
new OpData(1, 1, 2, 0), // MatrixTimesVector
new OpData(1, 1, 2, 0), // MatrixTimesMatrix
new OpData(1, 1, 2, 0), // OuterProduct
new OpData(1, 1, 2, 0), // Dot
new OpData(1, 1, 2, 0), // IAddCarry
new OpData(1, 1, 2, 0), // ISubBorrow
new OpData(1, 1, 2, 0), // UMulExtended
new OpData(1, 1, 2, 0), // SMulExtended
new OpData(1, 1, 0, 0), // #153
new OpData(1, 1, 1, 0), // Any
new OpData(1, 1, 1, 0), // All
new OpData(1, 1, 1, 0), // IsNan
new OpData(1, 1, 1, 0), // IsInf
new OpData(1, 1, 1, 0), // IsFinite
new OpData(1, 1, 1, 0), // IsNormal
new OpData(1, 1, 1, 0), // SignBitSet
new OpData(1, 1, 2, 0), // LessOrGreater
new OpData(1, 1, 2, 0), // Ordered
new OpData(1, 1, 2, 0), // Unordered
new OpData(1, 1, 2, 0), // LogicalEqual
new OpData(1, 1, 2, 0), // LogicalNotEqual
new OpData(1, 1, 2, 0), // LogicalOr
new OpData(1, 1, 2, 0), // LogicalAnd
new OpData(1, 1, 1, 0), // LogicalNot
new OpData(1, 1, 3, 0), // Select
new OpData(1, 1, 2, 0), // IEqual
new OpData(1, 1, 2, 0), // INotEqual
new OpData(1, 1, 2, 0), // UGreaterThan
new OpData(1, 1, 2, 0), // SGreaterThan
new OpData(1, 1, 2, 0), // UGreaterThanEqual
new OpData(1, 1, 2, 0), // SGreaterThanEqual
new OpData(1, 1, 2, 0), // ULessThan
new OpData(1, 1, 2, 0), // SLessThan
new OpData(1, 1, 2, 0), // ULessThanEqual
new OpData(1, 1, 2, 0), // SLessThanEqual
new OpData(1, 1, 2, 0), // FOrdEqual
new OpData(1, 1, 2, 0), // FUnordEqual
new OpData(1, 1, 2, 0), // FOrdNotEqual
new OpData(1, 1, 2, 0), // FUnordNotEqual
new OpData(1, 1, 2, 0), // FOrdLessThan
new OpData(1, 1, 2, 0), // FUnordLessThan
new OpData(1, 1, 2, 0), // FOrdGreaterThan
new OpData(1, 1, 2, 0), // FUnordGreaterThan
new OpData(1, 1, 2, 0), // FOrdLessThanEqual
new OpData(1, 1, 2, 0), // FUnordLessThanEqual
new OpData(1, 1, 2, 0), // FOrdGreaterThanEqual
new OpData(1, 1, 2, 0), // FUnordGreaterThanEqual
new OpData(1, 1, 0, 0), // #192
new OpData(1, 1, 0, 0), // #193
new OpData(1, 1, 2, 0), // ShiftRightLogical
new OpData(1, 1, 2, 0), // ShiftRightArithmetic
new OpData(1, 1, 2, 0), // ShiftLeftLogical
new OpData(1, 1, 2, 0), // BitwiseOr
new OpData(1, 1, 2, 0), // BitwiseXor
new OpData(1, 1, 2, 0), // BitwiseAnd
new OpData(1, 1, 1, 0), // Not
new OpData(1, 1, 4, 0), // BitFieldInsert
new OpData(1, 1, 3, 0), // BitFieldSExtract
new OpData(1, 1, 3, 0), // BitFieldUExtract
new OpData(1, 1, 1, 0), // BitReverse
new OpData(1, 1, 1, 0), // BitCount
new OpData(1, 1, 0, 0), // #206
new OpData(1, 1, 0, 0), // DPdx
new OpData(1, 1, 0, 0), // DPdy
new OpData(1, 1, 0, 0), // Fwidth
new OpData(1, 1, 0, 0), // DPdxFine
new OpData(1, 1, 0, 0), // DPdyFine
new OpData(1, 1, 0, 0), // FwidthFine
new OpData(1, 1, 0, 0), // DPdxCoarse
new OpData(1, 1, 0, 0), // DPdyCoarse
new OpData(1, 1, 0, 0), // FwidthCoarse
new OpData(1, 1, 0, 0), // #216
new OpData(1, 1, 0, 0), // #217
new OpData(0, 0, 0, 0), // EmitVertex
new OpData(0, 0, 0, 0), // EndPrimitive
new OpData(0, 0, 0, 0), // EmitStreamVertex
new OpData(0, 0, 0, 0), // EndStreamPrimitive
new OpData(1, 1, 0, 0), // #222
new OpData(1, 1, 0, 0), // #223
new OpData(0, 0, -3, 0), // ControlBarrier
new OpData(0, 0, -2, 0), // MemoryBarrier
new OpData(1, 1, 0, 0), // #226
new OpData(1, 1, 0, 0), // AtomicLoad
new OpData(0, 0, 0, 0), // AtomicStore
new OpData(1, 1, 0, 0), // AtomicExchange
new OpData(1, 1, 0, 0), // AtomicCompareExchange
new OpData(1, 1, 0, 0), // AtomicCompareExchangeWeak
new OpData(1, 1, 0, 0), // AtomicIIncrement
new OpData(1, 1, 0, 0), // AtomicIDecrement
new OpData(1, 1, 0, 0), // AtomicIAdd
new OpData(1, 1, 0, 0), // AtomicISub
new OpData(1, 1, 0, 0), // AtomicSMin
new OpData(1, 1, 0, 0), // AtomicUMin
new OpData(1, 1, 0, 0), // AtomicSMax
new OpData(1, 1, 0, 0), // AtomicUMax
new OpData(1, 1, 0, 0), // AtomicAnd
new OpData(1, 1, 0, 0), // AtomicOr
new OpData(1, 1, 0, 0), // AtomicXor
new OpData(1, 1, 0, 0), // #243
new OpData(1, 1, 0, 0), // #244
new OpData(1, 1, 0, 0), // Phi
new OpData(0, 0, -2, 1), // LoopMerge
new OpData(0, 0, -1, 1), // SelectionMerge
new OpData(1, 0, 0, 0), // Label
new OpData(0, 0, -1, 0), // Branch
new OpData(0, 0, -3, 1), // BranchConditional
new OpData(0, 0, 0, 0), // Switch
new OpData(0, 0, 0, 0), // Kill
new OpData(0, 0, 0, 0), // Return
new OpData(0, 0, 0, 0), // ReturnValue
new OpData(0, 0, 0, 0), // Unreachable
new OpData(0, 0, 0, 0), // LifetimeStart
new OpData(0, 0, 0, 0), // LifetimeStop
new OpData(1, 1, 0, 0), // #258
new OpData(1, 1, 0, 0), // GroupAsyncCopy
new OpData(0, 0, 0, 0), // GroupWaitEvents
new OpData(1, 1, 0, 0), // GroupAll
new OpData(1, 1, 0, 0), // GroupAny
new OpData(1, 1, 0, 0), // GroupBroadcast
new OpData(1, 1, 0, 0), // GroupIAdd
new OpData(1, 1, 0, 0), // GroupFAdd
new OpData(1, 1, 0, 0), // GroupFMin
new OpData(1, 1, 0, 0), // GroupUMin
new OpData(1, 1, 0, 0), // GroupSMin
new OpData(1, 1, 0, 0), // GroupFMax
new OpData(1, 1, 0, 0), // GroupUMax
new OpData(1, 1, 0, 0), // GroupSMax
new OpData(1, 1, 0, 0), // #272
new OpData(1, 1, 0, 0), // #273
new OpData(1, 1, 0, 0), // ReadPipe
new OpData(1, 1, 0, 0), // WritePipe
new OpData(1, 1, 0, 0), // ReservedReadPipe
new OpData(1, 1, 0, 0), // ReservedWritePipe
new OpData(1, 1, 0, 0), // ReserveReadPipePackets
new OpData(1, 1, 0, 0), // ReserveWritePipePackets
new OpData(0, 0, 0, 0), // CommitReadPipe
new OpData(0, 0, 0, 0), // CommitWritePipe
new OpData(1, 1, 0, 0), // IsValidReserveId
new OpData(1, 1, 0, 0), // GetNumPipePackets
new OpData(1, 1, 0, 0), // GetMaxPipePackets
new OpData(1, 1, 0, 0), // GroupReserveReadPipePackets
new OpData(1, 1, 0, 0), // GroupReserveWritePipePackets
new OpData(0, 0, 0, 0), // GroupCommitReadPipe
new OpData(0, 0, 0, 0), // GroupCommitWritePipe
new OpData(1, 1, 0, 0), // #289
new OpData(1, 1, 0, 0), // #290
new OpData(1, 1, 0, 0), // EnqueueMarker
new OpData(1, 1, 0, 0), // EnqueueKernel
new OpData(1, 1, 0, 0), // GetKernelNDrangeSubGroupCount
new OpData(1, 1, 0, 0), // GetKernelNDrangeMaxSubGroupSize
new OpData(1, 1, 0, 0), // GetKernelWorkGroupSize
new OpData(1, 1, 0, 0), // GetKernelPreferredWorkGroupSizeMultiple
new OpData(0, 0, 0, 0), // RetainEvent
new OpData(0, 0, 0, 0), // ReleaseEvent
new OpData(1, 1, 0, 0), // CreateUserEvent
new OpData(1, 1, 0, 0), // IsValidEvent
new OpData(0, 0, 0, 0), // SetUserEventStatus
new OpData(0, 0, 0, 0), // CaptureEventProfilingInfo
new OpData(1, 1, 0, 0), // GetDefaultQueue
new OpData(1, 1, 0, 0), // BuildNDRange
new OpData(1, 1, 2, 1), // ImageSparseSampleImplicitLod
new OpData(1, 1, 2, 1), // ImageSparseSampleExplicitLod
new OpData(1, 1, 3, 1), // ImageSparseSampleDrefImplicitLod
new OpData(1, 1, 3, 1), // ImageSparseSampleDrefExplicitLod
new OpData(1, 1, 2, 1), // ImageSparseSampleProjImplicitLod
new OpData(1, 1, 2, 1), // ImageSparseSampleProjExplicitLod
new OpData(1, 1, 3, 1), // ImageSparseSampleProjDrefImplicitLod
new OpData(1, 1, 3, 1), // ImageSparseSampleProjDrefExplicitLod
new OpData(1, 1, 2, 1), // ImageSparseFetch
new OpData(1, 1, 3, 1), // ImageSparseGather
new OpData(1, 1, 3, 1), // ImageSparseDrefGather
new OpData(1, 1, 1, 0), // ImageSparseTexelsResident
new OpData(0, 0, 0, 0), // NoLine
new OpData(1, 1, 0, 0), // AtomicFlagTestAndSet
new OpData(0, 0, 0, 0), // AtomicFlagClear
new OpData(1, 1, 0, 0), // ImageSparseRead
new OpData(1, 1, 0, 0), // SizeOf
new OpData(1, 1, 0, 0), // TypePipeStorage
new OpData(1, 1, 0, 0), // ConstantPipeStorage
new OpData(1, 1, 0, 0), // CreatePipeFromPipeStorage
new OpData(1, 1, 0, 0), // GetKernelLocalSizeForSubgroupCount
new OpData(1, 1, 0, 0), // GetKernelMaxNumSubgroups
new OpData(1, 1, 0, 0), // TypeNamedBarrier
new OpData(1, 1, 0, 1), // NamedBarrierInitialize
new OpData(0, 0, -2, 1), // MemoryNamedBarrier
new OpData(1, 1, 0, 0), // ModuleProcessed
};
};
}
+479
View File
@@ -0,0 +1,479 @@
using System;
using System.IO;
using System.Text;
namespace Smolv
{
public static class SmolvDecoder
{
public static int GetDecodedBufferSize(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (!CheckSmolHeader(data))
{
return 0;
}
int size = BitConverter.ToInt32(data, 5 * sizeof(uint));
return size;
}
public static int GetDecodedBufferSize(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
if (!stream.CanSeek)
{
throw new ArgumentException(nameof(stream));
}
if (stream.Position + HeaderSize > stream.Length)
{
return 0;
}
long initPosition = stream.Position;
stream.Position += HeaderSize - sizeof(uint);
int size = stream.ReadByte() | stream.ReadByte() << 8 | stream.ReadByte() << 16 | stream.ReadByte() << 24;
stream.Position = initPosition;
return size;
}
public static byte[] Decode(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
int bufferSize = GetDecodedBufferSize(data);
if (bufferSize == 0)
{
// invalid SMOL-V
return null;
}
byte[] output = new byte[bufferSize];
if (Decode(data, output))
{
return output;
}
return null;
}
public static bool Decode(byte[] data, byte[] output)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
int bufferSize = GetDecodedBufferSize(data);
if (bufferSize > output.Length)
{
return false;
}
using (MemoryStream outputStream = new MemoryStream(output))
{
return Decode(data, outputStream);
}
}
public static bool Decode(byte[] data, Stream outputStream)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
using (MemoryStream inputStream = new MemoryStream(data))
{
return Decode(inputStream, data.Length, outputStream);
}
}
public static bool Decode(Stream inputStream, int inputSize, Stream outputStream)
{
if (inputStream == null)
{
throw new ArgumentNullException(nameof(inputStream));
}
if (outputStream == null)
{
throw new ArgumentNullException(nameof(outputStream));
}
if (inputStream.Length < HeaderSize)
{
return false;
}
using (BinaryReader input = new BinaryReader(inputStream, Encoding.UTF8, true))
{
using (BinaryWriter output = new BinaryWriter(outputStream, Encoding.UTF8, true))
{
long inputEndPosition = input.BaseStream.Position + inputSize;
long outputStartPosition = output.BaseStream.Position;
// Header
output.Write(SpirVHeaderMagic);
input.BaseStream.Position += sizeof(uint);
uint version = input.ReadUInt32();
output.Write(version);
uint generator = input.ReadUInt32();
output.Write(generator);
int bound = input.ReadInt32();
output.Write(bound);
uint schema = input.ReadUInt32();
output.Write(schema);
int decodedSize = input.ReadInt32();
// Body
int prevResult = 0;
int prevDecorate = 0;
while (input.BaseStream.Position < inputEndPosition)
{
// read length + opcode
if (!ReadLengthOp(input, out uint instrLen, out SpvOp op))
{
return false;
}
bool wasSwizzle = op == SpvOp.VectorShuffleCompact;
if (wasSwizzle)
{
op = SpvOp.VectorShuffle;
}
output.Write((instrLen << 16) | (uint)op);
uint ioffs = 1;
// read type as varint, if we have it
if (op.OpHasType())
{
if (!ReadVarint(input, out uint value))
{
return false;
}
output.Write(value);
ioffs++;
}
// read result as delta+varint, if we have it
if (op.OpHasResult())
{
if (!ReadVarint(input, out uint value))
{
return false;
}
int zds = prevResult + ZigDecode(value);
output.Write(zds);
prevResult = zds;
ioffs++;
}
// Decorate: IDs relative to previous decorate
if (op == SpvOp.Decorate || op == SpvOp.MemberDecorate)
{
if (!ReadVarint(input, out uint value))
{
return false;
}
int zds = prevDecorate + unchecked((int)value);
output.Write(zds);
prevDecorate = zds;
ioffs++;
}
// Read this many IDs, that are relative to result ID
int relativeCount = op.OpDeltaFromResult();
bool inverted = false;
if (relativeCount < 0)
{
inverted = true;
relativeCount = -relativeCount;
}
for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
{
if (!ReadVarint(input, out uint value))
{
return false;
}
int zd = inverted ? ZigDecode(value) : unchecked((int)value);
output.Write(prevResult - zd);
}
if (wasSwizzle && instrLen <= 9)
{
uint swizzle = input.ReadByte();
if (instrLen > 5) output.Write(swizzle >> 6);
if (instrLen > 6) output.Write((swizzle >> 4) & 3);
if (instrLen > 7) output.Write((swizzle >> 2) & 3);
if (instrLen > 8) output.Write(swizzle & 3);
}
else if (op.OpVarRest())
{
// read rest of words with variable encoding
for (; ioffs < instrLen; ++ioffs)
{
if (!ReadVarint(input, out uint value))
{
return false;
}
output.Write(value);
}
}
else
{
// read rest of words without any encoding
for (; ioffs < instrLen; ++ioffs)
{
if (input.BaseStream.Position + 4 > input.BaseStream.Length)
{
return false;
}
uint val = input.ReadUInt32();
output.Write(val);
}
}
}
if (output.BaseStream.Position != outputStartPosition + decodedSize)
{
// something went wrong during decoding? we should have decoded to exact output size
return false;
}
return true;
}
}
}
private static bool CheckSmolHeader(byte[] data)
{
if (!CheckGenericHeader(data, SmolHeaderMagic))
{
return false;
}
return true;
}
private static bool CheckGenericHeader(byte[] data, uint expectedMagic)
{
if (data == null)
{
return false;
}
if (data.Length < HeaderSize)
{
return false;
}
uint headerMagic = BitConverter.ToUInt32(data, 0 * sizeof(uint));
if (headerMagic != expectedMagic)
{
return false;
}
uint headerVersion = BitConverter.ToUInt32(data, 1 * sizeof(uint));
if (headerVersion < 0x00010000 || headerVersion > 0x00010300)
{
// only support 1.0 through 1.3
return false;
}
return true;
}
private static bool ReadVarint(BinaryReader input, out uint value)
{
uint v = 0;
int shift = 0;
while (input.BaseStream.Position < input.BaseStream.Length)
{
byte b = input.ReadByte();
v |= unchecked((uint)(b & 127) << shift);
shift += 7;
if ((b & 128) == 0)
{
break;
}
}
value = v;
// @TODO: report failures
return true;
}
private static bool ReadLengthOp(BinaryReader input, out uint len, out SpvOp op)
{
len = default;
op = default;
if (!ReadVarint(input, out uint value))
{
return false;
}
len = ((value >> 20) << 4) | ((value >> 4) & 0xF);
op = (SpvOp) (((value >> 4) & 0xFFF0) | (value & 0xF));
op = RemapOp(op);
len = DecodeLen(op, len);
return true;
}
/// <summary>
/// Remap most common Op codes (Load, Store, Decorate, VectorShuffle etc.) to be in &lt; 16 range, for
/// more compact varint encoding. This basically swaps rarely used op values that are &lt; 16 with the
/// ones that are common.
/// </summary>
private static SpvOp RemapOp(SpvOp op)
{
switch (op)
{
// 0: 24%
case SpvOp.Decorate:
return SpvOp.Nop;
case SpvOp.Nop:
return SpvOp.Decorate;
// 1: 17%
case SpvOp.Load:
return SpvOp.Undef;
case SpvOp.Undef:
return SpvOp.Load;
// 2: 9%
case SpvOp.Store:
return SpvOp.SourceContinued;
case SpvOp.SourceContinued:
return SpvOp.Store;
// 3: 7.2%
case SpvOp.AccessChain:
return SpvOp.Source;
case SpvOp.Source:
return SpvOp.AccessChain;
// 4: 5.0%
// Name - already small enum value - 5: 4.4%
// MemberName - already small enum value - 6: 2.9%
case SpvOp.VectorShuffle:
return SpvOp.SourceExtension;
case SpvOp.SourceExtension:
return SpvOp.VectorShuffle;
// 7: 4.0%
case SpvOp.MemberDecorate:
return SpvOp.String;
case SpvOp.String:
return SpvOp.MemberDecorate;
// 8: 0.9%
case SpvOp.Label:
return SpvOp.Line;
case SpvOp.Line:
return SpvOp.Label;
// 9: 3.9%
case SpvOp.Variable:
return (SpvOp)9;
case (SpvOp)9:
return SpvOp.Variable;
// 10: 3.9%
case SpvOp.FMul:
return SpvOp.Extension;
case SpvOp.Extension:
return SpvOp.FMul;
// 11: 2.5%
// ExtInst - already small enum value - 12: 1.2%
// VectorShuffleCompact - already small enum value - used for compact shuffle encoding
case SpvOp.FAdd:
return SpvOp.ExtInstImport;
case SpvOp.ExtInstImport:
return SpvOp.FAdd;
// 14: 2.2%
case SpvOp.TypePointer:
return SpvOp.MemoryModel;
case SpvOp.MemoryModel:
return SpvOp.TypePointer;
// 15: 1.1%
case SpvOp.FNegate:
return SpvOp.EntryPoint;
case SpvOp.EntryPoint:
return SpvOp.FNegate;
}
return op;
}
private static uint DecodeLen(SpvOp op, uint len)
{
len++;
switch (op)
{
case SpvOp.VectorShuffle:
len += 4;
break;
case SpvOp.VectorShuffleCompact:
len += 4;
break;
case SpvOp.Decorate:
len += 2;
break;
case SpvOp.Load:
len += 3;
break;
case SpvOp.AccessChain:
len += 3;
break;
}
return len;
}
private static int DecorationExtraOps(int dec)
{
// RelaxedPrecision, Block..ColMajor
if (dec == 0 || (dec >= 2 && dec <= 5))
{
return 0;
}
// Stream..XfbStride
if (dec >= 29 && dec <= 37)
{
return 1;
}
// unknown, encode length
return -1;
}
private static int ZigDecode(uint u)
{
return (u & 1) != 0 ? unchecked((int)(~(u >> 1))) : unchecked((int)(u >> 1));
}
public const uint SpirVHeaderMagic = 0x07230203;
/// <summary>
/// 'SMOL' ascii
/// </summary>
public const uint SmolHeaderMagic = 0x534D4F4C;
private const int HeaderSize = 6 * sizeof(uint);
}
}
+369
View File
@@ -0,0 +1,369 @@
namespace Smolv
{
public enum SpvOp
{
Nop = 0,
Undef = 1,
SourceContinued = 2,
Source = 3,
SourceExtension = 4,
Name = 5,
MemberName = 6,
String = 7,
Line = 8,
Extension = 10,
ExtInstImport = 11,
ExtInst = 12,
/// <summary>
/// Not in SPIR-V, added for SMOL-V!
/// </summary>
VectorShuffleCompact = 13,
MemoryModel = 14,
EntryPoint = 15,
ExecutionMode = 16,
Capability = 17,
TypeVoid = 19,
TypeBool = 20,
TypeInt = 21,
TypeFloat = 22,
TypeVector = 23,
TypeMatrix = 24,
TypeImage = 25,
TypeSampler = 26,
TypeSampledImage = 27,
TypeArray = 28,
TypeRuntimeArray = 29,
TypeStruct = 30,
TypeOpaque = 31,
TypePointer = 32,
TypeFunction = 33,
TypeEvent = 34,
TypeDeviceEvent = 35,
TypeReserveId = 36,
TypeQueue = 37,
TypePipe = 38,
TypeForwardPointer = 39,
ConstantTrue = 41,
ConstantFalse = 42,
Constant = 43,
ConstantComposite = 44,
ConstantSampler = 45,
ConstantNull = 46,
SpecConstantTrue = 48,
SpecConstantFalse = 49,
SpecConstant = 50,
SpecConstantComposite = 51,
SpecConstantOp = 52,
Function = 54,
FunctionParameter = 55,
FunctionEnd = 56,
FunctionCall = 57,
Variable = 59,
ImageTexelPointer = 60,
Load = 61,
Store = 62,
CopyMemory = 63,
CopyMemorySized = 64,
AccessChain = 65,
InBoundsAccessChain = 66,
PtrAccessChain = 67,
ArrayLength = 68,
GenericPtrMemSemantics = 69,
InBoundsPtrAccessChain = 70,
Decorate = 71,
MemberDecorate = 72,
DecorationGroup = 73,
GroupDecorate = 74,
GroupMemberDecorate = 75,
VectorExtractDynamic = 77,
VectorInsertDynamic = 78,
VectorShuffle = 79,
CompositeConstruct = 80,
CompositeExtract = 81,
CompositeInsert = 82,
CopyObject = 83,
Transpose = 84,
SampledImage = 86,
ImageSampleImplicitLod = 87,
ImageSampleExplicitLod = 88,
ImageSampleDrefImplicitLod = 89,
ImageSampleDrefExplicitLod = 90,
ImageSampleProjImplicitLod = 91,
ImageSampleProjExplicitLod = 92,
ImageSampleProjDrefImplicitLod = 93,
ImageSampleProjDrefExplicitLod = 94,
ImageFetch = 95,
ImageGather = 96,
ImageDrefGather = 97,
ImageRead = 98,
ImageWrite = 99,
Image = 100,
ImageQueryFormat = 101,
ImageQueryOrder = 102,
ImageQuerySizeLod = 103,
ImageQuerySize = 104,
ImageQueryLod = 105,
ImageQueryLevels = 106,
ImageQuerySamples = 107,
ConvertFToU = 109,
ConvertFToS = 110,
ConvertSToF = 111,
ConvertUToF = 112,
UConvert = 113,
SConvert = 114,
FConvert = 115,
QuantizeToF16 = 116,
ConvertPtrToU = 117,
SatConvertSToU = 118,
SatConvertUToS = 119,
ConvertUToPtr = 120,
PtrCastToGeneric = 121,
GenericCastToPtr = 122,
GenericCastToPtrExplicit = 123,
Bitcast = 124,
SNegate = 126,
FNegate = 127,
IAdd = 128,
FAdd = 129,
ISub = 130,
FSub = 131,
IMul = 132,
FMul = 133,
UDiv = 134,
SDiv = 135,
FDiv = 136,
UMod = 137,
SRem = 138,
SMod = 139,
FRem = 140,
FMod = 141,
VectorTimesScalar = 142,
MatrixTimesScalar = 143,
VectorTimesMatrix = 144,
MatrixTimesVector = 145,
MatrixTimesMatrix = 146,
OuterProduct = 147,
Dot = 148,
IAddCarry = 149,
ISubBorrow = 150,
UMulExtended = 151,
SMulExtended = 152,
Any = 154,
All = 155,
IsNan = 156,
IsInf = 157,
IsFinite = 158,
IsNormal = 159,
SignBitSet = 160,
LessOrGreater = 161,
Ordered = 162,
Unordered = 163,
LogicalEqual = 164,
LogicalNotEqual = 165,
LogicalOr = 166,
LogicalAnd = 167,
LogicalNot = 168,
Select = 169,
IEqual = 170,
INotEqual = 171,
UGreaterThan = 172,
SGreaterThan = 173,
UGreaterThanEqual = 174,
SGreaterThanEqual = 175,
ULessThan = 176,
SLessThan = 177,
ULessThanEqual = 178,
SLessThanEqual = 179,
FOrdEqual = 180,
FUnordEqual = 181,
FOrdNotEqual = 182,
FUnordNotEqual = 183,
FOrdLessThan = 184,
FUnordLessThan = 185,
FOrdGreaterThan = 186,
FUnordGreaterThan = 187,
FOrdLessThanEqual = 188,
FUnordLessThanEqual = 189,
FOrdGreaterThanEqual = 190,
FUnordGreaterThanEqual = 191,
ShiftRightLogical = 194,
ShiftRightArithmetic = 195,
ShiftLeftLogical = 196,
BitwiseOr = 197,
BitwiseXor = 198,
BitwiseAnd = 199,
Not = 200,
BitFieldInsert = 201,
BitFieldSExtract = 202,
BitFieldUExtract = 203,
BitReverse = 204,
BitCount = 205,
DPdx = 207,
DPdy = 208,
Fwidth = 209,
DPdxFine = 210,
DPdyFine = 211,
FwidthFine = 212,
DPdxCoarse = 213,
DPdyCoarse = 214,
FwidthCoarse = 215,
EmitVertex = 218,
EndPrimitive = 219,
EmitStreamVertex = 220,
EndStreamPrimitive = 221,
ControlBarrier = 224,
MemoryBarrier = 225,
AtomicLoad = 227,
AtomicStore = 228,
AtomicExchange = 229,
AtomicCompareExchange = 230,
AtomicCompareExchangeWeak = 231,
AtomicIIncrement = 232,
AtomicIDecrement = 233,
AtomicIAdd = 234,
AtomicISub = 235,
AtomicSMin = 236,
AtomicUMin = 237,
AtomicSMax = 238,
AtomicUMax = 239,
AtomicAnd = 240,
AtomicOr = 241,
AtomicXor = 242,
Phi = 245,
LoopMerge = 246,
SelectionMerge = 247,
Label = 248,
Branch = 249,
BranchConditional = 250,
Switch = 251,
Kill = 252,
Return = 253,
ReturnValue = 254,
Unreachable = 255,
LifetimeStart = 256,
LifetimeStop = 257,
GroupAsyncCopy = 259,
GroupWaitEvents = 260,
GroupAll = 261,
GroupAny = 262,
GroupBroadcast = 263,
GroupIAdd = 264,
GroupFAdd = 265,
GroupFMin = 266,
GroupUMin = 267,
GroupSMin = 268,
GroupFMax = 269,
GroupUMax = 270,
GroupSMax = 271,
ReadPipe = 274,
WritePipe = 275,
ReservedReadPipe = 276,
ReservedWritePipe = 277,
ReserveReadPipePackets = 278,
ReserveWritePipePackets = 279,
CommitReadPipe = 280,
CommitWritePipe = 281,
IsValidReserveId = 282,
GetNumPipePackets = 283,
GetMaxPipePackets = 284,
GroupReserveReadPipePackets = 285,
GroupReserveWritePipePackets = 286,
GroupCommitReadPipe = 287,
GroupCommitWritePipe = 288,
EnqueueMarker = 291,
EnqueueKernel = 292,
GetKernelNDrangeSubGroupCount = 293,
GetKernelNDrangeMaxSubGroupSize = 294,
GetKernelWorkGroupSize = 295,
GetKernelPreferredWorkGroupSizeMultiple = 296,
RetainEvent = 297,
ReleaseEvent = 298,
CreateUserEvent = 299,
IsValidEvent = 300,
SetUserEventStatus = 301,
CaptureEventProfilingInfo = 302,
GetDefaultQueue = 303,
BuildNDRange = 304,
ImageSparseSampleImplicitLod = 305,
ImageSparseSampleExplicitLod = 306,
ImageSparseSampleDrefImplicitLod = 307,
ImageSparseSampleDrefExplicitLod = 308,
ImageSparseSampleProjImplicitLod = 309,
ImageSparseSampleProjExplicitLod = 310,
ImageSparseSampleProjDrefImplicitLod = 311,
ImageSparseSampleProjDrefExplicitLod = 312,
ImageSparseFetch = 313,
ImageSparseGather = 314,
ImageSparseDrefGather = 315,
ImageSparseTexelsResident = 316,
NoLine = 317,
AtomicFlagTestAndSet = 318,
AtomicFlagClear = 319,
ImageSparseRead = 320,
SizeOf = 321,
TypePipeStorage = 322,
ConstantPipeStorage = 323,
CreatePipeFromPipeStorage = 324,
GetKernelLocalSizeForSubgroupCount = 325,
GetKernelMaxNumSubgroups = 326,
TypeNamedBarrier = 327,
NamedBarrierInitialize = 328,
MemoryNamedBarrier = 329,
ModuleProcessed = 330,
KnownOpsCount,
}
public static class SpvOpExtensions
{
public static bool OpHasResult(this SpvOp _this)
{
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
{
return false;
}
return OpData.SpirvOpData[(int)_this].hasResult != 0;
}
public static bool OpHasType(this SpvOp _this)
{
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
{
return false;
}
return OpData.SpirvOpData[(int)_this].hasType != 0;
}
public static int OpDeltaFromResult(this SpvOp _this)
{
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
{
return 0;
}
return OpData.SpirvOpData[(int)_this].deltaFromResult;
}
public static bool OpVarRest(this SpvOp _this)
{
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
{
return false;
}
return OpData.SpirvOpData[(int)_this].varrest != 0;
}
public static bool OpDebugInfo(this SpvOp _this)
{
return
_this == SpvOp.SourceContinued ||
_this == SpvOp.Source ||
_this == SpvOp.SourceExtension ||
_this == SpvOp.Name ||
_this == SpvOp.MemberName ||
_this == SpvOp.String ||
_this == SpvOp.Line ||
_this == SpvOp.NoLine ||
_this == SpvOp.ModuleProcessed;
}
}
}
@@ -0,0 +1,74 @@
using Smolv;
using SpirV;
using System;
using System.IO;
using System.Text;
namespace AssetStudio
{
public static class SpirVShaderConverter
{
public static string Convert(byte[] m_ProgramCode)
{
var sb = new StringBuilder();
using (var ms = new MemoryStream(m_ProgramCode))
{
using (var reader = new BinaryReader(ms))
{
int requirements = reader.ReadInt32();
int minOffset = m_ProgramCode.Length;
int snippetCount = 5;
/*if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
{
snippetCount = 6;
}*/
for (int i = 0; i < snippetCount; i++)
{
if (reader.BaseStream.Position >= minOffset)
{
break;
}
int offset = reader.ReadInt32();
int size = reader.ReadInt32();
if (size > 0)
{
if (offset < minOffset)
{
minOffset = offset;
}
var pos = ms.Position;
sb.Append(ExportSnippet(ms, offset, size));
ms.Position = pos;
}
}
}
}
return sb.ToString();
}
private static string ExportSnippet(Stream stream, int offset, int size)
{
stream.Position = offset;
int decodedSize = SmolvDecoder.GetDecodedBufferSize(stream);
if (decodedSize == 0)
{
throw new Exception("Invalid SMOL-V shader header");
}
using (var decodedStream = new MemoryStream(new byte[decodedSize]))
{
if (SmolvDecoder.Decode(stream, size, decodedStream))
{
decodedStream.Position = 0;
var module = Module.ReadFrom(decodedStream);
var disassembler = new Disassembler();
return disassembler.Disassemble(module, DisassemblyOptions.Default).Replace("\r\n", "\n");
}
else
{
throw new Exception("Unable to decode SMOL-V shader");
}
}
}
}
}
+47 -37
View File
@@ -28,7 +28,7 @@ namespace AssetStudio
return null;
}
private static Bitmap CutImage(Texture2D m_Texture2D, Sprite m_Sprite, RectangleF textureRect, Vector2 textureRectOffset, SpriteSettings settingsRaw)
private static Bitmap CutImage(Texture2D m_Texture2D, Sprite m_Sprite, Rectf textureRect, Vector2 textureRectOffset, SpriteSettings settingsRaw)
{
var originalImage = m_Texture2D.ConvertToBitmap(false);
if (originalImage != null)
@@ -36,12 +36,21 @@ namespace AssetStudio
using (originalImage)
{
//var spriteImage = originalImage.Clone(textureRect, PixelFormat.Format32bppArgb);
var textureRectI = Rectangle.Round(textureRect);
var spriteImage = new Bitmap(textureRectI.Width, textureRectI.Height, PixelFormat.Format32bppArgb);
var destRect = new Rectangle(0, 0, textureRectI.Width, textureRectI.Height);
var rectf = new RectangleF(textureRect.x, textureRect.y, textureRect.width, textureRect.height);
var rect = Rectangle.Round(rectf);
if (rect.Width == 0)
{
rect.Width = 1;
}
if (rect.Height == 0)
{
rect.Height = 1;
}
var spriteImage = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
var destRect = new Rectangle(0, 0, rect.Width, rect.Height);
using (var graphic = Graphics.FromImage(spriteImage))
{
graphic.DrawImage(originalImage, destRect, textureRectI, GraphicsUnit.Pixel);
graphic.DrawImage(originalImage, destRect, rect, GraphicsUnit.Pixel);
}
if (settingsRaw.packed == 1)
{
@@ -83,21 +92,22 @@ namespace AssetStudio
|| (version[0] == 5 && version[1] < 4)
|| (version[0] == 5 && version[1] == 4 && version[2] <= 1)) //5.4.1p3 down
{
matr.Translate(m_Sprite.m_Rect.Width * 0.5f - textureRectOffset.X, m_Sprite.m_Rect.Height * 0.5f - textureRectOffset.Y);
matr.Translate(m_Sprite.m_Rect.width * 0.5f - textureRectOffset.X, m_Sprite.m_Rect.height * 0.5f - textureRectOffset.Y);
}
else
{
matr.Translate(m_Sprite.m_Rect.Width * m_Sprite.m_Pivot.X - textureRectOffset.X, m_Sprite.m_Rect.Height * m_Sprite.m_Pivot.Y - textureRectOffset.Y);
matr.Translate(m_Sprite.m_Rect.width * m_Sprite.m_Pivot.X - textureRectOffset.X, m_Sprite.m_Rect.height * m_Sprite.m_Pivot.Y - textureRectOffset.Y);
}
matr.Scale(m_Sprite.m_PixelsToUnits, m_Sprite.m_PixelsToUnits);
path.Transform(matr);
var bitmap = new Bitmap(textureRectI.Width, textureRectI.Height);
var bitmap = new Bitmap(rect.Width, rect.Height);
using (var graphic = Graphics.FromImage(bitmap))
{
using (var brush = new TextureBrush(spriteImage))
{
graphic.FillPath(brush, path);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
spriteImage.Dispose();
return bitmap;
}
}
@@ -136,43 +146,43 @@ namespace AssetStudio
}
return triangles;
}
return GetTriangles(m_RD.m_VertexData, m_RD.m_SubMeshes, m_RD.m_IndexBuffer); //5.6 and up
}
private static Vector2[][] GetTriangles(VertexData m_VertexData, SubMesh[] m_SubMeshes, byte[] m_IndexBuffer)
{
var triangles = new List<Vector2[]>();
var m_Channel = m_VertexData.m_Channels[0]; //kShaderChannelVertex
var m_Stream = m_VertexData.m_Streams[m_Channel.stream];
using (BinaryReader vertexReader = new BinaryReader(new MemoryStream(m_VertexData.m_DataSize)),
indexReader = new BinaryReader(new MemoryStream(m_IndexBuffer)))
else //5.6 and up
{
foreach (var subMesh in m_SubMeshes)
var triangles = new List<Vector2[]>();
var m_VertexData = m_RD.m_VertexData;
var m_Channel = m_VertexData.m_Channels[0]; //kShaderChannelVertex
var m_Stream = m_VertexData.m_Streams[m_Channel.stream];
using (var vertexReader = new BinaryReader(new MemoryStream(m_VertexData.m_DataSize)))
{
vertexReader.BaseStream.Position = m_Stream.offset + subMesh.firstVertex * m_Stream.stride + m_Channel.offset;
var vertices = new Vector2[subMesh.vertexCount];
for (int v = 0; v < subMesh.vertexCount; v++)
using (var indexReader = new BinaryReader(new MemoryStream(m_RD.m_IndexBuffer)))
{
vertices[v] = vertexReader.ReadVector3();
vertexReader.BaseStream.Position += m_Stream.stride - 12;
}
foreach (var subMesh in m_RD.m_SubMeshes)
{
vertexReader.BaseStream.Position = m_Stream.offset + subMesh.firstVertex * m_Stream.stride + m_Channel.offset;
indexReader.BaseStream.Position = subMesh.firstByte;
var vertices = new Vector2[subMesh.vertexCount];
for (int v = 0; v < subMesh.vertexCount; v++)
{
vertices[v] = vertexReader.ReadVector3();
vertexReader.BaseStream.Position += m_Stream.stride - 12;
}
var triangleCount = subMesh.indexCount / 3u;
for (int i = 0; i < triangleCount; i++)
{
var first = indexReader.ReadUInt16() - subMesh.firstVertex;
var second = indexReader.ReadUInt16() - subMesh.firstVertex;
var third = indexReader.ReadUInt16() - subMesh.firstVertex;
var triangle = new[] { vertices[first], vertices[second], vertices[third] };
triangles.Add(triangle);
indexReader.BaseStream.Position = subMesh.firstByte;
var triangleCount = subMesh.indexCount / 3u;
for (int i = 0; i < triangleCount; i++)
{
var first = indexReader.ReadUInt16() - subMesh.firstVertex;
var second = indexReader.ReadUInt16() - subMesh.firstVertex;
var third = indexReader.ReadUInt16() - subMesh.firstVertex;
var triangle = new[] { vertices[first], vertices[second], vertices[third] };
triangles.Add(triangle);
}
}
}
}
return triangles.ToArray();
}
return triangles.ToArray();
}
}
}
@@ -0,0 +1,311 @@
using Mono.Cecil;
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.CecilTools;
using Unity.SerializationLogic;
namespace AssetStudio
{
public class TypeDefinitionConverter
{
private readonly TypeDefinition TypeDef;
private readonly TypeResolver TypeResolver;
private readonly SerializedTypeHelper Helper;
private readonly int Indent;
public TypeDefinitionConverter(TypeDefinition typeDef, SerializedTypeHelper helper, int indent)
{
TypeDef = typeDef;
TypeResolver = new TypeResolver(null);
Helper = helper;
Indent = indent;
}
public List<TypeTreeNode> ConvertToTypeTreeNodes()
{
var nodes = new List<TypeTreeNode>();
Stack<TypeReference> baseTypes = new Stack<TypeReference>();
TypeReference baseType = TypeDef.BaseType;
while (!UnitySerializationLogic.IsNonSerialized(baseType))
{
GenericInstanceType genericInstanceType = baseType as GenericInstanceType;
if (genericInstanceType != null)
{
TypeResolver.Add(genericInstanceType);
}
baseTypes.Push(baseType);
baseType = baseType.Resolve().BaseType;
}
while (baseTypes.Count > 0)
{
TypeReference typeReference = baseTypes.Pop();
TypeDefinition typeDefinition = typeReference.Resolve();
foreach (var fieldDefinition in typeDefinition.Fields.Where(WillUnitySerialize))
{
if (!IsHiddenByParentClass(baseTypes, fieldDefinition, TypeDef))
{
nodes.AddRange(ProcessingFieldRef(ResolveGenericFieldReference(fieldDefinition)));
}
}
var genericInstanceType2 = typeReference as GenericInstanceType;
if (genericInstanceType2 != null)
{
TypeResolver.Remove(genericInstanceType2);
}
}
foreach (FieldDefinition fieldDefinition2 in FilteredFields())
{
nodes.AddRange(ProcessingFieldRef(fieldDefinition2));
}
return nodes;
}
private bool WillUnitySerialize(FieldDefinition fieldDefinition)
{
bool result;
try
{
TypeReference typeReference = TypeResolver.Resolve(fieldDefinition.FieldType);
if (UnitySerializationLogic.ShouldNotTryToResolve(typeReference))
{
result = false;
}
else
{
if (!UnityEngineTypePredicates.IsUnityEngineObject(typeReference))
{
if (typeReference.FullName == fieldDefinition.DeclaringType.FullName)
{
return false;
}
}
result = UnitySerializationLogic.WillUnitySerialize(fieldDefinition, TypeResolver);
}
}
catch (Exception ex)
{
throw new Exception(string.Format("Exception while processing {0} {1}, error {2}", fieldDefinition.FieldType.FullName, fieldDefinition.FullName, ex.Message));
}
return result;
}
private static bool IsHiddenByParentClass(IEnumerable<TypeReference> parentTypes, FieldDefinition fieldDefinition, TypeDefinition processingType)
{
return processingType.Fields.Any((FieldDefinition f) => f.Name == fieldDefinition.Name) || parentTypes.Any((TypeReference t) => t.Resolve().Fields.Any((FieldDefinition f) => f.Name == fieldDefinition.Name));
}
private IEnumerable<FieldDefinition> FilteredFields()
{
foreach (var f in TypeDef.Fields.Where(WillUnitySerialize))
{
if (UnitySerializationLogic.IsSupportedCollection(f.FieldType) || !f.FieldType.IsGenericInstance || UnitySerializationLogic.ShouldImplementIDeserializable(f.FieldType.Resolve()))
{
yield return f;
}
}
yield break;
}
private FieldReference ResolveGenericFieldReference(FieldReference fieldRef)
{
FieldReference field = new FieldReference(fieldRef.Name, fieldRef.FieldType, ResolveDeclaringType(fieldRef.DeclaringType));
return TypeDef.Module.ImportReference(field);
}
private TypeReference ResolveDeclaringType(TypeReference declaringType)
{
TypeDefinition typeDefinition = declaringType.Resolve();
TypeReference result;
if (typeDefinition == null || !typeDefinition.HasGenericParameters)
{
result = typeDefinition;
}
else
{
GenericInstanceType genericInstanceType = new GenericInstanceType(typeDefinition);
foreach (GenericParameter item in typeDefinition.GenericParameters)
{
genericInstanceType.GenericArguments.Add(item);
}
result = TypeResolver.Resolve(genericInstanceType);
}
return result;
}
private List<TypeTreeNode> ProcessingFieldRef(FieldReference fieldDef)
{
var typeRef = TypeResolver.Resolve(fieldDef.FieldType);
return TypeRefToTypeTreeNodes(typeRef, fieldDef.Name, Indent, false);
}
private static bool IsStruct(TypeReference typeRef)
{
return typeRef.IsValueType && !IsEnum(typeRef) && !typeRef.IsPrimitive;
}
private static bool IsEnum(TypeReference typeRef)
{
return !typeRef.IsArray && typeRef.Resolve().IsEnum;
}
private static bool RequiresAlignment(TypeReference typeRef)
{
bool result;
switch (typeRef.MetadataType)
{
case MetadataType.Boolean:
case MetadataType.Char:
case MetadataType.SByte:
case MetadataType.Byte:
case MetadataType.Int16:
case MetadataType.UInt16:
result = true;
break;
default:
result = (UnitySerializationLogic.IsSupportedCollection(typeRef) && RequiresAlignment(CecilUtils.ElementTypeOfCollection(typeRef)));
break;
}
return result;
}
private static bool IsSystemString(TypeReference typeRef)
{
return typeRef.FullName == "System.String";
}
private List<TypeTreeNode> TypeRefToTypeTreeNodes(TypeReference typeRef, string name, int indent, bool isElement)
{
var align = false;
if (!IsStruct(TypeDef) || !UnityEngineTypePredicates.IsUnityEngineValueType(TypeDef))
{
if (IsStruct(typeRef) || RequiresAlignment(typeRef))
{
align = true;
}
}
var nodes = new List<TypeTreeNode>();
if (typeRef.IsPrimitive)
{
var primitiveName = typeRef.Name;
switch (primitiveName)
{
case "Boolean":
primitiveName = "bool";
break;
case "Byte":
primitiveName = "UInt8";
break;
case "SByte":
primitiveName = "SInt8";
break;
case "Int16":
primitiveName = "SInt16";
break;
case "UInt16":
primitiveName = "UInt16";
break;
case "Int32":
primitiveName = "SInt32";
break;
case "UInt32":
primitiveName = "UInt32";
break;
case "Int64":
primitiveName = "SInt64";
break;
case "UInt64":
primitiveName = "UInt64";
break;
case "Char":
primitiveName = "char";
break;
case "Double":
primitiveName = "double";
break;
case "Single":
primitiveName = "float";
break;
default:
throw new NotSupportedException();
}
if (isElement)
{
align = false;
}
nodes.Add(new TypeTreeNode(primitiveName, name, indent, align));
}
else if (IsSystemString(typeRef))
{
Helper.AddString(nodes, name, indent);
}
else if (IsEnum(typeRef))
{
nodes.Add(new TypeTreeNode("SInt32", name, indent, align));
}
else if (CecilUtils.IsGenericList(typeRef))
{
var elementRef = CecilUtils.ElementTypeOfCollection(typeRef);
nodes.Add(new TypeTreeNode(typeRef.Name, name, indent, align));
Helper.AddArray(nodes, indent + 1);
nodes.AddRange(TypeRefToTypeTreeNodes(elementRef, "data", indent + 2, true));
}
else if (typeRef.IsArray)
{
var elementRef = typeRef.GetElementType();
nodes.Add(new TypeTreeNode(typeRef.Name, name, indent, align));
Helper.AddArray(nodes, indent + 1);
nodes.AddRange(TypeRefToTypeTreeNodes(elementRef, "data", indent + 2, true));
}
else if (UnityEngineTypePredicates.IsUnityEngineObject(typeRef))
{
Helper.AddPPtr(nodes, typeRef.Name, name, indent);
}
else if (UnityEngineTypePredicates.IsSerializableUnityClass(typeRef) || UnityEngineTypePredicates.IsSerializableUnityStruct(typeRef))
{
switch (typeRef.FullName)
{
case "UnityEngine.AnimationCurve":
Helper.AddAnimationCurve(nodes, name, indent + 1);
break;
case "UnityEngine.Gradient":
Helper.AddGradient(nodes, name, indent + 1);
break;
case "UnityEngine.GUIStyle":
Helper.AddGUIStyle(nodes, name, indent + 1);
break;
case "UnityEngine.RectOffset":
Helper.AddRectOffset(nodes, name, indent + 1);
break;
case "UnityEngine.Color32":
Helper.AddColor32(nodes, name, indent + 1);
break;
case "UnityEngine.Matrix4x4":
Helper.AddMatrix4x4(nodes, name, indent + 1);
break;
case "UnityEngine.Rendering.SphericalHarmonicsL2":
Helper.AddSphericalHarmonicsL2(nodes, name, indent + 1);
break;
case "UnityEngine.PropertyName":
Helper.AddPropertyName(nodes, name, indent + 1);
break;
}
}
else
{
nodes.Add(new TypeTreeNode(typeRef.Name, name, indent, align));
var typeDef = typeRef.Resolve();
var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, Helper, indent + 1);
nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNodes());
}
return nodes;
}
}
}
+39 -18
View File
@@ -7,7 +7,7 @@ AssetStudio is a tool for exploring, extracting and exporting assets and assetbu
## Features
* Support version:
* 2.5 - 2019.3
* 2.5 - 2021.1
* Support asset types:
* **Texture2D** : convert to png, tga, jpeg, bmp
* **Sprite** : crop Texture2D to png, tga, jpeg, bmp
@@ -18,32 +18,53 @@ AssetStudio is a tool for exploring, extracting and exporting assets and assetbu
* **Shader**
* **MovieTexture**
* **VideoClip**
* **MonoBehaviour**
* **MonoBehaviour** : json
* **Animator** : export to FBX file with bound AnimationClip
## Usage
### Requirements
## Requirements
- [.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472)
- [Microsoft Visual C++ 2017 Redistributable](https://support.microsoft.com/help/2977003/the-latest-supported-visual-c-downloads)
### How to use
## Usage
### Load Assets/AssetBundles
Use **File-Load file** or **File-Load folder**.
When AssetStudio loads AssetBundles, it decompresses and reads it directly in memory, which may cause a large amount of memory to be used. You can use **File-Extract file** or **File-Extract folder** to extract AssetBundles to another folder, and then read.
### Extract/Decompress AssetBundles
Use **File-Extract file** or **File-Extract folder**.
### Export Assets
use **Export** menu.
### Export Model
Export model from "Scene Hierarchy" using the **Model** menu.
Export Animator from "Asset List" using the **Export** menu.
#### With AnimationClip
Select model from "Scene Hierarchy" then select the AnimationClip from "Asset List", using **Model-Export selected objects with AnimationClip** to export.
Export Animator will export bound AnimationClip or use **Ctrl** to select Animator and AnimationClip from "Asset List", using **Export-Export Animator with selected AnimationClip** to export.
### Export MonoBehaviour
When you select an asset of the MonoBehaviour type for the first time, AssetStudio will ask you the directory where the assembly is located, please select the directory where the assembly is located, such as the `Managed` folder.
#### For Il2Cpp
First, use my another program [Il2CppDumper](https://github.com/Perfare/Il2CppDumper) to generate dummy dll, then when using AssetStudio to select the assembly directory, select the dummy dll folder.
* Use **File-Load file**, **File-Load folder** to load assets or assetbundles from multiple files or folder
* Use **File-Extract file**, **File-Extract folder** to export assetbundles to assets from multiple files or folder
* Export assets: use **Export** menu
* Export model:
* Export model from "Scene Hierarchy" using the **Model** menu
* Export Animator from "Asset List" using the **Export** menu
* With AnimationClip:
* Select model from "Scene Hierarchy" then select the AnimationClip from "Asset List", using **Model-Export selected objects with AnimationClip** to export
* Export Animator will export bound AnimationClip or use **Ctrl** to select Animator and AnimationClip from "Asset List", using **Export-Export Animator with selected AnimationClip** to export
## Build
* Visual Studio 2019 or newer
* **AssetStudioFBX** uses FBX SDK 2020.0.1 VS2017, before building, you need to install the FBX SDK and modify the project file, change include directory and library directory to point to the FBX SDK directory
* If you want to change the FBX SDK version, you need to replace `libfbxsdk.dll` which in `AssetStudioGUI/Libraries/x86/` and `AssetStudioGUI/Libraries/x64/` directory to the new version
* **AssetStudioFBXNative** uses FBX SDK 2020.0.1 VS2017, before building, you need to install the FBX SDK and modify the project file, change include directory and library directory to point to the FBX SDK directory
## Open source libraries used
@@ -153,6 +153,7 @@
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -187,6 +188,7 @@
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>