update MeatKit (9a1a68ab68cd0650227af944ffa30d1166b9e056)

This commit is contained in:
msk
2023-07-26 16:45:05 -07:00
parent 920875f56b
commit d2316bac96
266 changed files with 2855 additions and 9187 deletions
@@ -0,0 +1,228 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using BepInEx;
using HarmonyLib;
using Mono.Cecil;
using Mono.Cecil.Cil;
using MethodBody = Mono.Cecil.Cil.MethodBody;
namespace MeatKit
{
public static partial class MeatKit
{
private const string EditorAssemblyPath = "Library/ScriptAssemblies/";
private static void ExportEditorAssembly(string folder, string tempFile = null,
Dictionary<string, List<string>> requiredScripts = null)
{
// Make a copy of the file if we aren't already given one
string editorAssembly = EditorAssemblyPath + AssemblyName + ".dll";
if (!File.Exists(editorAssembly) && !File.Exists(tempFile))
{
throw new MeatKitBuildException("Editor assembly missing! Can't export scripts.");
}
if (string.IsNullOrEmpty(tempFile))
{
tempFile = Path.GetTempFileName();
File.Copy(editorAssembly, tempFile, true);
}
// Delete the old file
var settings = BuildWindow.SelectedProfile;
var exportPath = folder + settings.PackageName + ".dll";
if (File.Exists(exportPath)) File.Delete(exportPath);
var rParams = new ReaderParameters
{
AssemblyResolver =
new RedirectedAssemblyResolver(Path.GetDirectoryName(typeof(UnityEngine.Object).Assembly.Location), ManagedDirectory)
};
// Get the MeatKitPlugin class and rename it
using (var asm = AssemblyDefinition.ReadAssembly(tempFile, rParams))
{
// Locate the plugin class for this profile and set it's name and namespace
string mainNamespace = BuildWindow.SelectedProfile.MainNamespace;
var plugin = FindPluginClass(asm.MainModule, mainNamespace);
BuildLog.WriteLine("Using plugin class " + plugin.FullName);
plugin.Namespace = mainNamespace;
plugin.Name = settings.PackageName + "Plugin";
// Watermark the plugin just in case it's useful to someone
BuildLog.WriteLine("Watermarking plugin class");
var str = asm.MainModule.TypeSystem.String;
var descriptionAttributeConstructor = typeof(DescriptionAttribute).GetConstructor(new[] {typeof(string)});
var descriptionAttributeRef = asm.MainModule.ImportReference(descriptionAttributeConstructor);
var descriptionAttribute = new CustomAttribute(descriptionAttributeRef);
descriptionAttribute.ConstructorArguments.Add(new CustomAttributeArgument(str, "Built with MeatKit"));
plugin.CustomAttributes.Add(descriptionAttribute);
// This is some quantum bullshit.
// If you don't enumerate the constructor arguments for attributes their values aren't updated correctly.
BuildLog.WriteLine("Performing quantum bullshit");
foreach (var x in GetAllCustomAttributes(asm).SelectMany(a => a.ConstructorArguments))
{
}
// Get the BepInPlugin attribute and replace the values in it with our own
BuildLog.WriteLine("Applying BepInPlugin attribute params");
var guid = settings.Author + "." + settings.PackageName;
var pluginAttribute = plugin.CustomAttributes.First(a => a.AttributeType.Name == "BepInPlugin");
pluginAttribute.ConstructorArguments[0] = new CustomAttributeArgument(str, guid);
pluginAttribute.ConstructorArguments[1] = new CustomAttributeArgument(str, settings.PackageName);
pluginAttribute.ConstructorArguments[2] = new CustomAttributeArgument(str, settings.Version);
// Get the LoadAssets method and make a new body for it
BuildLog.WriteLine("Generating LoadAssets()");
var loadAssetsMethod = plugin.Methods.First(m => m.Name == "LoadAssets");
loadAssetsMethod.Body = new MethodBody(loadAssetsMethod);
var il = loadAssetsMethod.Body.GetILProcessor();
// If we're automatically applying Harmony patches, do that now
// This IL translates to Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "PluginGuid");
if (settings.ApplyHarmonyPatches)
{
BuildLog.WriteLine(" Code to apply harmony patches");
var assemblyGetExecutingAssembly = typeof(Assembly).GetMethod("GetExecutingAssembly");
var harmonyCreateAndPatchALl = typeof(Harmony).GetMethod("CreateAndPatchAll", new[] {typeof(Assembly), typeof(string)});
il.Emit(OpCodes.Call, plugin.Module.ImportReference(assemblyGetExecutingAssembly));
il.Emit(OpCodes.Ldstr, guid);
il.Emit(OpCodes.Call, plugin.Module.ImportReference(harmonyCreateAndPatchALl));
il.Emit(OpCodes.Pop);
}
// Let any build items insert their own code in here
foreach (var item in settings.BuildItems)
{
BuildLog.WriteLine(" " + item);
item.GenerateLoadAssets(plugin, il);
}
// Insert a ret at the end so it's valid
il.Emit(OpCodes.Ret);
// Module name needs to be changed away from Assembly-CSharp.dll because it is a reserved name.
string newAssemblyName = settings.PackageName + ".dll";
BuildLog.WriteLine("Renaming assembly (" + newAssemblyName + ")");
asm.Name = new AssemblyNameDefinition(settings.PackageName, asm.Name.Version);
asm.MainModule.Name = newAssemblyName;
// References to renamed unity code must be swapped out.
BuildLog.WriteLine("Renaming assembly references");
foreach (var ii in asm.MainModule.AssemblyReferences)
{
// Rename any references to the game's code
if (ii.Name.Contains("H3VRCode-CSharp"))
{
var newReference = ii.Name.Replace("H3VRCode-CSharp", "Assembly-CSharp");
BuildLog.WriteLine(" " + ii.Name + " -> " + newReference);
ii.Name = newReference;
}
// And also if we're referencing a MonoMod DLL, we need to fix reference too
if (ii.Name.EndsWith(".mm"))
{
// What the name currently is:
// Assembly-CSharp.PatchName.mm
// What we want:
// Assembly-CSharp
// So just lop off anything past the second to last dot
int idx = ii.Name.LastIndexOf('.', ii.Name.Length - 4);
var newReference = ii.Name.Substring(0, idx);
BuildLog.WriteLine(" " + ii.Name + " -> " + newReference);
ii.Name = newReference;
}
}
if (BuildWindow.SelectedProfile.StripNamespaces)
{
// Remove types not in an allowed namespace or the global namespace
BuildLog.WriteLine("Stripping namespaces");
string[] allowedNamespaces = BuildWindow.SelectedProfile.GetAllAllowedNamespaces();
List<TypeDefinition> typesToRemove = new List<TypeDefinition>();
foreach (var type in asm.MainModule.Types)
{
if (type.Namespace == "" || allowedNamespaces.Any(x => type.Namespace.Contains(x)))
continue;
BuildLog.WriteLine(" " + type.FullName);
typesToRemove.Add(type);
}
foreach (var type in typesToRemove) asm.MainModule.Types.Remove(type);
}
// Remove the same types we didn't want to import. This cannot be skipped.
foreach (var type in StripAssemblyTypes
.Select(x => asm.MainModule.GetType(x))
.Where(x => x != null)) asm.MainModule.Types.Remove(type);
// Check if we're now missing any scripts from the export
BuildLog.WriteLine("Checking for missing types");
List<string> missing = new List<string>();
string originalAssemblyName = AssemblyName + ".dll";
if (requiredScripts != null && requiredScripts.ContainsKey(originalAssemblyName))
{
missing.AddRange(requiredScripts[originalAssemblyName]
.Where(typeName => !StripAssemblyTypes.Contains(typeName) && asm.MainModule.GetType(typeName) == null));
}
// If we're missing anything, fail the build.
if (missing.Count > 0)
{
string missingTypes = string.Join("\n", missing.ToArray());
throw new MeatKitBuildException(
"Exported objects reference scripts which do not exist in the exported assembly... Did you forget to allow a namespace?\n\nMissing types:\n" +
missingTypes, null);
}
try
{
// Save it
asm.Write(exportPath);
}
catch (ArgumentException e)
{
throw new MeatKitBuildException(
"Unable to write exported scripts file. This is likely due to namespace stripping being enabled and a required namespace is not whitelisted.",
e);
}
}
// Delete temp file now that we're done.
File.Delete(tempFile);
}
private static TypeDefinition FindPluginClass(ModuleDefinition module, string mainNamespace)
{
// Get the default MeatKitPlugin class from the module
var pluginClass = module.GetType("MeatKitPlugin");
// Try and locate any alternative plugin classes
foreach (var type in module.Types)
{
// We're looking for types that extend the BaseUnityPlugin class and is in the main namespace of our mod
if (type.IsSubtypeOf(typeof(BaseUnityPlugin)) && type.Namespace == mainNamespace)
{
pluginClass = type;
break;
}
}
return pluginClass;
}
private static IEnumerable<CustomAttribute> GetAllCustomAttributes(AssemblyDefinition asm)
{
foreach (var type in asm.MainModule.Types)
{
foreach (var attrib in type.CustomAttributes) yield return attrib;
foreach (CustomAttribute attrib in type.Methods.SelectMany(method => method.CustomAttributes))
yield return attrib;
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0c6f57f9c2dd40b8a7eabb4f85e2e283
timeCreated: 1617344435
@@ -0,0 +1,292 @@
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using Mono.Cecil;
using NStrip;
using UnityEditor;
using UnityEngine;
namespace MeatKit
{
/// <summary>
/// Assembly importer class to get the managed assemblies from the game into the Unity editor without
/// the editor wanting to crash itself. Original implementation by Nolenz.
/// https://github.com/WurstModders/WurstMod-Reloaded/blob/2e33e83284b3a9f39c8df210ad907925d1d7d9d8/WMRWorkbench/Assets/Editor/Manglers/AssemblyMangler.cs
/// </summary>
public static partial class MeatKit
{
public const string AssemblyName = "Assembly-CSharp";
public const string AssemblyRename = "H3VRCode-CSharp";
public const string AssemblyFirstpassName = "Assembly-CSharp-firstpass";
public const string AssemblyFirstpassRename = "H3VRCode-CSharp-firstpass";
// Types we want to strip from the main Unity assembly
public static readonly string[] StripAssemblyTypes =
{
// Alloy classes
"MaterialMapChannelPackerDefinition",
"Alloy.PackedMapDefinition",
"Alloy.BaseTextureChannelMapping",
"Alloy.MapChannel",
"Alloy.TextureValueChannelMode",
"Alloy.NormalMapChannelTextureChannelMapping",
"Alloy.TextureImportConfig",
"Alloy.MapTextureChannelMapping",
"AlloyUtils",
"Alloy.EnumExtension",
"MinValueAttribute",
"MaxValueAttribute",
"AlloyEffectsManager",
"Alloy.EnumFlagsAttribute",
// Bakery MonoBehaviours
"BakeryAlwaysRender",
"BakeryDirectLight",
"BakeryLightmapGroup",
"BakeryLightmapGroupSelector",
"BakeryLightmappedPrefab",
"BakeryLightMesh",
"BakeryPointLight",
"BakerySkyLight",
"BakeryVolume",
"BakeryVolumeReceiver",
"BakeryVolumeTrigger",
"BakeryProjectSettings",
"VolumeTestScene2",
"BakeryPackAsSingleSquare",
"BakerySector",
"BakerySectorCapture",
"ftGlobalStorage",
"ftLightmaps",
"ftLightmapsStorage",
"ftLocalStorage",
// Bakery supporting types
"ftUniqueIDRegistry",
"BakeryLightmapGroupPlain",
//Editor Tool Scripts
"IconCamera"
};
// Array of the extra assemblies that need to come with the main Unity assemblies
private static readonly string[] ExtraAssemblies =
{
"DinoFracture.dll",
"ES2.dll"
};
private static void ImportAssemblies(string assembliesDirectory, string destinationDirectory)
{
// Remove whatever was there before and make the folder again
if (!Directory.Exists(destinationDirectory)) Directory.CreateDirectory(destinationDirectory);
// Load all of our modifiers
var editors = Extensions.GetAllInstances<AssemblyModifier>();
foreach (var editor in editors) editor.Applied = false;
// We need a custom assembly resolver that sometimes points to different directories.
var rParams = new ReaderParameters
{
AssemblyResolver = new RedirectedAssemblyResolver(assembliesDirectory, destinationDirectory)
};
// Rename the game's firstpass assembly
{
var firstpassAssembly =
AssemblyDefinition.ReadAssembly(Path.Combine(assembliesDirectory, AssemblyFirstpassName + ".dll"));
firstpassAssembly.Name =
new AssemblyNameDefinition(AssemblyFirstpassRename, firstpassAssembly.Name.Version);
firstpassAssembly.MainModule.Name = AssemblyFirstpassRename + ".dll";
// Apply modifications
foreach (var editor in editors) editor.ApplyModification(firstpassAssembly);
// Publicize Assembly
AssemblyStripper.MakePublic(firstpassAssembly, new string[0], false, false);
firstpassAssembly.Write(Path.Combine(destinationDirectory, AssemblyFirstpassRename + ".dll"));
firstpassAssembly.Dispose();
}
// Main assembly
{
// Rename the main assembly
var mainAssembly =
AssemblyDefinition.ReadAssembly(Path.Combine(assembliesDirectory, AssemblyName + ".dll"), rParams);
mainAssembly.Name = new AssemblyNameDefinition(AssemblyRename, mainAssembly.Name.Version);
mainAssembly.MainModule.Name = AssemblyRename + ".dll";
// Change the firstpass reference in this assembly
mainAssembly.MainModule.AssemblyReferences
.First(x => x.Name == AssemblyFirstpassName)
.Name = AssemblyFirstpassRename;
// Strip some types from the assembly to prevent doubles in the editor
foreach (var typename in StripAssemblyTypes)
{
var type = mainAssembly.MainModule.GetType(typename);
if (type != null) mainAssembly.MainModule.Types.Remove(type);
else Debug.LogWarning("Type " + typename + " was not found in assembly.");
}
// Apply modifications
foreach (var editor in editors) editor.ApplyModification(mainAssembly);
// Publicize assembly
AssemblyStripper.MakePublic(mainAssembly, new string[0], false, false);
// Apply help URLs
ApplyWikiHelpAttribute(mainAssembly);
// Write the main assembly out into the destination folder and dispose it
mainAssembly.Write(Path.Combine(destinationDirectory, AssemblyRename + ".dll"));
}
// Then lastly copy the other assemblies to the destination folder
foreach (var file in ExtraAssemblies)
{
var path = Path.Combine(assembliesDirectory, file);
if (File.Exists(path))
ImportSingleAssembly(path, destinationDirectory);
}
// Check if anything didn't apply
foreach (var editor in editors)
if (!editor.Applied)
Debug.LogWarning(editor.name + " was not applied while importing.", editor);
// When we're done importing assemblies, let Unity refresh the asset database
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "H3VR_IMPORTED");
NormalizeMetaFileGUIDs();
}
private static void ImportSingleAssembly(string assemblyPath, string destinationDirectory)
{
var rParams = new ReaderParameters
{
AssemblyResolver =
new RedirectedAssemblyResolver(Path.GetDirectoryName(assemblyPath), destinationDirectory)
};
// If this assembly uses the Assembly-CSharp name at all for any reason, replace it with H3VRCode-CSharp
// This would probably only be done on MonoMod patches but is required to make Unity shut up
var asm = AssemblyDefinition.ReadAssembly(assemblyPath, rParams);
string name = asm.Name.Name;
if (name.Contains("Assembly-CSharp"))
{
name = name.Replace("Assembly-CSharp", "H3VRCode-CSharp");
asm.Name = new AssemblyNameDefinition(name, asm.Name.Version);
asm.MainModule.Name = name + ".dll";
}
// Replace all occurrences to references of Assembly-CSharp with H3VRCode-CSharp
foreach (var reference in asm.MainModule.AssemblyReferences)
{
if (reference.Name.Contains("Assembly-CSharp"))
{
reference.Name = reference.Name.Replace("Assembly-CSharp", "H3VRCode-CSharp");
}
}
asm.Write(Path.Combine(destinationDirectory, asm.MainModule.Name));
NormalizeMetaFileGUIDs();
}
private static void ApplyWikiHelpAttribute(AssemblyDefinition asm)
{
// For convenience, we can add the Unity HelpURL attribute to the components from the game assembly.
// We'll point the url at the wiki and just append the full type name at the end
// Iterate over every type in the assembly and just stick the attribute on it
// Probably doesn't matter if types that don't need it have it.
foreach (var type in asm.MainModule.Types)
{
// If the type doesn't already have this attribute, add it.
if (type.CustomAttributes.Any(a => a.AttributeType.Name == "HelpURLAttribute")) continue;
string helpUrl = "https://h3vr-modding.github.io/wiki/docs/h3vr/" + type.FullName + ".html";
var str = asm.MainModule.TypeSystem.String;
var attributeConstructor = typeof(HelpURLAttribute).GetConstructor(new[] {typeof(string)});
var attributeRef = asm.MainModule.ImportReference(attributeConstructor);
var attribute = new CustomAttribute(attributeRef);
attribute.ConstructorArguments.Add(new CustomAttributeArgument(str, helpUrl));
type.CustomAttributes.Add(attribute);
}
}
private static void NormalizeMetaFileGUIDs()
{
// This is a really important step. We need to make sure that the meta files for the assemblies are generated
// WITH THE SAME GUIDs each time. Otherwise, if you lose one and didn't have a backup, all your scripts will be missing
// and that is of course no bueno. Unity expects 32 hexadecimal digits for the guid so we'll use md5.
// We need every meta file to exist already.
AssetDatabase.Refresh();
var hashFunction = MD5.Create();
var replaceWith = new Regex(@"^guid: [0-9a-f]{32}$", RegexOptions.Multiline);
foreach (var metaFile in Directory.GetFiles(ManagedDirectory, "*.meta"))
{
// First we get the hash
var assemblyName = Path.GetFileName(metaFile.Substring(0, metaFile.Length - 5));
var hash = hashFunction.ComputeHash(Encoding.UTF8.GetBytes(assemblyName));
var hexHash = Extensions.ByteArrayToString(hash).ToLower();
// Then we need to replace the hash in the meta file with it.
var metaText = File.ReadAllText(metaFile);
metaText = replaceWith.Replace(metaText, "guid: " + hexHash);
File.WriteAllText(metaFile, metaText);
}
// If anything was changed we need Unity to apply it immediately.
AssetDatabase.Refresh();
}
/// <summary>
/// Assembly resolver that redirects references to another path if not found.
/// </summary>
private class RedirectedAssemblyResolver : BaseAssemblyResolver
{
private readonly DefaultAssemblyResolver _defaultResolver = new DefaultAssemblyResolver();
private readonly string[] _redirectPaths;
public RedirectedAssemblyResolver(params string[] redirectPath)
{
_redirectPaths = redirectPath;
}
public override AssemblyDefinition Resolve(AssemblyNameReference name)
{
AssemblyDefinition asm = null;
try
{
asm = _defaultResolver.Resolve(name);
}
catch (AssemblyResolutionException)
{
foreach (var path in _redirectPaths)
try
{
var asmPath = Path.Combine(path, name.Name + ".dll");
if (File.Exists(asmPath))
asm = AssemblyDefinition.ReadAssembly(asmPath,
new ReaderParameters {AssemblyResolver = this});
}
catch (AssemblyResolutionException)
{
// Ignored
}
}
if (asm != null) return asm;
throw new AssemblyResolutionException(name);
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4d2f661647864f0689e2c38c7c687c99
timeCreated: 1617325184
@@ -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;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3994182a62444e7e97029b92adc131f5
timeCreated: 1655415474