mirror of
https://github.com/AssetRipper/AssetRipper.git
synced 2025-12-11 20:15:29 +01:00
193 lines
5.8 KiB
C#
193 lines
5.8 KiB
C#
using AssetRipper.Core.Classes.Meta;
|
|
using AssetRipper.Core.Classes.Misc;
|
|
using AssetRipper.Core.Interfaces;
|
|
using AssetRipper.Core.Parser.Files.SerializedFiles;
|
|
using AssetRipper.Core.Project;
|
|
using AssetRipper.Core.Project.Collections;
|
|
using AssetRipper.Core.Project.Exporters;
|
|
using AssetRipper.Core.SourceGenExtensions;
|
|
using AssetRipper.Core.Structure.Assembly;
|
|
using AssetRipper.Core.Utils;
|
|
using AssetRipper.SourceGenerated.Classes.ClassID_1035;
|
|
using AssetRipper.SourceGenerated.Classes.ClassID_115;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace AssetRipper.Library.Exporters.Scripts
|
|
{
|
|
public class ScriptExportCollection : ExportCollection
|
|
{
|
|
public ScriptExportCollection(IAssetExporter assetExporter, IMonoScript script)
|
|
{
|
|
AssetExporter = assetExporter ?? throw new ArgumentNullException(nameof(assetExporter));
|
|
File = script.SerializedFile;
|
|
|
|
// find copies in whole project and skip them
|
|
Dictionary<MonoScriptInfo, IMonoScript> uniqueDictionary = new();
|
|
foreach (IUnityObjectBase asset in script.SerializedFile.Collection.FetchAssets())
|
|
{
|
|
if (asset is not IMonoScript assetScript)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
MonoScriptInfo info = MonoScriptInfo.From(assetScript);
|
|
if(uniqueDictionary.TryGetValue(info, out IMonoScript? uniqueScript))
|
|
{
|
|
m_scripts.Add(assetScript, uniqueScript);
|
|
}
|
|
else
|
|
{
|
|
m_scripts.Add(assetScript, assetScript);
|
|
uniqueDictionary.Add(info, assetScript);
|
|
if (assetScript.IsScriptPresents())
|
|
{
|
|
m_export.Add(assetScript);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override bool Export(IProjectAssetContainer container, string dirPath)
|
|
{
|
|
if (m_export.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
string scriptFolder = m_export[0].ExportPath;
|
|
string scriptPath = Path.Combine(dirPath, scriptFolder);
|
|
|
|
AssetExporter.Export(container, m_export, scriptPath, OnScriptExported);
|
|
return true;
|
|
}
|
|
|
|
public override bool IsContains(IUnityObjectBase asset)
|
|
{
|
|
return m_scripts.ContainsKey(asset);
|
|
}
|
|
|
|
public override long GetExportID(IUnityObjectBase asset)
|
|
{
|
|
return ExportIdHandler.GetMainExportID(asset);
|
|
}
|
|
|
|
public override MetaPtr CreateExportPointer(IUnityObjectBase asset, bool isLocal)
|
|
{
|
|
if (isLocal)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
IMonoScript script = m_scripts[asset];
|
|
if (!MonoScriptExtensions.HasAssemblyName(script.SerializedFile.Version, script.SerializedFile.Flags) || s_unityEngine.IsMatch(script.GetAssemblyNameFixed()))
|
|
{
|
|
if (MonoScriptExtensions.HasNamespace(script.SerializedFile.Version))
|
|
{
|
|
int fileID = Compute(script.Namespace_C115.String, script.ClassName_C115.String);
|
|
return new MetaPtr(fileID, UnityEngineGUID, AssetExporter.ToExportType(asset));
|
|
}
|
|
else
|
|
{
|
|
ScriptIdentifier scriptInfo = script.GetScriptID();
|
|
if (!scriptInfo.IsDefault)
|
|
{
|
|
int fileID = Compute(scriptInfo.Namespace, scriptInfo.Name);
|
|
return new MetaPtr(fileID, UnityEngineGUID, AssetExporter.ToExportType(asset));
|
|
}
|
|
}
|
|
}
|
|
|
|
long exportID = GetExportID(asset);
|
|
UnityGUID uniqueGUID = script.GUID;
|
|
return new MetaPtr(exportID, uniqueGUID, AssetExporter.ToExportType(asset));
|
|
}
|
|
|
|
private static int Compute(string @namespace, string name)
|
|
{
|
|
string toBeHashed = $"s\0\0\0{@namespace}{name}";
|
|
using HashAlgorithm hash = new MD4();
|
|
byte[] hashed = hash.ComputeHash(Encoding.UTF8.GetBytes(toBeHashed));
|
|
|
|
int result = 0;
|
|
for (int i = 3; i >= 0; --i)
|
|
{
|
|
result <<= 8;
|
|
result |= hashed[i];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private void OnScriptExported(IExportContainer container, IUnityObjectBase asset, string path)
|
|
{
|
|
IMonoScript script = (IMonoScript)asset;
|
|
IMonoImporter importer = MonoImporterFactory.CreateAsset(container.ExportVersion);
|
|
importer.ExecutionOrder_C1035 = (short)script.ExecutionOrder_C115;
|
|
Meta meta = new Meta(script.GUID, importer);
|
|
ExportMeta(container, meta, path);
|
|
}
|
|
|
|
public override IAssetExporter AssetExporter { get; }
|
|
public override ISerializedFile File { get; }
|
|
public override IEnumerable<IUnityObjectBase> Assets => m_scripts.Keys;
|
|
public override string Name => nameof(ScriptExportCollection);
|
|
|
|
private static readonly UnityGUID UnityEngineGUID = new UnityGUID(0x1F55507F, 0xA1948D44, 0x4080F528, 0xC176C90E);
|
|
private static readonly Regex s_unityEngine = new Regex(@"^UnityEngine(\.[0-9a-zA-Z]+)*(\.dll)?$", RegexOptions.Compiled);
|
|
|
|
private readonly List<IMonoScript> m_export = new List<IMonoScript>();
|
|
private readonly Dictionary<IUnityObjectBase, IMonoScript> m_scripts = new Dictionary<IUnityObjectBase, IMonoScript>();
|
|
|
|
private struct MonoScriptInfo : IEquatable<MonoScriptInfo>
|
|
{
|
|
public readonly string @class;
|
|
public readonly string @namespace;
|
|
public readonly string assembly;
|
|
|
|
public MonoScriptInfo(string @class, string @namespace, string assembly)
|
|
{
|
|
this.@class = @class;
|
|
this.@namespace = @namespace;
|
|
this.assembly = assembly;
|
|
}
|
|
|
|
public static MonoScriptInfo From(IMonoScript monoScript)
|
|
{
|
|
return new MonoScriptInfo(monoScript.ClassName_C115.String, monoScript.Namespace_C115.String, monoScript.GetAssemblyNameFixed());
|
|
}
|
|
|
|
public override bool Equals(object? obj)
|
|
{
|
|
return obj is MonoScriptInfo info && Equals(info);
|
|
}
|
|
|
|
public bool Equals(MonoScriptInfo other)
|
|
{
|
|
return @class == other.@class &&
|
|
@namespace == other.@namespace &&
|
|
assembly == other.assembly;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(@class, @namespace, assembly);
|
|
}
|
|
|
|
public static bool operator ==(MonoScriptInfo left, MonoScriptInfo right)
|
|
{
|
|
return left.Equals(right);
|
|
}
|
|
|
|
public static bool operator !=(MonoScriptInfo left, MonoScriptInfo right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
}
|
|
}
|