129 lines
5.5 KiB
C#
129 lines
5.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using AssetStudio;
|
|
|
|
namespace PathIDExtractor
|
|
{
|
|
struct ParsedObject
|
|
{
|
|
public readonly long pathId;
|
|
public readonly string type;
|
|
public string name;
|
|
|
|
public ParsedObject(long pathId, string type)
|
|
{
|
|
this.pathId = pathId;
|
|
this.type = type;
|
|
name = null;
|
|
}
|
|
|
|
public override string ToString() => $"{pathId},{type},{(name is null ? "" : name)}";
|
|
}
|
|
|
|
class Program
|
|
{
|
|
private static string pathIdsFilePath;
|
|
private static string containersFilePath;
|
|
|
|
static void ParseObjects (List<AssetStudio.Object> objects)
|
|
{
|
|
/*
|
|
* As objects have no particular order and some objects hold other objects,
|
|
* and we want to keep a reference to each object's container,
|
|
* we will keep all the parsed objects and all the containers we find for those objects,
|
|
* then re-link them at the end.
|
|
*/
|
|
var parsedObjects = new Dictionary<AssetStudio.Object, ParsedObject>(objects.Count);
|
|
var containers = new List<(PPtr<AssetStudio.Object>, string)>();
|
|
|
|
foreach (var asset in objects)
|
|
{
|
|
var parsedObject = new ParsedObject(asset.m_PathID, asset.type.ToString());
|
|
// Find the name of an object depending on its type
|
|
switch (asset)
|
|
{
|
|
case Shader m_Shader:
|
|
parsedObject.name = m_Shader.m_ParsedForm?.m_Name ?? m_Shader.m_Name;
|
|
break;
|
|
case Animator m_Animator:
|
|
if (m_Animator.m_GameObject.TryGet(out var gameObject)) parsedObject.name = gameObject.m_Name;
|
|
break;
|
|
case MonoBehaviour m_MonoBehaviour:
|
|
if (m_MonoBehaviour.m_Name == "" && m_MonoBehaviour.m_Script.TryGet(out var m_Script)) parsedObject.name = m_Script.m_ClassName;
|
|
else parsedObject.name = m_MonoBehaviour.m_Name;
|
|
break;
|
|
case AssetBundle m_AssetBundle:
|
|
foreach (var m_Container in m_AssetBundle.m_Container)
|
|
{
|
|
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));
|
|
}
|
|
}
|
|
parsedObject.name = 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 namedObject:
|
|
parsedObject.name = namedObject.m_Name;
|
|
break;
|
|
}
|
|
parsedObjects.Add(asset, parsedObject);
|
|
}
|
|
File.AppendAllText(pathIdsFilePath, String.Join("\n", parsedObjects.Values.Select(obj => obj.ToString())) + "\n");
|
|
File.AppendAllText(containersFilePath, String.Join("\n", containers.Select(tuple => tuple.Item1.TryGet(out var obj) ? $"{obj.m_PathID},{tuple.Item2}" : null).Where(output => output != null)) + "\n");
|
|
Console.WriteLine($"Parsed {parsedObjects.Count} values");
|
|
}
|
|
|
|
static void Main(string[] args)
|
|
{
|
|
Console.Title = "Path ID Extractor";
|
|
Console.BackgroundColor = ConsoleColor.DarkRed;
|
|
Console.ForegroundColor = ConsoleColor.White;
|
|
Console.Clear();
|
|
Console.WriteLine("--- lucidiot's path ID extractor ---");
|
|
|
|
string basePath;
|
|
do
|
|
{
|
|
Console.WriteLine("Enter the base path of all Unity data files to analyze:");
|
|
basePath = Path.GetFullPath(Console.ReadLine());
|
|
} while (!Directory.Exists(basePath));
|
|
|
|
var files = Directory.GetFiles(basePath, "*.*", SearchOption.AllDirectories);
|
|
Console.WriteLine($"{files.Length} files to parse");
|
|
|
|
string baseOutputPath;
|
|
do
|
|
{
|
|
Console.WriteLine("Enter the base output path:");
|
|
baseOutputPath = Path.GetFullPath(Console.ReadLine());
|
|
} while (!Directory.Exists(baseOutputPath));
|
|
pathIdsFilePath = Path.Combine(baseOutputPath, "path_ids.csv");
|
|
containersFilePath = Path.Combine(baseOutputPath, "containers.csv");
|
|
|
|
Console.WriteLine($"Outputting to {pathIdsFilePath} and {containersFilePath}");
|
|
File.WriteAllText(pathIdsFilePath, "path_id,type,name\n");
|
|
File.WriteAllText(containersFilePath, "path_id,container\n");
|
|
|
|
var manager = new AssetsManager();
|
|
foreach (var filePath in files)
|
|
{
|
|
Console.WriteLine($"Loading {filePath.Substring(basePath.Length)}");
|
|
manager.LoadFiles(filePath);
|
|
manager.assetsFileList.ForEach(file => ParseObjects(file.Objects));
|
|
manager.Clear();
|
|
}
|
|
}
|
|
}
|
|
}
|