hybridclr_unity/Editor/3rds/UnityFS/UnityBinFile.cs

125 lines
3.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using System.Text;
using System.Reflection;
using System;
using System.Linq;
namespace UnityFS
{
/// <summary>
/// Unity 生成的二进制文件(本代码不支持5.x之前的版本)
/// </summary>
public unsafe class UnityBinFile
{
/*
* MonoManager: idx: 6;
* type: metaData.types[objects[6].typeID]
*/
public const int kMonoManagerIdx = 6;
public FileHeader header;
public MetaData metaData;
public ScriptsData scriptsData;
private Stream _originStream;
public void LoadFromStream(Stream source)
{
_originStream = source;
using (var br = new BinaryReader(source, Encoding.UTF8, true))
{
header.LoadFromStream(br);
// 按理说 metaData 应该新开一个buffer来避免加载时的对齐逻辑问题但由于 sizeof(Header) = 20已经对齐到4了所以可以连续读
metaData.LoadFromStream(br, header.dataOffset);
scriptsData = metaData.GetScriptData(br);
}
}
public void Load(string path)
{
LoadFromStream(new MemoryStream(File.ReadAllBytes(path)));
}
public void AddScriptingAssemblies(List<string> assemblies)
{
foreach (string name in assemblies)
{
if (!scriptsData.dllNames.Contains(name))
{
scriptsData.dllNames.Add(name);
scriptsData.dllTypes.Add(16); // user dll type
Debug.Log($"[PatchScriptAssembliesJson] add dll:{name} to globalgamemanagers");
}
}
}
public byte[] CreatePatchedBytes()
{
var fsR = _originStream;
fsR.Position = 0;
var brR = new BinaryReader(fsR, Encoding.UTF8, true);
var ms = new MemoryStream((int)(header.fileSize * 1.5f));
var bw = new BinaryWriter(ms, Encoding.UTF8, true);
/*
* 开始写入data
* dll名称列表存储于 data 区段,修改其数据并不会影响 MetaData 大小,因此 dataOffset 不会改变
*/
ms.Position = header.dataOffset;
Dictionary<long, ObjectInfo> newObjInfos = new Dictionary<long, ObjectInfo>();
foreach (var kv in metaData.objects)
{
long objID = kv.Key;
ObjectInfo objInfo = kv.Value;
byte[] buff = new byte[objInfo.size];
fsR.Position = objInfo.realPos;
brR.Read(buff, 0, buff.Length);
{// unity 的数据偏移貌似会对齐到 8
int newPos = (((int)ms.Position + 7) >> 3) << 3;
int gapSize = newPos - (int)ms.Position;
for (int i = 0; i < gapSize; i++)
bw.Write((byte)0);
objInfo.dataPos = (uint)ms.Position - header.dataOffset; // 重定位数据偏移
}
if (objID != kMonoManagerIdx)
bw.Write(buff, 0, buff.Length);
else
objInfo.size = (uint)scriptsData.SaveToStream(bw);
newObjInfos.Add(objID, objInfo);
}
metaData.objects = newObjInfos;
header.fileSize = (uint)ms.Position;
ms.Position = 0;
header.SaveToStream(bw);
metaData.SaveToStream(bw);
brR.Close();
// 写入新文件
ms.Position = 0;
return ms.ToArray();
}
public void Save(string newPath)
{
byte[] patchedBytes = CreatePatchedBytes();
File.WriteAllBytes(newPath, patchedBytes);
}
}
}