mirror of
https://github.com/muskit/H3VR-TNH-Quality-of-Life-Improvements.git
synced 2026-06-02 20:24:26 -07:00
update MeatKit (9a1a68ab68cd0650227af944ffa30d1166b9e056)
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MeatKit
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public static class AssetBundleIO
|
||||
{
|
||||
// Toggles for keeping track if we're processing reads and/or writes
|
||||
public static bool ProcessingEnabledRead { get; private set; }
|
||||
public static bool ProcessingEnabledWrite { get; private set; }
|
||||
|
||||
// Output dictionaries for remembering what scripts got modified.
|
||||
public static Dictionary<string, List<string>> SerializedScriptNames { get; private set; }
|
||||
public static Dictionary<string, List<string>> DeserializedScriptNames { get; private set; }
|
||||
|
||||
private static Dictionary<string, string> _replaceMap;
|
||||
|
||||
static AssetBundleIO()
|
||||
{
|
||||
if (!EditorVersion.IsSupportedVersion) return;
|
||||
|
||||
// Apply the one hook we need here
|
||||
OrigMonoScriptTransferWrite = NativeHookManager.ApplyEditorDetour<MonoScriptTransferWrite>(EditorVersion.Current.FunctionOffsets.MonoScriptTransferWrite, new MonoScriptTransferWrite(OnMonoScriptTransferWrite));
|
||||
OrigMonoScriptTransferRead = NativeHookManager.ApplyEditorDetour<MonoScriptTransferRead>(EditorVersion.Current.FunctionOffsets.MonoScriptTransferRead, new MonoScriptTransferRead(OnMonoScriptTransferRead));
|
||||
}
|
||||
|
||||
public static void EnableProcessing(Dictionary<string, string> replaceMap, bool read, bool write)
|
||||
{
|
||||
_replaceMap = replaceMap;
|
||||
SerializedScriptNames = new Dictionary<string, List<string>>();
|
||||
DeserializedScriptNames = new Dictionary<string, List<string>>();
|
||||
ProcessingEnabledRead = read;
|
||||
ProcessingEnabledWrite = write;
|
||||
}
|
||||
|
||||
public static void DisableProcessing()
|
||||
{
|
||||
ProcessingEnabledRead = false;
|
||||
ProcessingEnabledWrite = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a detour on some of the native Unity editor code which is part of writing data to asset bundles.
|
||||
/// When Unity goes to serialize a MonoScript struct, we want to pre-process it a bit before it actually
|
||||
/// writes the data to the bundle.
|
||||
///
|
||||
/// Our processing includes building a list of used scripts so we can verify the user has their exports setup
|
||||
/// properly, as well as remapping the assembly names for some scripts so that references are maintained
|
||||
/// correctly when loaded in the game.
|
||||
/// </summary>
|
||||
private static void OnMonoScriptTransferWrite(IntPtr monoScript, IntPtr streamedBinaryWrite)
|
||||
{
|
||||
// If processing is disabled just run the original and skip.
|
||||
if (!ProcessingEnabledWrite)
|
||||
{
|
||||
OrigMonoScriptTransferWrite(monoScript, streamedBinaryWrite);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a couple variables for later
|
||||
var applied = false;
|
||||
|
||||
// Read the assembly name and class name from memory
|
||||
var className = UnityNativeHelper.ReadNativeString(monoScript, MonoScriptClassName);
|
||||
var assemblyName = UnityNativeHelper.ReadNativeString(monoScript, MonoScriptAssemblyName);
|
||||
var namespaceName = UnityNativeHelper.ReadNativeString(monoScript, MonoScriptNamespace);
|
||||
var fullName = string.IsNullOrEmpty(namespaceName) ? className : (namespaceName + "." + className);
|
||||
|
||||
// Add it to the scripts usage dictionary
|
||||
if (!SerializedScriptNames.ContainsKey(assemblyName)) SerializedScriptNames[assemblyName] = new List<string>();
|
||||
SerializedScriptNames[assemblyName].Add(fullName);
|
||||
|
||||
// Prepare some debugging string
|
||||
string debug = " " + assemblyName + " " + fullName + ": ";
|
||||
|
||||
// Check if we want to remap this assembly name
|
||||
string newAssemblyName;
|
||||
if (_replaceMap.TryGetValue(assemblyName, out newAssemblyName))
|
||||
{
|
||||
// If we're processing a type that should exist in the main game assembly, skip translation
|
||||
if (assemblyName != MeatKit.AssemblyName + ".dll" || !MeatKit.StripAssemblyTypes.Contains(fullName))
|
||||
{
|
||||
// Write the new assembly name into memory
|
||||
UnityNativeHelper.WriteNativeString(monoScript, MonoScriptAssemblyName, newAssemblyName);
|
||||
applied = true;
|
||||
debug += "ReplaceMap";
|
||||
}
|
||||
else
|
||||
{
|
||||
debug += "Ignored";
|
||||
}
|
||||
}
|
||||
|
||||
// If it didn't exist in the replace map, check if it contains H3VRCode-CSharp. This is for MonoMod assemblies.
|
||||
else if (assemblyName.Contains(MeatKit.AssemblyRename))
|
||||
{
|
||||
// Write the new assembly name into memory
|
||||
UnityNativeHelper.WriteNativeString(monoScript, MonoScriptAssemblyName, assemblyName.Replace(MeatKit.AssemblyRename, MeatKit.AssemblyName));
|
||||
applied = true;
|
||||
debug += "MonoMod";
|
||||
}
|
||||
else
|
||||
{
|
||||
debug += "Unchanged";
|
||||
}
|
||||
|
||||
BuildLog.WriteLine(debug);
|
||||
|
||||
// Let the original method run
|
||||
OrigMonoScriptTransferWrite(monoScript, streamedBinaryWrite);
|
||||
|
||||
// If we didn't apply any remapping, skip this last part.
|
||||
if (!applied) return;
|
||||
|
||||
// Cleanup by writing the original value back to memory and freeing the memory allocated for the new name.
|
||||
UnityNativeHelper.WriteNativeString(monoScript, MonoScriptAssemblyName, assemblyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Any time the editor reads from an asset bundle, we want to apply our remapping so that references from
|
||||
/// the game can be properly deserialized.
|
||||
/// </summary>
|
||||
private static long OnMonoScriptTransferRead(IntPtr monoScript, IntPtr streamedBinaryRead)
|
||||
{
|
||||
// Run the original method and return the result if processing is disabled.
|
||||
long result = OrigMonoScriptTransferRead(monoScript, streamedBinaryRead);
|
||||
if (!ProcessingEnabledRead) return result;
|
||||
|
||||
// Read the assembly name and class name from memory
|
||||
var className = UnityNativeHelper.ReadNativeString(monoScript, MonoScriptClassName);
|
||||
var assemblyName = UnityNativeHelper.ReadNativeString(monoScript, MonoScriptAssemblyName);
|
||||
var namespaceName = UnityNativeHelper.ReadNativeString(monoScript, MonoScriptNamespace);
|
||||
var fullName = string.IsNullOrEmpty(namespaceName) ? className : (namespaceName + "." + className);
|
||||
|
||||
// Add it to the scripts usage dictionary
|
||||
if (!DeserializedScriptNames.ContainsKey(assemblyName)) DeserializedScriptNames[assemblyName] = new List<string>();
|
||||
DeserializedScriptNames[assemblyName].Add(fullName);
|
||||
|
||||
// Check if we want to remap this assembly name
|
||||
string newAssemblyName;
|
||||
if (_replaceMap.TryGetValue(assemblyName, out newAssemblyName))
|
||||
{
|
||||
// If we're processing a type that should exist in the main game assembly, skip translation
|
||||
if (assemblyName != MeatKit.AssemblyName || !MeatKit.StripAssemblyTypes.Contains(fullName))
|
||||
// Write the new assembly name into memory
|
||||
UnityNativeHelper.WriteNativeString(monoScript, MonoScriptAssemblyName, newAssemblyName);
|
||||
}
|
||||
|
||||
// If it didn't exist in the replace map, check if it contains H3VRCode-CSharp. This is for MonoMod assemblies.
|
||||
else if (assemblyName.Contains(MeatKit.AssemblyName))
|
||||
{
|
||||
// Write the new assembly name into memory
|
||||
UnityNativeHelper.WriteNativeString(monoScript, MonoScriptAssemblyName, assemblyName.Replace(MeatKit.AssemblyName, MeatKit.AssemblyRename));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Actual name: MonoScript::Transfer<StreamedBinaryWrite<0>>(StreamedBinaryWrite<0> &)
|
||||
private delegate void MonoScriptTransferWrite(IntPtr monoScript, IntPtr streamedBinaryWrite);
|
||||
|
||||
private static readonly MonoScriptTransferWrite OrigMonoScriptTransferWrite;
|
||||
|
||||
// Actual name: MonoScript::Transfer<StreamedBinaryRead<1>>(StreamedBinaryRead<1> &)
|
||||
private delegate long MonoScriptTransferRead(IntPtr monoScript, IntPtr streamedBinaryRead);
|
||||
|
||||
private static readonly MonoScriptTransferRead OrigMonoScriptTransferRead;
|
||||
|
||||
private const int MonoScriptClassName = 224;
|
||||
|
||||
private const int MonoScriptNamespace = 272;
|
||||
|
||||
private const int MonoScriptAssemblyName = 320;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user