mirror of
https://github.com/AssetRipper/AssetRipper.git
synced 2025-12-11 20:15:29 +01:00
602 lines
18 KiB
C#
602 lines
18 KiB
C#
using AssetRipper.Assets;
|
|
using AssetRipper.Assets.Metadata;
|
|
using AssetRipper.Assets.Traversal;
|
|
using AssetRipper.SourceGenerated;
|
|
using AssetRipper.SourceGenerated.Classes.ClassID_114;
|
|
using AssetRipper.SourceGenerated.Extensions;
|
|
using AssetRipper.SourceGenerated.Subclasses.GUID;
|
|
using AssetRipper.SourceGenerated.Subclasses.Hash128;
|
|
using AssetRipper.SourceGenerated.Subclasses.PropertyName;
|
|
using AssetRipper.Yaml;
|
|
using AssetRipper.Yaml.Extensions;
|
|
using System.Diagnostics;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace AssetRipper.Export.UnityProjects;
|
|
|
|
public class YamlWalker : AssetWalker
|
|
{
|
|
private readonly record struct YamlContext(YamlMappingNode? MappingNode, YamlSequenceNode? SequenceNode, string? FieldName)
|
|
{
|
|
public YamlContext(YamlMappingNode mappingNode) : this(mappingNode, null, null)
|
|
{
|
|
}
|
|
|
|
public YamlContext(YamlMappingNode mappingNode, string fieldName) : this(mappingNode, null, fieldName)
|
|
{
|
|
}
|
|
|
|
public YamlContext(YamlSequenceNode sequenceNode) : this(null, sequenceNode, null)
|
|
{
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// These fields are excluded from meta files even though they might not have flags indicating that.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This set uses original names for robustness and clarity.
|
|
/// </remarks>
|
|
private static readonly HashSet<string> FieldsToSkipInImporters = new()
|
|
{
|
|
"m_ObjectHideFlags",
|
|
"m_ExtensionPtr",
|
|
"m_PrefabParentObject",
|
|
"m_CorrespondingSourceObject",
|
|
"m_PrefabInternal",
|
|
"m_PrefabAsset",
|
|
"m_PrefabInstance",
|
|
};
|
|
|
|
private const string Data = "data";
|
|
private const string First = "first";
|
|
private const string Second = "second";
|
|
private Stack<YamlContext> ContextStack { get; } = new();
|
|
public bool ExportingAssetImporter { private get; set; }
|
|
public bool UseHyphensInDictionaries { get; set; } = true;
|
|
private YamlMappingNode? CurrentMappingNode => ContextStack.Peek().MappingNode;
|
|
private YamlSequenceNode? CurrentSequenceNode => ContextStack.Peek().SequenceNode;
|
|
private string? CurrentFieldName => ContextStack.Peek().FieldName;
|
|
|
|
public YamlWalker WithUnityVersion(UnityVersion version)
|
|
{
|
|
UseHyphensInDictionaries = version.GreaterThanOrEquals(5, 4);
|
|
return this;
|
|
}
|
|
|
|
public YamlDocument ExportYamlDocument(IUnityObjectBase asset, long exportID)
|
|
{
|
|
ContextStack.Clear();
|
|
|
|
YamlDocument document = new();
|
|
|
|
YamlMappingNode root = document.CreateMappingRoot();
|
|
root.Tag = asset.ClassID.ToString();
|
|
root.Anchor = exportID.ToString();
|
|
|
|
ContextStack.Push(new(root, null, asset.ClassName));
|
|
asset.WalkEditor(this);
|
|
|
|
if (asset.IsStripped())
|
|
{
|
|
Debug.Assert(root.Children.Count == 1);
|
|
asset.RemoveStrippedFields((YamlMappingNode)root.Children[0].Value);
|
|
root.Stripped = true;
|
|
}
|
|
|
|
return document;
|
|
}
|
|
|
|
public YamlNode ExportYamlNode(IUnityAssetBase asset)
|
|
{
|
|
ContextStack.Clear();
|
|
YamlSequenceNode falseRoot = new();
|
|
ContextStack.Push(new(falseRoot));
|
|
asset.WalkEditor(this);
|
|
Debug.Assert(falseRoot.Children.Count == 1);
|
|
return falseRoot.Children[0];
|
|
}
|
|
|
|
public override bool EnterAsset(IUnityAssetBase asset)
|
|
{
|
|
if (asset is GUID guid)
|
|
{
|
|
VisitPrimitive(guid.ToString());
|
|
return false;
|
|
}
|
|
else if (asset is IHash128 hash)
|
|
{
|
|
AddNode(HashHelper.ExportYaml(hash));
|
|
return false;
|
|
}
|
|
else if (asset is IPropertyName propertyName)
|
|
{
|
|
VisitPrimitive(propertyName.GetIdString());
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
bool result = EnterMap(asset.FlowMappedInYaml);
|
|
Debug.Assert(result);
|
|
Debug.Assert(CurrentMappingNode is { Children.Count: 0 });
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
CurrentMappingNode.AddSerializedVersion(asset.SerializedVersion);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public sealed override void DivideAsset(IUnityAssetBase asset)
|
|
{
|
|
}
|
|
|
|
public override void ExitAsset(IUnityAssetBase asset)
|
|
{
|
|
ExitMap();
|
|
}
|
|
|
|
public override bool EnterField(IUnityAssetBase asset, string name)
|
|
{
|
|
Debug.Assert(CurrentMappingNode is not null);
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
if (ExportingAssetImporter && (FieldsToSkipInImporters.Contains(name) || asset.IgnoreFieldInMetaFiles(name)))
|
|
{
|
|
return false;
|
|
}
|
|
ContextStack.Push(new(CurrentMappingNode, name));
|
|
return true;
|
|
}
|
|
|
|
public override void ExitField(IUnityAssetBase asset, string name)
|
|
{
|
|
Debug.Assert(CurrentMappingNode is not null);
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
if (name is "m_Structure" && asset is IMonoBehaviour)
|
|
{
|
|
YamlMappingNode structureNode = PopStructureNode(CurrentMappingNode.Children);
|
|
CurrentMappingNode.Append(structureNode);
|
|
}
|
|
|
|
static YamlMappingNode PopStructureNode(List<KeyValuePair<YamlNode, YamlNode>> children)
|
|
{
|
|
KeyValuePair<YamlNode, YamlNode> pair = children[^1];
|
|
Debug.Assert(pair.Key.ToString() == "m_Structure");
|
|
children.RemoveAt(children.Count - 1);
|
|
return (YamlMappingNode)pair.Value;
|
|
}
|
|
}
|
|
|
|
public override bool EnterList<T>(IReadOnlyList<T> list)
|
|
{
|
|
// Integer arrays and lists are emitted as hex strings by Unity, both in custom MonoBehaviour fields and internal engine classes.
|
|
// In this particular case, integer means the traditional C# integer types, bool, and char.
|
|
// float and double are not emitted as hex strings. They are emitted as regular sequences.
|
|
if (typeof(T) == typeof(sbyte) ||
|
|
typeof(T) == typeof(byte) ||
|
|
typeof(T) == typeof(short) ||
|
|
typeof(T) == typeof(ushort) ||
|
|
typeof(T) == typeof(int) ||
|
|
typeof(T) == typeof(uint) ||
|
|
typeof(T) == typeof(long) ||
|
|
typeof(T) == typeof(ulong) ||
|
|
typeof(T) == typeof(bool) ||
|
|
typeof(T) == typeof(char))
|
|
{
|
|
VisitPrimitive(list);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return EnterSequence(SequenceStyle.Block);
|
|
}
|
|
}
|
|
|
|
public override void ExitList<T>(IReadOnlyList<T> list)
|
|
{
|
|
ExitSequence();
|
|
}
|
|
|
|
public override bool EnterPair<TKey, TValue>(KeyValuePair<TKey, TValue> pair)
|
|
{
|
|
YamlMappingNode node = new YamlMappingNode();
|
|
ContextStack.Push(new(node));
|
|
if (!IsValidDictionaryKey<TKey>())
|
|
{
|
|
ContextStack.Push(new(node, First));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override void DividePair<TKey, TValue>(KeyValuePair<TKey, TValue> pair)
|
|
{
|
|
Debug.Assert(CurrentMappingNode is not null);
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
if (IsValidDictionaryKey<TKey>())
|
|
{
|
|
Debug.Assert(CurrentFieldName is not null);
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(CurrentFieldName is null);
|
|
ContextStack.Push(new(CurrentMappingNode, Second));
|
|
}
|
|
}
|
|
|
|
public override void ExitPair<TKey, TValue>(KeyValuePair<TKey, TValue> pair)
|
|
{
|
|
ExitMap();
|
|
}
|
|
|
|
public override bool EnterDictionary<TKey, TValue>(IReadOnlyCollection<KeyValuePair<TKey, TValue>> dictionary)
|
|
{
|
|
if (IsValidDictionaryKey<TKey>() || !UseHyphensInDictionaries)
|
|
{
|
|
return EnterMap();
|
|
}
|
|
else
|
|
{
|
|
return EnterSequence(SequenceStyle.BlockCurve);
|
|
}
|
|
}
|
|
|
|
public override void ExitDictionary<TKey, TValue>(IReadOnlyCollection<KeyValuePair<TKey, TValue>> dictionary)
|
|
{
|
|
if (IsValidDictionaryKey<TKey>() || !UseHyphensInDictionaries)
|
|
{
|
|
ExitMap();
|
|
}
|
|
else
|
|
{
|
|
ExitSequence();
|
|
}
|
|
}
|
|
|
|
public override bool EnterDictionaryPair<TKey, TValue>(KeyValuePair<TKey, TValue> pair)
|
|
{
|
|
if (IsValidDictionaryKey<TKey>())
|
|
{
|
|
Debug.Assert(CurrentMappingNode is not null);
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
}
|
|
else if (!UseHyphensInDictionaries)
|
|
{
|
|
Debug.Assert(CurrentMappingNode is not null);
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
YamlMappingNode node = new();
|
|
CurrentMappingNode.Add(Data, node);
|
|
ContextStack.Push(new(node));
|
|
ContextStack.Push(new(node, First));
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(CurrentMappingNode is null);
|
|
Debug.Assert(CurrentSequenceNode is not null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
YamlMappingNode node = new();
|
|
CurrentSequenceNode.Add(node);
|
|
ContextStack.Push(new(node));
|
|
ContextStack.Push(new(node, First));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override void DivideDictionaryPair<TKey, TValue>(KeyValuePair<TKey, TValue> pair)
|
|
{
|
|
if (IsValidDictionaryKey<TKey>())
|
|
{
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(CurrentMappingNode is not null);
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
ContextStack.Push(new(CurrentMappingNode, Second));
|
|
}
|
|
}
|
|
|
|
public override void ExitDictionaryPair<TKey, TValue>(KeyValuePair<TKey, TValue> pair)
|
|
{
|
|
if (IsValidDictionaryKey<TKey>())
|
|
{
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(CurrentMappingNode is not null);
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
ContextStack.Pop();
|
|
}
|
|
}
|
|
|
|
public override void VisitPrimitive<T>(T value)
|
|
{
|
|
if (CurrentMappingNode is not null)
|
|
{
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
|
|
if (CurrentFieldName is not null)
|
|
{
|
|
CurrentMappingNode.Add(CurrentFieldName, ToNode(value));
|
|
|
|
//Pop the context off the stack
|
|
ContextStack.Pop();
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(IsValidDictionaryKey<T>());
|
|
ContextStack.Push(new(CurrentMappingNode, value?.ToString() ?? ""));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(CurrentSequenceNode is not null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
|
|
//Add to sequence
|
|
CurrentSequenceNode.Add(ToNode(value));
|
|
}
|
|
|
|
static YamlNode ToNode(T value)
|
|
{
|
|
// IReadOnlyList<T> branches are from EnterList
|
|
if (typeof(T) == typeof(IReadOnlyList<sbyte>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<sbyte>)value);
|
|
}
|
|
else if (typeof(T) == typeof(IReadOnlyList<byte>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<byte>)value);
|
|
}
|
|
else if (typeof(T) == typeof(IReadOnlyList<short>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<short>)value);
|
|
}
|
|
else if (typeof(T) == typeof(IReadOnlyList<ushort>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<ushort>)value);
|
|
}
|
|
else if (typeof(T) == typeof(IReadOnlyList<int>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<int>)value);
|
|
}
|
|
else if (typeof(T) == typeof(IReadOnlyList<uint>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<uint>)value);
|
|
}
|
|
else if (typeof(T) == typeof(IReadOnlyList<long>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<long>)value);
|
|
}
|
|
else if (typeof(T) == typeof(IReadOnlyList<ulong>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<ulong>)value);
|
|
}
|
|
else if (typeof(T) == typeof(IReadOnlyList<bool>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<bool>)value);
|
|
}
|
|
else if (typeof(T) == typeof(IReadOnlyList<char>))
|
|
{
|
|
return YamlScalarNode.CreateHex((IReadOnlyList<char>)value);
|
|
}
|
|
else if (typeof(T) == typeof(byte[]))
|
|
{
|
|
return YamlScalarNode.CreateHex(Unsafe.As<T, byte[]>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(bool))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, bool>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(char))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, char>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(sbyte))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, sbyte>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(byte))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, byte>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(short))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, short>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(ushort))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, ushort>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(int))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, int>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(uint))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, uint>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(long))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, long>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(ulong))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, ulong>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(float))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, float>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(double))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, double>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(string))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, string>(ref value));
|
|
}
|
|
else if (typeof(T) == typeof(Utf8String))
|
|
{
|
|
return YamlScalarNode.Create(Unsafe.As<T, Utf8String>(ref value));
|
|
}
|
|
else
|
|
{
|
|
return YamlScalarNode.Create(value?.ToString() ?? "");// Fallback
|
|
}
|
|
}
|
|
}
|
|
|
|
public sealed override void VisitPPtr<TAsset>(PPtr<TAsset> pptr)
|
|
{
|
|
AddNode(CreateYamlNodeForPPtr(pptr));
|
|
}
|
|
|
|
public virtual YamlNode CreateYamlNodeForPPtr<TAsset>(PPtr<TAsset> pptr) where TAsset : IUnityObjectBase
|
|
{
|
|
YamlMappingNode mappingNode = new()
|
|
{
|
|
Style = MappingStyle.Flow,
|
|
};
|
|
mappingNode.Add("m_FileID", pptr.FileID);
|
|
mappingNode.Add("m_PathID", pptr.PathID);
|
|
mappingNode.Add("m_TargetClassID", GetClassID(typeof(TAsset)));
|
|
return mappingNode;
|
|
}
|
|
|
|
protected static int GetClassID(Type type)
|
|
{
|
|
return (int)(ClassIDTypeMap.Dictionary.GetValueOrDefault(type, ClassIDType.Object));
|
|
}
|
|
|
|
private bool EnterMap(bool flowmapped = false)
|
|
{
|
|
ContextStack.Push(new(new YamlMappingNode(flowmapped ? MappingStyle.Flow : MappingStyle.Block)));
|
|
return true;
|
|
}
|
|
|
|
private void ExitMap()
|
|
{
|
|
YamlContext context = ContextStack.Pop();
|
|
Debug.Assert(context.MappingNode is not null);
|
|
Debug.Assert(context.SequenceNode is null);
|
|
Debug.Assert(context.FieldName is null);
|
|
|
|
AddNode(context.MappingNode);
|
|
}
|
|
|
|
private bool EnterSequence(SequenceStyle style)
|
|
{
|
|
ContextStack.Push(new(new YamlSequenceNode(style)));
|
|
return true;
|
|
}
|
|
|
|
private void ExitSequence()
|
|
{
|
|
YamlContext context = ContextStack.Pop();
|
|
Debug.Assert(context.MappingNode is null);
|
|
Debug.Assert(context.SequenceNode is not null);
|
|
Debug.Assert(context.FieldName is null);
|
|
|
|
AddNode(context.SequenceNode);
|
|
}
|
|
|
|
protected void AddNode(YamlNode node)
|
|
{
|
|
if (CurrentMappingNode is not null)
|
|
{
|
|
Debug.Assert(CurrentSequenceNode is null);
|
|
Debug.Assert(CurrentFieldName is not null);
|
|
CurrentMappingNode.Add(CurrentFieldName, node);
|
|
ContextStack.Pop();
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(CurrentSequenceNode is not null);
|
|
Debug.Assert(CurrentFieldName is null);
|
|
CurrentSequenceNode.Add(node);
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
|
private static bool IsString<T>() => typeof(T) == typeof(string) || typeof(T) == typeof(Utf8String);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
|
private static bool IsValidDictionaryKey<T>() => IsString<T>() || typeof(T).IsPrimitive || typeof(T) == typeof(GUID);
|
|
|
|
private static class HashHelper
|
|
{
|
|
public static YamlMappingNode ExportYaml(IHash128 hash)
|
|
{
|
|
return ExportYaml(hash.Bytes__0, hash.Bytes__1, hash.Bytes__2, hash.Bytes__3, hash.Bytes__4, hash.Bytes__5, hash.Bytes__6, hash.Bytes__7, hash.Bytes__8, hash.Bytes__9, hash.Bytes_10, hash.Bytes_11, hash.Bytes_12, hash.Bytes_13, hash.Bytes_14, hash.Bytes_15, hash.SerializedVersion);
|
|
}
|
|
|
|
private static YamlMappingNode ExportYaml(byte bytes__0, byte bytes__1, byte bytes__2, byte bytes__3, byte bytes__4, byte bytes__5, byte bytes__6, byte bytes__7, byte bytes__8, byte bytes__9, byte bytes_10, byte bytes_11, byte bytes_12, byte bytes_13, byte bytes_14, byte bytes_15, int serializedVersion)
|
|
{
|
|
YamlMappingNode node = new();
|
|
node.AddSerializedVersion(serializedVersion);
|
|
if (serializedVersion > 1)
|
|
{
|
|
//Unity is stupid and didn't change the type trees.
|
|
//To see an example of this, look at Texture3D.
|
|
//This change happened at the beginning of Unity 5.
|
|
string str = ToString(bytes__0, bytes__1, bytes__2, bytes__3, bytes__4, bytes__5, bytes__6, bytes__7, bytes__8, bytes__9, bytes_10, bytes_11, bytes_12, bytes_13, bytes_14, bytes_15);
|
|
node.Add(HashName, str);
|
|
}
|
|
else
|
|
{
|
|
node.Add(Bytes00Name, bytes__0);
|
|
node.Add(Bytes01Name, bytes__1);
|
|
node.Add(Bytes02Name, bytes__2);
|
|
node.Add(Bytes03Name, bytes__3);
|
|
node.Add(Bytes04Name, bytes__4);
|
|
node.Add(Bytes05Name, bytes__5);
|
|
node.Add(Bytes06Name, bytes__6);
|
|
node.Add(Bytes07Name, bytes__7);
|
|
node.Add(Bytes08Name, bytes__8);
|
|
node.Add(Bytes09Name, bytes__9);
|
|
node.Add(Bytes10Name, bytes_10);
|
|
node.Add(Bytes11Name, bytes_11);
|
|
node.Add(Bytes12Name, bytes_12);
|
|
node.Add(Bytes13Name, bytes_13);
|
|
node.Add(Bytes14Name, bytes_14);
|
|
node.Add(Bytes15Name, bytes_15);
|
|
}
|
|
return node;
|
|
}
|
|
|
|
public static string ToString(byte bytes__0, byte bytes__1, byte bytes__2, byte bytes__3, byte bytes__4, byte bytes__5, byte bytes__6, byte bytes__7, byte bytes__8, byte bytes__9, byte bytes_10, byte bytes_11, byte bytes_12, byte bytes_13, byte bytes_14, byte bytes_15)
|
|
{
|
|
//Not sure if this depends on Endianess
|
|
//If it does, it might be best to split Hash at Unity 5
|
|
uint Data0 = bytes__0 | (uint)bytes__1 << 8 | (uint)bytes__2 << 16 | (uint)bytes__3 << 24;
|
|
uint Data1 = bytes__4 | (uint)bytes__5 << 8 | (uint)bytes__6 << 16 | (uint)bytes__7 << 24;
|
|
uint Data2 = bytes__8 | (uint)bytes__9 << 8 | (uint)bytes_10 << 16 | (uint)bytes_11 << 24;
|
|
uint Data3 = bytes_12 | (uint)bytes_13 << 8 | (uint)bytes_14 << 16 | (uint)bytes_15 << 24;
|
|
string str = $"{Data0:x8}{Data1:x8}{Data2:x8}{Data3:x8}";
|
|
return str;
|
|
}
|
|
|
|
private const string Bytes00Name = "bytes[0]";
|
|
private const string Bytes01Name = "bytes[1]";
|
|
private const string Bytes02Name = "bytes[2]";
|
|
private const string Bytes03Name = "bytes[3]";
|
|
private const string Bytes04Name = "bytes[4]";
|
|
private const string Bytes05Name = "bytes[5]";
|
|
private const string Bytes06Name = "bytes[6]";
|
|
private const string Bytes07Name = "bytes[7]";
|
|
private const string Bytes08Name = "bytes[8]";
|
|
private const string Bytes09Name = "bytes[9]";
|
|
private const string Bytes10Name = "bytes[10]";
|
|
private const string Bytes11Name = "bytes[11]";
|
|
private const string Bytes12Name = "bytes[12]";
|
|
private const string Bytes13Name = "bytes[13]";
|
|
private const string Bytes14Name = "bytes[14]";
|
|
private const string Bytes15Name = "bytes[15]";
|
|
private const string HashName = "Hash";
|
|
}
|
|
}
|