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
-31
View File
@@ -1,31 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: afed54a239594b8abd631a8047a54987, type: 3}
m_Name: BuildProfile
m_EditorClassIdentifier:
PackageName: TNH_Quality_of_Life_Improvements
Author: muskit
Version: 1.2.3
Icon: {fileID: 2800000, guid: 785b7946398f5314b95bf593d2d77d67, type: 3}
ReadMe: {fileID: 102900000, guid: ab1d6dea017447a48ac348db588a6f35, type: 3}
WebsiteURL: https://github.com/muskit/TNH-Quality-of-Life-Improvements
Description: Quality of life improvements to the Take and Hold experience.
AdditionalDependencies:
- BepInEx-BepInExPack_H3VR-5.4.1700
- nrgill28-Sodalite-1.3.5
StripNamespaces: 0
AdditionalNamespaces:
- TNHQoLImprovements
BuildItems:
- {fileID: 11400000, guid: ccaff18373cd99848b344316974e6d46, type: 2}
BundleCompressionType: 2
BuildAction: 1
OutputProfile: C:/Users/Alex/AppData/Roaming/r2modmanPlus-local/H3VR/profiles/dev
+186
View File
@@ -0,0 +1,186 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6389bd26f6b33074ba8afe182d11c33d, type: 3}
m_Name: DefaultPathReplacements
m_EditorClassIdentifier:
ReplacementPaths:
- ScriptableObjectName: FistVR.MainMenuSceneDef
NewPath: Misc/MainMenuSceneDef
NewDefaultName: MainMenuSceneDef
NewOrder: 0
- ScriptableObjectName: FistVR.ZosigMoodPreset
NewPath: Sosig/Zosig/MoodPreset
NewDefaultName: MoodPreset
NewOrder: 0
- ScriptableObjectName: FistVR.ZBldgTileList
NewPath: Sosig/Zosig/zBldgTileList
NewDefaultName: zBldgTileList
NewOrder: 0
- ScriptableObjectName: FistVR.ZosigEnemyTemplate
NewPath: Sosig/Zosig/ZosigEnemyTemplate
NewDefaultName: ZosigEnemyTemplate
NewOrder: 0
- ScriptableObjectName: FistVR.ZosigItemSpawnTable
NewPath: Sosig/Zosig/ZosigItemSpawnTable
NewDefaultName: ZosigItemSpawnTable
NewOrder: 0
- ScriptableObjectName: FistVR.ZosigNPCProfile
NewPath: Sosig/Zosig/ZosigNPCProfile
NewDefaultName: ZosigNPCProfile
NewOrder: 0
- ScriptableObjectName: FistVR.HangableDef
NewPath: Misc/HangableDef
NewDefaultName: HangableDef
NewOrder: 0
- ScriptableObjectName: FistVR.AutoMeaterFirearmSoundProfile
NewPath: Misc/AutoMeaterFirearmSoundProfile
NewDefaultName: AutoMeaterFirearmSoundProfile
NewOrder: 0
- ScriptableObjectName: FistVR.wwBotWurstGunSoundConfig
NewPath: Misc/wwBotWurstGunSoundConfig
NewDefaultName: wwBotWurstGunSoundConfig
NewOrder: 0
- ScriptableObjectName: FistVR.DestructibleChunkProfile
NewPath: Destruction/DestructibleChunkProfile
NewDefaultName: DestructibleChunkProfile
NewOrder: 0
- ScriptableObjectName: FistVR.BreakableGlassPattern
NewPath: Destruction/BreakableGlassPattern
NewDefaultName: BreakableGlassPattern
NewOrder: 0
- ScriptableObjectName: FistVR.CubeGameWaveType
NewPath: Misc/CubeGameWaveType
NewDefaultName: CubeGameWaveType
NewOrder: 0
- ScriptableObjectName: FistVR.CubeGameWaveElement
NewPath: Misc/CubeGameWaveElement
NewDefaultName: CubeGameWaveElement
NewOrder: 0
- ScriptableObjectName: FistVR.CubeGameWaveSequence
NewPath: Misc/CubeGameWaveSequence
NewDefaultName: CubeGameWaveSequence
NewOrder: 0
- ScriptableObjectName: FistVR.UberShatterableDamageConfig
NewPath: Destruction/UberShatterableDamageConfig
NewDefaultName: UberShatterableDamageConfig
NewOrder: 0
- ScriptableObjectName: FistVR.UberShatterableMeshDecalConfig
NewPath: Destruction/UberShatterableMeshDecalConfig
NewDefaultName: UberShatterableMeshDecalConfig
NewOrder: 0
- ScriptableObjectName: FistVR.BallisticChart
NewPath: Ballistics/BallisticChart
NewDefaultName: BallisticChart
NewOrder: 0
- ScriptableObjectName: FistVR.PMaterialDefinition
NewPath: Misc/PMaterialDefinition
NewDefaultName: PMaterialDefinition
NewOrder: 0
- ScriptableObjectName: FistVR.MatDef
NewPath: Misc/MatDef
NewDefaultName: MatDef
NewOrder: 0
- ScriptableObjectName: FistVR.FVRControllerDefinition
NewPath: Misc/FVRControllerDefinition
NewDefaultName: FVRControllerDefinition
NewOrder: 0
- ScriptableObjectName: FistVR.FVREntityFlagUsage
NewPath: Misc/FVREntityFlagUsage
NewDefaultName: FVREntityFlagUsage
NewOrder: 0
- ScriptableObjectName: FistVR.FVREntityDefinition
NewPath: Misc/FVREntityDefinition
NewDefaultName: FVREntityDefinition
NewOrder: 0
- ScriptableObjectName: FistVR.HG_ModeProfile
NewPath: Misc/HG_ModeProfile
NewDefaultName: HG_ModeProfile
NewOrder: 0
- ScriptableObjectName: FistVR.MF_SquadDefinition
NewPath: Misc/MF_SquadDefinition
NewDefaultName: MF_SquadDefinition
NewOrder: 0
- ScriptableObjectName: FistVR.MG_EventAIConfig
NewPath: Misc/MG_EventAIConfig
NewDefaultName: MG_EventAIConfig
NewOrder: 0
- ScriptableObjectName: FistVR.MG_IncidenceChart
NewPath: Misc/MG_IncidenceChart
NewDefaultName: MG_IncidenceChart
NewOrder: 0
- ScriptableObjectName: FistVR.OmniSequencerSequenceDefinition
NewPath: Misc/OmniSequencerSequenceDefinition
NewDefaultName: OmniSequencerSequenceDefinition
NewOrder: 0
- ScriptableObjectName: FistVR.SV_LootTable
NewPath: Misc/SV_LootTable
NewDefaultName: SV_LootTable
NewOrder: 0
- ScriptableObjectName: FistVR.wwBotWurstConfig
NewPath: Misc/wwBotWurstConfig
NewDefaultName: wwBotWurstConfig
NewOrder: 0
- ScriptableObjectName: FistVR.wwMagicKeypadHash
NewPath: Misc/wwMagicKeypadHash
NewDefaultName: wwMagicKeypadHash
NewOrder: 0
- ScriptableObjectName: FistVR.SlideSequenceDef
NewPath: Misc/SlideSequenceDef
NewDefaultName: SlideSequenceDef
NewOrder: 0
- ScriptableObjectName: FistVR.PTargetCategoryDic
NewPath: Misc/PTargetCategoryDic
NewDefaultName: PTargetCategoryDic
NewOrder: 0
- ScriptableObjectName: FistVR.ReticleColorProgression
NewPath: Misc/ReticleColorProgression
NewDefaultName: ReticleColorProgression
NewOrder: 0
- ScriptableObjectName: FistVR.FVRHapticBuzzProfile
NewPath: Misc/FVRHapticBuzzProfile
NewDefaultName: FVRHapticBuzzProfile
NewOrder: 0
- ScriptableObjectName: FistVR.ItemSpawnerCategoryDefinitionsV2
NewPath: ItemSpawner/ItemSpawnerCategoryDefinitionsV2
NewDefaultName: ItemSpawnerCategoryDefinitionsV2
NewOrder: 0
- ScriptableObjectName: FistVR.ItemSpawnerNewItemManifest
NewPath: ItemSpawner/ItemSpawnerNewItemManifest
NewDefaultName: ItemSpawnerNewItemManifest
NewOrder: 0
- ScriptableObjectName: FistVR.ItemSpawnerV2TagCatDef
NewPath: ItemSpawner/ItemSpawnerV2TagCatDef
NewDefaultName: ItemSpawnerV2TagCatDef
NewOrder: 0
- ScriptableObjectName: FistVR.EquipmentPoolDef
NewPath: TNH/EquipmentPoolDef
NewDefaultName: EquipmentPoolDef
NewOrder: 0
- ScriptableObjectName: FistVR.TNH_CharacterDef
NewPath: TNH/TNH_CharacterDef
NewDefaultName: TNH_CharacterDef
NewOrder: 0
- ScriptableObjectName: FistVR.ObjectTableDef
NewPath: TNH/ObjectTableDef
NewDefaultName: ObjectTableDef
NewOrder: 0
- ScriptableObjectName: FistVR.TNH_PointSequence
NewPath: TNH/TNH_PointSequence
NewDefaultName: TNH_PointSequence
NewOrder: 0
- ScriptableObjectName: FistVR.PTargetProfile
NewPath: Misc/PTargetProfile
NewDefaultName: PTargetProfile
NewOrder: 0
- ScriptableObjectName: FistVR.TutorialBlock
NewPath: ItemSpawner/TutorialBlock
NewDefaultName: TutorialBlock
NewOrder: 0
@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: b545caf63c55b0143bd5c4ce2e5eef7c
timeCreated: 1642332594
guid: ef60ed33189250d4c8b65b237758ad95
timeCreated: 1645904809
licenseType: Free
NativeFormatImporter:
mainObjectFileID: 11400000
-126
View File
@@ -1,126 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace MeatKit
{
public static partial class MeatKit
{
private const string EditorAssemblyPath = "Library/ScriptAssemblies/";
public const string BundleOutputPath = "AssetBundles/";
private static void ExportEditorAssembly(string folder)
{
if (!File.Exists(EditorAssemblyPath + AssemblyName + ".dll")) return;
// 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))
};
// Get the MeatKitPlugin class and rename it
string tempFile = Path.GetTempFileName();
File.Copy(EditorAssemblyPath + AssemblyName + ".dll", tempFile, true);
using (var asm = AssemblyDefinition.ReadAssembly(tempFile, rParams))
{
var plugin = asm.MainModule.GetType("MeatKitPlugin");
plugin.Name = settings.PackageName + "Plugin";
// This is some quantum bullshit.
// If you don't enumerate the constructor arguments for attributes their values aren't updated correctly.
foreach (var x in GetAllCustomAttributes(asm).SelectMany(a => a.ConstructorArguments))
{
}
// Get the BepInPlugin attribute and replace the values in it with our own
var str = asm.MainModule.TypeSystem.String;
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
var loadAssetsMethod = plugin.Methods.First(m => m.Name == "LoadAssets");
loadAssetsMethod.Body = new MethodBody(loadAssetsMethod);
var il = loadAssetsMethod.Body.GetILProcessor();
// Let any build items insert their own code in here
foreach (var item in settings.BuildItems)
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.
asm.Name = new AssemblyNameDefinition(settings.PackageName, asm.Name.Version);
asm.MainModule.Name = settings.PackageName + ".dll";
// References to renamed unity code must be swapped out.
foreach (var ii in asm.MainModule.AssemblyReferences)
switch (ii.Name)
{
case AssemblyRename:
ii.Name = AssemblyName;
break;
case AssemblyFirstpassRename:
ii.Name = AssemblyFirstpassName;
break;
}
if (BuildWindow.SelectedProfile.StripNamespaces)
{
// Remove types not in an allowed namespace or the global namespace
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;
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);
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 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;
}
}
}
}
@@ -1,3 +1,12 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: c7e21420a1d84ca5947b2fd9eb9db6d8
timeCreated: 1628213934
timeCreated: 1649523855
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,80 @@
using System;
using System.Linq;
using Mono.Cecil;
using UnityEngine;
namespace MeatKit
{
[CreateAssetMenu(menuName = "MeatKit/Assembly Editors/Path Replacer", fileName = "New Path Replacer")]
public class CreatePathModifier : AssemblyModifier
{
[Tooltip("The new path replacements")]
public ReplacementPath[] ReplacementPaths = new ReplacementPath[0];
public override void ApplyModification(AssemblyDefinition assembly)
{
TypeReference stringRef = assembly.MainModule.TypeSystem.String;
TypeReference intRef = assembly.MainModule.TypeSystem.Int32;
if (stringRef == null || intRef == null) return;
foreach (ReplacementPath replacementPath in ReplacementPaths)
{
TypeReference type = assembly.MainModule.GetType(replacementPath.ScriptableObjectName);
if (type == null) continue;
TypeDefinition definition = type.Resolve();
CustomAttribute createMenuAttribute = GetCreateAssetMenuAttribute(definition);
if (createMenuAttribute == null)
{
Debug.LogWarning("Could not get CreateAssetMenuAttribute for scriptable object: " + replacementPath.ScriptableObjectName);
continue;
}
CustomAttributeArgument pathArgumentValue = new CustomAttributeArgument(stringRef, replacementPath.NewPath);
CustomAttributeArgument fileNameArgumentValue = new CustomAttributeArgument(stringRef, replacementPath.NewDefaultName);
CustomAttributeArgument orderArgumentValue = new CustomAttributeArgument(intRef, replacementPath.NewOrder);
CustomAttributeNamedArgument pathArgument = new CustomAttributeNamedArgument("menuName", pathArgumentValue);
CustomAttributeNamedArgument fileNameArgument = new CustomAttributeNamedArgument("fileName", fileNameArgumentValue);
CustomAttributeNamedArgument orderArgument = new CustomAttributeNamedArgument("order", orderArgumentValue);
createMenuAttribute.Properties.Clear();
createMenuAttribute.Properties.Add(pathArgument);
createMenuAttribute.Properties.Add(fileNameArgument);
createMenuAttribute.Properties.Add(orderArgument);
}
Applied = true;
}
private CustomAttribute GetCreateAssetMenuAttribute(TypeDefinition definition)
{
CustomAttribute[] foundAttributes = definition.CustomAttributes.Where(ca => ca.AttributeType.FullName.Contains("CreateAssetMenuAttribute")).ToArray();
if(foundAttributes.Length > 0)
{
return foundAttributes[0];
}
return null;
}
[Serializable]
public struct ReplacementPath
{
[Tooltip("Specify the FULL NAME of the scriptable object you wish to modify. e.g. Sub.Namespace.Type")]
public string ScriptableObjectName;
[Tooltip("The new create asset path of the scriptable object")]
public string NewPath;
[Tooltip("The new default name of the scriptable object when created")]
public string NewDefaultName;
[Tooltip("The new ordering of the scriptable object in menu")]
public int NewOrder;
}
}
}
@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 80429e2d9786fda44b01ab04cadd4b75
timeCreated: 1641758895
guid: 6389bd26f6b33074ba8afe182d11c33d
timeCreated: 1649523850
licenseType: Free
MonoImporter:
serializedVersion: 2
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using Mono.Cecil;
using UnityEngine;
@@ -18,8 +19,28 @@ namespace MeatKit
public override void ApplyModification(AssemblyDefinition assembly)
{
// Try to get this type from the assembly. If it doesn't exist, we can just skip.
TypeReference type = assembly.MainModule.GetType(EnumName);
// Try to get the enum type. If it contains a '+' in the name, it's nested and we have to do a bit of extra stuff
TypeDefinition type;
if (EnumName.Contains("+"))
{
string[] parts = EnumName.Split('+');
type = assembly.MainModule.GetType(parts[0]);
if (type != null)
{
for (int i = 1; i < parts.Length; i++)
{
Debug.Log(type);
type = type.NestedTypes.FirstOrDefault(x => x.Name == parts[i]);
if (type == null) break;
}
}
}
// Otherwise we can just grab it directly if it isn't nested
else type = assembly.MainModule.GetType(EnumName);
// If we can't find the type, skip.
if (type == null) return;
var definition = type.Resolve();
+11 -2
View File
@@ -1,3 +1,12 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 486e27304e8449efb6c6136482952c4d
timeCreated: 1628213734
timeCreated: 1649523858
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -12,8 +12,10 @@ namespace MeatKit
"FistVR.FireArmRoundType",
"FistVR.FireArmRoundClass",
"FistVR.FireArmMagazineType",
"FistVR.ItemSpawnerObjectDefinition.ItemSpawnerCategory",
"FistVR.SosigEnemyID"
"FistVR.ItemSpawnerObjectDefinition+ItemSpawnerCategory",
"FistVR.SosigEnemyID",
"FistVR.FVRFireArmAttachementMountType",
"FistVR.FireArmClipType"
};
private SerializedProperty _addedValues;
@@ -1,3 +1,12 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 4980597d341c4eed913ae30680f3f9f3
timeCreated: 1628218472
timeCreated: 1649523860
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+80 -37
View File
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -14,6 +14,8 @@ namespace MeatKit
{
public static void DoBuild()
{
BuildLog.StartNew();
try
{
DoBuildInternal();
@@ -23,13 +25,17 @@ namespace MeatKit
string message = e.Message;
if (e.InnerException != null) message += "\n\n" + e.InnerException.Message;
EditorUtility.DisplayDialog("Build failed", message, "Ok.");
BuildLog.SetCompletionStatus(true, "MeatKit Build Exception", e);
}
catch (Exception e)
{
EditorUtility.DisplayDialog("Build failed with unknown error",
"Error message: " + e.Message + "\n\nCheck console for full exception text.", "Ok.");
Debug.LogException(e);
BuildLog.SetCompletionStatus(true, "Unexpected exception during build", e);
}
BuildLog.Finish();
}
private static void DoBuildInternal()
@@ -41,6 +47,8 @@ namespace MeatKit
BuildProfile profile = BuildWindow.SelectedProfile;
if (!profile) return;
string bundleOutputPath = profile.ExportPath;
// Start a stopwatch to time the build
Stopwatch sw = Stopwatch.StartNew();
@@ -48,39 +56,66 @@ namespace MeatKit
if (!profile.EnsureValidForEditor()) return;
// Clean the output folder
CleanBuild();
BuildLog.WriteLine("Cleaning build folder");
CleanBuild(profile);
// And export the assembly to the folder
ExportEditorAssembly(BundleOutputPath);
// Then get their asset bundle configurations
var bundles = profile.BuildItems.SelectMany(x => x.ConfigureBuild()).ToArray();
BuildPipeline.BuildAssetBundles(BundleOutputPath, bundles, BuildAssetBundleOptions.None,
BuildTarget.StandaloneWindows64);
// Cleanup the unused files created with building the bundles
foreach (var file in Directory.GetFiles(BundleOutputPath, "*.manifest"))
File.Delete(file);
File.Delete(Path.Combine(BundleOutputPath, "AssetBundles"));
// With the bundles done building we can process them
// Make a copy of the editor assembly because when we build an asset bundle, Unity will delete it
string editorAssembly = EditorAssemblyPath + AssemblyName + ".dll";
string tempAssemblyFile = Path.GetTempFileName();
BuildLog.WriteLine("Copying editor assembly: " + editorAssembly + " -> " + tempAssemblyFile);
File.Copy(editorAssembly, tempAssemblyFile, true);
// Make sure we have the virtual reality supported checkbox enabled
// If this is not set to true when we build our asset bundles, the shaders will not compile correctly
BuildLog.WriteLine("Forcing VR support on");
bool wasVirtualRealitySupported = PlayerSettings.virtualRealitySupported;
PlayerSettings.virtualRealitySupported = true;
// Create a map of assembly names to what we want to rename them to, then enable bundle processing
var replaceMap = new Dictionary<string, string>
{
{"Assembly-CSharp.dll", profile.PackageName + ".dll"},
{"Assembly-CSharp-firstpass.dll", profile.PackageName + "-firstpass.dll"},
{"H3VRCode-CSharp.dll", "Assembly-CSharp.dll"},
{"H3VRCode-CSharp-firstpass.dll", "Assembly-CSharp-firstpass.dll"}
{AssemblyName + ".dll", profile.PackageName + ".dll"},
{AssemblyFirstpassName + ".dll", profile.PackageName + "-firstpass.dll"},
{AssemblyRename + ".dll", AssemblyName + ".dll"},
{AssemblyFirstpassRename + ".dll", AssemblyFirstpassName + ".dll"}
};
BuildLog.WriteLine("Enabling bundle processing.");
BuildLog.WriteLine("Replace map:");
foreach (var key in replaceMap.Keys)
BuildLog.WriteLine(" " + key + " -> " + replaceMap[key]);
BuildLog.WriteLine("Ignored types (Assembly-CSharp.dll):");
foreach (var type in StripAssemblyTypes)
BuildLog.WriteLine(" " + type);
AssetBundleIO.EnableProcessing(replaceMap, false, true);
foreach (var bundle in bundles)
{
var path = Path.Combine(BundleOutputPath, bundle.assetBundleName);
ProcessBundle(path, path, replaceMap, profile.BundleCompressionType);
}
// Get the list of asset bundle configurations and build them
BuildLog.WriteLine("Collecting bundles from build items");
var bundles = profile.BuildItems.SelectMany(x => x.ConfigureBuild()).ToArray();
BuildLog.WriteLine(bundles.Length + " bundles to build. Building bundles.");
BuildPipeline.BuildAssetBundles(bundleOutputPath, bundles, BuildAssetBundleOptions.ChunkBasedCompression,
BuildTarget.StandaloneWindows64);
// Disable bundle processing now that we're done with it.
AssetBundleIO.DisableProcessing();
var requiredScripts = AssetBundleIO.SerializedScriptNames;
BuildLog.WriteLine("Bundles built");
// Cleanup the unused files created with building the bundles
BuildLog.WriteLine("Cleaning unused files");
foreach (var file in Directory.GetFiles(bundleOutputPath, "*.manifest"))
File.Delete(file);
File.Delete(Path.Combine(bundleOutputPath, profile.Version));
// Reset the virtual reality supported checkbox, so if the user had it disabled it will stay disabled
PlayerSettings.virtualRealitySupported = wasVirtualRealitySupported;
// And export the assembly to the folder
BuildLog.WriteLine("Exporting editor assembly");
ExportEditorAssembly(bundleOutputPath, tempAssemblyFile, requiredScripts);
// Now we can write the Thunderstore stuff to the folder
profile.WriteThunderstoreManifest(BundleOutputPath + "manifest.json");
BuildLog.WriteLine("Writing Thunderstore manifest");
profile.WriteThunderstoreManifest(bundleOutputPath + "manifest.json");
// Check if the icon is already 256x256
Texture2D icon = profile.Icon;
@@ -90,6 +125,7 @@ namespace MeatKit
if (!importSettings.isReadable ||
importSettings.textureCompression != TextureImporterCompression.Uncompressed)
{
BuildLog.WriteLine("Fixing icon import settings");
importSettings.isReadable = true;
importSettings.textureCompression = TextureImporterCompression.Uncompressed;
importSettings.SaveAndReimport();
@@ -98,41 +134,48 @@ namespace MeatKit
if (profile.Icon.width != 256 || profile.Icon.height != 256)
{
// Resize it for the build
BuildLog.WriteLine("Icon was not 256x256, resizing");
icon = icon.ScaleTexture(256, 256);
}
// Write the texture to file
File.WriteAllBytes(BundleOutputPath + "icon.png", icon.EncodeToPNG());
BuildLog.WriteLine("Saving icon");
File.WriteAllBytes(bundleOutputPath + "icon.png", icon.EncodeToPNG());
// Copy the readme
File.Copy(AssetDatabase.GetAssetPath(profile.ReadMe), BundleOutputPath + "README.md");
BuildLog.WriteLine("Copying readme");
File.Copy(AssetDatabase.GetAssetPath(profile.ReadMe), bundleOutputPath + "README.md");
string packageName = profile.Author + "-" + profile.PackageName;
if (profile.BuildAction == BuildAction.CopyToProfile)
{
BuildLog.WriteLine("Copying built files to profile");
string pluginFolder = Path.Combine(profile.OutputProfile, "BepInEx/plugins/" + packageName);
if (Directory.Exists(pluginFolder)) Directory.Delete(pluginFolder, true);
Directory.CreateDirectory(pluginFolder);
Extensions.CopyFilesRecursively(BundleOutputPath, pluginFolder);
Extensions.CopyFilesRecursively(bundleOutputPath, pluginFolder);
}
else if (profile.BuildAction == BuildAction.CreateThunderstorePackage)
{
BuildLog.WriteLine("Zipping built files");
using (var zip = new ZipFile())
{
zip.AddDirectory(BundleOutputPath, "");
zip.Save(Path.Combine(BundleOutputPath, packageName + ".zip"));
zip.AddDirectory(bundleOutputPath, "");
zip.Save(Path.Combine(bundleOutputPath, packageName + "-" + profile.Version + ".zip"));
}
}
// End the stopwatch and save the time
BuildLog.SetCompletionStatus(false, "", null);
MeatKitCache.LastBuildDuration = sw.Elapsed;
MeatKitCache.LastBuildTime = DateTime.Now;
}
public static void CleanBuild()
public static void CleanBuild(BuildProfile profile)
{
if (Directory.Exists(BundleOutputPath)) Directory.Delete(BundleOutputPath, true);
Directory.CreateDirectory(BundleOutputPath);
string outputPath = profile.ExportPath;
if (Directory.Exists(outputPath)) Directory.Delete(outputPath, true);
Directory.CreateDirectory(outputPath);
}
}
}
}
@@ -1,12 +1,12 @@
fileFormatVersion: 2
guid: d18106ea7c52411db45cabd362f21f16
timeCreated: 1640061580
licenseType: Pro
timeCreated: 1649523901
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 151c1f5398ee70041a49c417b23f1846, type: 3}
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,12 +1,12 @@
fileFormatVersion: 2
guid: f6d6db4144b34551885c304840edfb62
timeCreated: 1640061353
licenseType: Pro
timeCreated: 1649523904
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 6fae6dfd178cd184180013acef55632c, type: 3}
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,100 @@
using System;
using System.Diagnostics;
using System.IO;
namespace MeatKit
{
public static class BuildLog
{
private static StringWriter _temp;
private static Stopwatch _sw;
private static DateTime _startTime;
private static bool _failed;
private static string _completionMessage;
private static Exception _exception;
public static void StartNew()
{
_temp = new StringWriter();
_sw = Stopwatch.StartNew();
_startTime = DateTime.Now;
}
public static void WriteLine(string text)
{
if (_temp == null) return;
_temp.WriteLine(text);
}
public static void SetCompletionStatus(bool failed, string message, Exception exception)
{
_failed = failed;
_completionMessage = message;
_exception = exception;
}
public static void Finish()
{
_sw.Stop();
StreamWriter output = new StreamWriter("AssetBundles/buildlog.txt", false);
WriteProfileInfo(output);
output.WriteLine();
output.WriteLine("--- MeatKit Build Log ---");
output.WriteLine("Start Time: " + _startTime.ToString("dddd, dd MMMM yyyy HH:mm:ssK"));
output.WriteLine("Duration : " + _sw.Elapsed.GetReadableTimespan());
output.WriteLine("Status : " + (_failed ? "FAILED" : "COMPLETED"));
if (!string.IsNullOrEmpty(_completionMessage))
output.WriteLine("Message : " + _completionMessage);
if (_exception != null)
{
output.WriteLine("Exception :");
output.WriteLine(_exception.ToString());
}
output.WriteLine("\n--- Full build log ---");
output.Write(_temp.ToString());
output.Close();
output.Dispose();
_temp = null;
}
private static void WriteProfileInfo(StreamWriter output)
{
var profile = BuildWindow.SelectedProfile;
var implicitDependencies = profile.GetRequiredDependencies();
output.WriteLine("--- Selected Build Profile ---");
output.WriteLine("Thunderstore Metadata");
output.WriteLine(" Package Name: " + profile.PackageName);
output.WriteLine(" Author : " + profile.Author);
output.WriteLine(" Version : " + profile.Version);
output.WriteLine(" Icon Set : " + (profile.Icon == null ? "No" : "Yes"));
output.WriteLine(" Readme Set : " + (profile.ReadMe == null ? "No" : "Yes"));
output.WriteLine(" Website URL : " + profile.WebsiteURL);
output.WriteLine(" Description : " + profile.Description);
output.WriteLine(" Implicit Dependencies : (" + implicitDependencies.Length + ")");
foreach (var dependency in implicitDependencies)
output.WriteLine(" " + dependency);
output.WriteLine(" Additional Dependencies: (" + profile.AdditionalDependencies.Length + ")");
foreach (var dependency in profile.AdditionalDependencies)
output.WriteLine(" " + dependency);
output.WriteLine("Script Options");
output.WriteLine(" Strip Namespaces : " + profile.StripNamespaces);
output.WriteLine(" Additional Namespaces: (" + profile.AdditionalNamespaces.Length + ")");
foreach (var @namespace in profile.AdditionalNamespaces)
output.WriteLine(" " + @namespace);
output.WriteLine(" Apply Harmony Patches: " + profile.ApplyHarmonyPatches);
output.WriteLine("Export Options");
output.WriteLine(" Build Items: (" + profile.BuildItems.Length + ")");
foreach (var buildItem in profile.BuildItems)
output.WriteLine(" " + buildItem);
output.WriteLine(" Build Action: " + profile.BuildAction);
output.WriteLine(" Export Path : " + profile.ExportPath);
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f474df2cd776465d8cc9d2f7f52f77c7
timeCreated: 1664853706
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using AssetsTools.NET;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -18,6 +17,8 @@ namespace MeatKit
[CreateAssetMenu(menuName = "MeatKit/Build Profile")]
public class BuildProfile : ScriptableObject, IValidatable
{
private const string BaseOutputPath = "AssetBundles/";
[Header("Thunderstore Metadata")]
public string PackageName = "";
public string Author = "";
@@ -31,10 +32,10 @@ namespace MeatKit
[Header("Script Options")]
public bool StripNamespaces = true;
public string[] AdditionalNamespaces = new string[0];
public bool ApplyHarmonyPatches = true;
[Header("Export Options")]
public BuildItem[] BuildItems = new BuildItem[0];
public AssetBundleCompressionType BundleCompressionType = AssetBundleCompressionType.LZ4;
public BuildAction BuildAction = BuildAction.JustBuildFiles;
[HideInInspector]
@@ -49,6 +50,11 @@ namespace MeatKit
messages["PackageName"] =
BuildMessage.Error("Package name can only contain letters, numbers, and underscores.");
// Author needs to match regex
if (!Regex.IsMatch(Author, @"^[a-zA-Z_0-9]+$"))
messages["Author"] =
BuildMessage.Error("Author can only contain letters, numbers, and underscores.");
// Make sure the version number is a valid x.x.x
if (!Regex.IsMatch(Version, @"^\d+\.\d+\.\d+$"))
messages["Version"] = BuildMessage.Error("Version number must be in format 'x.x.x'.");
@@ -65,18 +71,8 @@ namespace MeatKit
if (!ReadMe)
messages["ReadMe"] = BuildMessage.Error("Missing readme.");
switch (BundleCompressionType)
{
case AssetBundleCompressionType.NONE:
messages["BundleCompressionType"] = BuildMessage.Warning(
"Uncompressed bundles are not recommended for publication. They can and will be very large.");
break;
case AssetBundleCompressionType.LZMA:
messages["BundleCompressionType"] = BuildMessage.Info(
"LZMA can take longer to compress than LZ4, however it will result in smaller file sizes usually.");
break;
}
else if (!AssetDatabase.GetAssetPath(ReadMe).EndsWith(".md", StringComparison.InvariantCultureIgnoreCase))
messages["ReadMe"] = BuildMessage.Warning("Are you sure this is a Markdown file? It doesn't have the .md file extension.");
switch (BuildAction)
{
@@ -109,11 +105,32 @@ namespace MeatKit
public bool EnsureValidForEditor()
{
// Go over each build item
BuildLog.WriteLine("Starting build profile check...");
// Check ourselves
bool hasErrors = false, hasWarnings = false;
foreach (var item in BuildItems)
// Check if it has any validation messages
foreach (var message in Validate().Values)
{
// Log them
switch (message.Type)
{
case MessageType.Error:
Debug.LogError(AssetDatabase.GetAssetPath(this) + ": " + message.Message);
hasErrors = true;
break;
case MessageType.Warning:
Debug.LogWarning(AssetDatabase.GetAssetPath(this) + ": " + message.Message);
hasWarnings = true;
break;
}
BuildLog.WriteLine(" " + message.Type + ": " + this + ": " + message.Message);
}
// Go over each build item and check for any validation messages
foreach (var item in BuildItems.Where(x => x != null))
foreach (var message in item.Validate().Values)
{
// Log them
switch (message.Type)
{
@@ -125,45 +142,54 @@ namespace MeatKit
Debug.LogWarning(AssetDatabase.GetAssetPath(item) + ": " + message.Message);
hasWarnings = true;
break;
case MessageType.Info:
Debug.Log(AssetDatabase.GetAssetPath(item) + ": " + message.Message);
break;
default:
throw new ArgumentOutOfRangeException();
}
BuildLog.WriteLine(" " + message.Type + ": " + item + ": " + message.Message);
}
// If there's errors don't let anything continue
if (hasErrors)
{
EditorUtility.DisplayDialog("Build errors",
"There were errors validating your build items. Please check the console for more info.", "Ok.");
BuildLog.SetCompletionStatus(true, "Build profile failed one or more checks", null);
return false;
}
// If there's only warnings, let the user decide if they want to continue
if (hasWarnings)
return EditorUtility.DisplayDialog("Build warnings",
{
var continueAnyway = EditorUtility.DisplayDialog("Build warnings",
"Some build items validated with warnings. Continue with build anyway?", "Yes", "No");
// Otherwise continue
return true;
BuildLog.WriteLine("Build profile has one or more warnings.");
BuildLog.WriteLine(" Continue anyway? " + continueAnyway);
BuildLog.SetCompletionStatus(true, "User canceled build", null);
return continueAnyway;
}
else
{
// Otherwise continue
BuildLog.WriteLine(" Build profile passed all checks!");
return true;
}
}
public string[] GetRequiredDependencies()
{
return BuildItems
.Where(x => x != null)
.SelectMany(x => x.RequiredDependencies).ToArray();
.SelectMany(x => x.RequiredDependencies)
.Distinct().ToArray();
}
public string MainNamespace
{
get
{
return Author + "." + PackageName;
}
get { return Author + "." + PackageName; }
}
public string[] GetRequiredNamespaces()
{
return new[] {MainNamespace};
@@ -173,7 +199,12 @@ namespace MeatKit
{
return GetRequiredNamespaces().Concat(AdditionalNamespaces).ToArray();
}
public string ExportPath
{
get { return Path.Combine(BaseOutputPath, Path.Combine(PackageName, Version)) + Path.DirectorySeparatorChar; }
}
public void WriteThunderstoreManifest(string location)
{
#if H3VR_IMPORTED
@@ -187,7 +218,7 @@ namespace MeatKit
// ReSharper disable once CoVariantArrayConversion
obj["dependencies"] = new JArray(GetRequiredDependencies().Concat(AdditionalDependencies).ToArray());
File.WriteAllText(location, JsonConvert.SerializeObject(obj));
File.WriteAllText(location, JsonConvert.SerializeObject(obj,Formatting.Indented));
#endif
}
}
@@ -198,4 +229,4 @@ namespace MeatKit
CopyToProfile,
CreateThunderstorePackage
}
}
}
+13 -2
View File
@@ -1,3 +1,14 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: afed54a239594b8abd631a8047a54987
timeCreated: 1635004125
timeCreated: 1649524426
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences:
- Icon: {instanceID: 0}
- ReadMe: {instanceID: 0}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -4,9 +4,12 @@ namespace MeatKit
{
public class MeatKitBuildException : Exception
{
public MeatKitBuildException(string message) : base(message)
{
}
public MeatKitBuildException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
-85
View File
@@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using AssetsTools.NET;
using AssetsTools.NET.Extra;
using UnityEditor;
namespace MeatKit
{
public static partial class MeatKit
{
private static void ProcessBundle(string source, string destination, IDictionary<string, string> replaceMap,
AssetBundleCompressionType recompressAs)
{
try
{
// Step 1: Load the asset bundle.
EditorUtility.DisplayProgressBar("Processing bundle", "Loading asset bundle...", 0f);
var am = new AssetsManager();
var bundle = am.LoadBundleFile(source);
var assets = am.LoadAssetsFileFromBundle(bundle, 0);
// Step 2: For each MonoScript asset, alter it's assembly name
EditorUtility.DisplayProgressBar("Processing bundle", "Modifying assets...", 0.33f);
var modifications = new List<AssetsReplacer>();
foreach (AssetFileInfoEx assetInfo in assets.table.assetFileInfo)
{
// We only want MonoScripts (type 115)
if (assetInfo.curFileType != 115) continue;
// Get the field for this asset
var field = am.GetTypeInstance(assets, assetInfo).GetBaseField();
var assemblyNameValue = field["m_AssemblyName"].GetValue();
// Check if we want to replace this name
var asmName = assemblyNameValue.AsString();
if (replaceMap.ContainsKey(asmName))
{
// Modify it's assembly name
assemblyNameValue.Set(replaceMap[asmName]);
// Write the modifications to the list
var newBytes = field.WriteToByteArray();
modifications.Add(new AssetsReplacerFromMemory(0, assetInfo.index, (int) assetInfo.curFileType,
0xFFFF, newBytes));
}
}
// Step 3: Write the modified assets back into an uncompressed bundle
EditorUtility.DisplayProgressBar("Processing bundle", "Saving changes...", 0.66f);
using (var fileStream = new FileStream(destination + ".uncompressed", FileMode.Create))
{
var bunRepl = new BundleReplacerFromAssets(assets.name, assets.name, assets.file, modifications);
var bunWriter = new AssetsFileWriter(fileStream);
bundle.file.Write(bunWriter, new List<BundleReplacer> {bunRepl});
}
// Unload the existing bundle
am.UnloadAll();
// Step 4: Re-compress the bundle if requested
EditorUtility.DisplayProgressBar("Processing bundle", "Recompressing bundle...", 1f);
if (recompressAs != AssetBundleCompressionType.NONE)
{
var compressedBundle = am.LoadBundleFile(destination + ".uncompressed");
using (var fs = File.OpenWrite(destination))
using (var writer = new AssetsFileWriter(fs))
{
compressedBundle.file.Pack(compressedBundle.file.reader, writer, recompressAs);
}
am.UnloadAll();
File.Delete(destination + ".uncompressed");
}
else File.Move(destination + ".uncompressed", destination);
}
finally
{
EditorUtility.ClearProgressBar();
GC.Collect();
}
}
}
}
-3
View File
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 69efae90f6bb4c3eadcd9e7c4af6ec67
timeCreated: 1617337071
@@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: c7a0d66f64ea9324e9fcfe43a9f69c4e
guid: 0b75c98df00b4b55b3642b3aed976883
folderAsset: yes
timeCreated: 1638903534
licenseType: Pro
timeCreated: 1655428806
DefaultImporter:
userData:
assetBundleName:
@@ -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;
}
}
}
}
@@ -17,13 +17,13 @@ namespace MeatKit
/// </summary>
public static partial class MeatKit
{
private const string AssemblyName = "Assembly-CSharp";
private const string AssemblyRename = "H3VRCode-CSharp";
private const string AssemblyFirstpassName = "Assembly-CSharp-firstpass";
private const string AssemblyFirstpassRename = "H3VRCode-CSharp-passfirst";
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
private static readonly string[] StripAssemblyTypes =
public static readonly string[] StripAssemblyTypes =
{
// Alloy classes
"MaterialMapChannelPackerDefinition",
@@ -139,6 +139,9 @@ namespace MeatKit
// 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"));
}
@@ -169,23 +172,53 @@ namespace MeatKit
new RedirectedAssemblyResolver(Path.GetDirectoryName(assemblyPath), destinationDirectory)
};
// We just want to rename the references to the game's assemblies here
// 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)
switch (reference.Name)
{
if (reference.Name.Contains("Assembly-CSharp"))
{
case AssemblyName:
reference.Name = AssemblyRename;
break;
case AssemblyFirstpassName:
reference.Name = AssemblyFirstpassRename;
break;
reference.Name = reference.Name.Replace("Assembly-CSharp", "H3VRCode-CSharp");
}
}
asm.Write(Path.Combine(destinationDirectory, Path.GetFileName(assemblyPath)));
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
@@ -241,7 +274,6 @@ namespace MeatKit
try
{
var asmPath = Path.Combine(path, name.Name + ".dll");
Debug.Log("Assembly path: " + asmPath);
if (File.Exists(asmPath))
asm = AssemblyDefinition.ReadAssembly(asmPath,
new ReaderParameters {AssemblyResolver = this});
@@ -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
+30 -38
View File
@@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.IO;
using AssetsTools.NET;
using UnityEditor;
using UnityEngine;
using Debug = UnityEngine.Debug;
@@ -9,7 +7,7 @@ namespace MeatKit
{
public static partial class MeatKit
{
private static readonly string ManagedDirectory = Path.Combine(Application.dataPath, "MeatKit/Managed/");
private static readonly string ManagedDirectory = Path.Combine(Application.dataPath, "Managed/");
private static bool ShowErrorIfH3VRNotImported()
{
@@ -28,13 +26,35 @@ namespace MeatKit
var gameManagedLocation = MeatKitCache.GameManagedLocation;
if (string.IsNullOrEmpty(gameManagedLocation) || !Directory.Exists(gameManagedLocation))
{
gameManagedLocation = EditorUtility.OpenFolderPanel("Select H3VR Managed directory", string.Empty, "Managed");
MeatKitCache.GameManagedLocation = gameManagedLocation;
// Cache wasn't set or directory doesn't exist. Lets see if we can find it automatically via Steam
gameManagedLocation = SteamAppLocator.LocateGame();
if (string.IsNullOrEmpty(gameManagedLocation))
{
// Still nope. Ask the user for it directly.
gameManagedLocation =
EditorUtility.OpenFolderPanel("Select H3VR Managed directory", string.Empty, "Managed");
}
else gameManagedLocation = Path.Combine(gameManagedLocation, "h3vr_Data/Managed");
}
// If it's _still_ empty, the user must have cancelled.
// If it's _still_ empty, the user must have cancelled the input prompt, so cancel the import.
if (string.IsNullOrEmpty(gameManagedLocation)) return;
// Also, check if the path is even valid
if (!File.Exists(Path.Combine(gameManagedLocation, "Assembly-CSharp.dll")))
{
EditorUtility.DisplayDialog("Error",
"Looks like the path you selected is invalid. Make sure you are selecting the h3vr_Data/Managed folder in the game directory.",
"Ok");
return;
}
// Import the assemblies and update the cache so we can find it in the future
ImportAssemblies(gameManagedLocation, ManagedDirectory);
MeatKitCache.GameManagedLocation = gameManagedLocation;
// Let the user know we've completed the action
EditorUtility.DisplayDialog("Success", "Game scripts imported", "Ok");
}
[MenuItem("MeatKit/Scripts/Import Single", priority = 0)]
@@ -66,38 +86,10 @@ namespace MeatKit
{
// Make sure the scripts are imported and there are no errors before exporting
if (ShowErrorIfH3VRNotImported()) return;
if (!BuildWindow.SelectedProfile) return;
if (!BuildWindow.SelectedProfile.EnsureValidForEditor()) return;
ExportEditorAssembly(BundleOutputPath);
}
[MenuItem("MeatKit/Asset Bundle/Export", priority = 1)]
public static void ExportBundle()
{
var assetBundlePath = EditorUtility.OpenFilePanel("Select asset bundle", Application.dataPath, "");
var settings = BuildWindow.SelectedProfile;
var replaceMap = new Dictionary<string, string>
{
{"Assembly-CSharp.dll", settings.PackageName + ".dll"},
{"Assembly-CSharp-firstpass.dll", settings.PackageName + "-firstpass.dll"},
{"H3VRCode-CSharp.dll", "Assembly-CSharp.dll"},
{"H3VRCode-CSharp-firstpass.dll", "Assembly-CSharp-firstpass.dll"}
};
ProcessBundle(assetBundlePath, assetBundlePath, replaceMap, AssetBundleCompressionType.LZ4);
}
[MenuItem("MeatKit/Asset Bundle/Import", priority = 1)]
public static void ImportBundle()
{
var assetBundlePath = EditorUtility.OpenFilePanel("Select asset bundle", Application.dataPath, "");
var replaceMap = new Dictionary<string, string>
{
{"Assembly-CSharp.dll", "H3VRCode-CSharp.dll"},
{"Assembly-CSharp-firstpass.dll", "H3VRCode-CSharp-firstpass.dll"}
};
ProcessBundle(assetBundlePath, assetBundlePath + "-imported", replaceMap, AssetBundleCompressionType.NONE);
ExportEditorAssembly(BuildWindow.SelectedProfile.ExportPath);
}
public static void ClearCache()
@@ -110,4 +102,4 @@ namespace MeatKit
AssetDatabase.Refresh();
}
}
}
}
+13
View File
@@ -25,6 +25,9 @@ namespace MeatKit
[SerializeField]
private string _lastSelectedProfileGuid;
[SerializeField]
private string _lastUpdateCheckTime = default(DateTime).ToString(CultureInfo.InvariantCulture);
private static string CacheFilePath
{
@@ -108,5 +111,15 @@ namespace MeatKit
WriteCache();
}
}
public static DateTime LastUpdateCheckTime
{
get { return DateTime.Parse(Instance._lastUpdateCheckTime); }
set
{
Instance._lastUpdateCheckTime = value.ToString(CultureInfo.InvariantCulture);
WriteCache();
}
}
}
}
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: c302b95892ac1244bbc2d7eb2a4584a2
guid: e6ff8168d990b424b85c55e8aa09801f
folderAsset: yes
timeCreated: 1640060210
timeCreated: 1634920921
licenseType: Pro
DefaultImporter:
userData:
@@ -0,0 +1,258 @@
using UnityEngine;
using UnityEngine.AI;
namespace UnityEditor.AI
{
public static class NavMeshComponentsGUIUtility
{
public static void AreaPopup(string labelName, SerializedProperty areaProperty)
{
var areaIndex = -1;
var areaNames = GameObjectUtility.GetNavMeshAreaNames();
for (var i = 0; i < areaNames.Length; i++)
{
var areaValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[i]);
if (areaValue == areaProperty.intValue)
areaIndex = i;
}
ArrayUtility.Add(ref areaNames, "");
ArrayUtility.Add(ref areaNames, "Open Area Settings...");
var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
EditorGUI.BeginProperty(rect, GUIContent.none, areaProperty);
EditorGUI.BeginChangeCheck();
areaIndex = EditorGUI.Popup(rect, labelName, areaIndex, areaNames);
if (EditorGUI.EndChangeCheck())
{
if (areaIndex >= 0 && areaIndex < areaNames.Length - 2)
areaProperty.intValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[areaIndex]);
else if (areaIndex == areaNames.Length - 1)
NavMeshEditorHelpers.OpenAreaSettings();
}
EditorGUI.EndProperty();
}
public static void AgentTypePopup(string labelName, SerializedProperty agentTypeID)
{
var index = -1;
var count = NavMesh.GetSettingsCount();
var agentTypeNames = new string[count + 2];
for (var i = 0; i < count; i++)
{
var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
var name = NavMesh.GetSettingsNameFromID(id);
agentTypeNames[i] = name;
if (id == agentTypeID.intValue)
index = i;
}
agentTypeNames[count] = "";
agentTypeNames[count + 1] = "Open Agent Settings...";
bool validAgentType = index != -1;
if (!validAgentType)
{
EditorGUILayout.HelpBox("Agent Type invalid.", MessageType.Warning);
}
var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
EditorGUI.BeginProperty(rect, GUIContent.none, agentTypeID);
EditorGUI.BeginChangeCheck();
index = EditorGUI.Popup(rect, labelName, index, agentTypeNames);
if (EditorGUI.EndChangeCheck())
{
if (index >= 0 && index < count)
{
var id = NavMesh.GetSettingsByIndex(index).agentTypeID;
agentTypeID.intValue = id;
}
else if (index == count + 1)
{
NavMeshEditorHelpers.OpenAgentSettings(-1);
}
}
EditorGUI.EndProperty();
}
// Agent mask is a set (internally array/list) of agentTypeIDs.
// It is used to describe which agents modifiers apply to.
// There is a special case of "None" which is an empty array.
// There is a special case of "All" which is an array of length 1, and value of -1.
public static void AgentMaskPopup(string labelName, SerializedProperty agentMask)
{
// Contents of the dropdown box.
string popupContent = "";
if (agentMask.hasMultipleDifferentValues)
popupContent = "\u2014";
else
popupContent = GetAgentMaskLabelName(agentMask);
var content = new GUIContent(popupContent);
var popupRect = GUILayoutUtility.GetRect(content, EditorStyles.popup);
EditorGUI.BeginProperty(popupRect, GUIContent.none, agentMask);
popupRect = EditorGUI.PrefixLabel(popupRect, 0, new GUIContent(labelName));
bool pressed = GUI.Button(popupRect, content, EditorStyles.popup);
if (pressed)
{
var show = !agentMask.hasMultipleDifferentValues;
var showNone = show && agentMask.arraySize == 0;
var showAll = show && IsAll(agentMask);
var menu = new GenericMenu();
menu.AddItem(new GUIContent("None"), showNone, SetAgentMaskNone, agentMask);
menu.AddItem(new GUIContent("All"), showAll, SetAgentMaskAll, agentMask);
menu.AddSeparator("");
var count = NavMesh.GetSettingsCount();
for (var i = 0; i < count; i++)
{
var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
var sname = NavMesh.GetSettingsNameFromID(id);
var showSelected = show && AgentMaskHasSelectedAgentTypeID(agentMask, id);
var userData = new object[] { agentMask, id, !showSelected };
menu.AddItem(new GUIContent(sname), showSelected, ToggleAgentMaskItem, userData);
}
menu.DropDown(popupRect);
}
EditorGUI.EndProperty();
}
public static GameObject CreateAndSelectGameObject(string suggestedName, GameObject parent)
{
var parentTransform = parent != null ? parent.transform : null;
var uniqueName = GameObjectUtility.GetUniqueNameForSibling(parentTransform, suggestedName);
var child = new GameObject(uniqueName);
Undo.RegisterCreatedObjectUndo(child, "Create " + uniqueName);
if (parentTransform != null)
Undo.SetTransformParent(child.transform, parentTransform, "Parent " + uniqueName);
Selection.activeGameObject = child;
return child;
}
static bool IsAll(SerializedProperty agentMask)
{
return agentMask.arraySize == 1 && agentMask.GetArrayElementAtIndex(0).intValue == -1;
}
static void ToggleAgentMaskItem(object userData)
{
var args = (object[])userData;
var agentMask = (SerializedProperty)args[0];
var agentTypeID = (int)args[1];
var value = (bool)args[2];
ToggleAgentMaskItem(agentMask, agentTypeID, value);
}
static void ToggleAgentMaskItem(SerializedProperty agentMask, int agentTypeID, bool value)
{
if (agentMask.hasMultipleDifferentValues)
{
agentMask.ClearArray();
agentMask.serializedObject.ApplyModifiedProperties();
}
// Find which index this agent type is in the agentMask array.
int idx = -1;
for (var j = 0; j < agentMask.arraySize; j++)
{
var elem = agentMask.GetArrayElementAtIndex(j);
if (elem.intValue == agentTypeID)
idx = j;
}
// Handle "All" special case.
if (IsAll(agentMask))
{
agentMask.DeleteArrayElementAtIndex(0);
}
// Toggle value.
if (value)
{
if (idx == -1)
{
agentMask.InsertArrayElementAtIndex(agentMask.arraySize);
agentMask.GetArrayElementAtIndex(agentMask.arraySize - 1).intValue = agentTypeID;
}
}
else
{
if (idx != -1)
{
agentMask.DeleteArrayElementAtIndex(idx);
}
}
agentMask.serializedObject.ApplyModifiedProperties();
}
static void SetAgentMaskNone(object data)
{
var agentMask = (SerializedProperty)data;
agentMask.ClearArray();
agentMask.serializedObject.ApplyModifiedProperties();
}
static void SetAgentMaskAll(object data)
{
var agentMask = (SerializedProperty)data;
agentMask.ClearArray();
agentMask.InsertArrayElementAtIndex(0);
agentMask.GetArrayElementAtIndex(0).intValue = -1;
agentMask.serializedObject.ApplyModifiedProperties();
}
static string GetAgentMaskLabelName(SerializedProperty agentMask)
{
if (agentMask.arraySize == 0)
return "None";
if (IsAll(agentMask))
return "All";
if (agentMask.arraySize <= 3)
{
var labelName = "";
for (var j = 0; j < agentMask.arraySize; j++)
{
var elem = agentMask.GetArrayElementAtIndex(j);
var settingsName = NavMesh.GetSettingsNameFromID(elem.intValue);
if (string.IsNullOrEmpty(settingsName))
continue;
if (labelName.Length > 0)
labelName += ", ";
labelName += settingsName;
}
return labelName;
}
return "Mixed...";
}
static bool AgentMaskHasSelectedAgentTypeID(SerializedProperty agentMask, int agentTypeID)
{
for (var j = 0; j < agentMask.arraySize; j++)
{
var elem = agentMask.GetArrayElementAtIndex(j);
if (elem.intValue == agentTypeID)
return true;
}
return false;
}
}
}
@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: dcb72b0d9a9ea3b43a48a22b952f43c5
timeCreated: 1637536229
guid: 82fa0afb6dbea4d4f9e991c991ceaeb5
timeCreated: 1634920994
licenseType: Pro
MonoImporter:
serializedVersion: 2
@@ -0,0 +1,281 @@
#if H3VR_IMPORTED
using UnityEngine;
using UnityEngine.AI;
namespace UnityEditor.AI
{
[CanEditMultipleObjects]
[CustomEditor(typeof(NavMeshLink))]
class NavMeshLinkEditor : Editor
{
SerializedProperty m_AgentTypeID;
SerializedProperty m_Area;
SerializedProperty m_CostModifier;
SerializedProperty m_AutoUpdatePosition;
SerializedProperty m_Bidirectional;
SerializedProperty m_EndPoint;
SerializedProperty m_StartPoint;
SerializedProperty m_Width;
static int s_SelectedID;
static int s_SelectedPoint = -1;
static Color s_HandleColor = new Color(255f, 167f, 39f, 210f) / 255;
static Color s_HandleColorDisabled = new Color(255f * 0.75f, 167f * 0.75f, 39f * 0.75f, 100f) / 255;
void OnEnable()
{
m_AgentTypeID = serializedObject.FindProperty("m_AgentTypeID");
m_Area = serializedObject.FindProperty("m_Area");
m_CostModifier = serializedObject.FindProperty("m_CostModifier");
m_AutoUpdatePosition = serializedObject.FindProperty("m_AutoUpdatePosition");
m_Bidirectional = serializedObject.FindProperty("m_Bidirectional");
m_EndPoint = serializedObject.FindProperty("m_EndPoint");
m_StartPoint = serializedObject.FindProperty("m_StartPoint");
m_Width = serializedObject.FindProperty("m_Width");
s_SelectedID = 0;
s_SelectedPoint = -1;
NavMeshVisualizationSettings.showNavigation++;
}
void OnDisable()
{
NavMeshVisualizationSettings.showNavigation--;
}
static Matrix4x4 UnscaledLocalToWorldMatrix(Transform t)
{
return Matrix4x4.TRS(t.position, t.rotation, Vector3.one);
}
void AlignTransformToEndPoints(NavMeshLink navLink)
{
var mat = UnscaledLocalToWorldMatrix(navLink.transform);
var worldStartPt = mat.MultiplyPoint(navLink.startPoint);
var worldEndPt = mat.MultiplyPoint(navLink.endPoint);
var forward = worldEndPt - worldStartPt;
var up = navLink.transform.up;
// Flatten
forward -= Vector3.Dot(up, forward) * up;
var transform = navLink.transform;
transform.rotation = Quaternion.LookRotation(forward, up);
transform.position = (worldEndPt + worldStartPt) * 0.5f;
transform.localScale = Vector3.one;
navLink.startPoint = transform.InverseTransformPoint(worldStartPt);
navLink.endPoint = transform.InverseTransformPoint(worldEndPt);
}
public override void OnInspectorGUI()
{
serializedObject.Update();
NavMeshComponentsGUIUtility.AgentTypePopup("Agent Type", m_AgentTypeID);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_StartPoint);
EditorGUILayout.PropertyField(m_EndPoint);
GUILayout.BeginHorizontal();
GUILayout.Space(EditorGUIUtility.labelWidth);
if (GUILayout.Button("Swap"))
{
foreach (NavMeshLink navLink in targets)
{
var tmp = navLink.startPoint;
navLink.startPoint = navLink.endPoint;
navLink.endPoint = tmp;
}
SceneView.RepaintAll();
}
if (GUILayout.Button("Align Transform"))
{
foreach (NavMeshLink navLink in targets)
{
Undo.RecordObject(navLink.transform, "Align Transform to End Points");
Undo.RecordObject(navLink, "Align Transform to End Points");
AlignTransformToEndPoints(navLink);
}
SceneView.RepaintAll();
}
GUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_Width);
EditorGUILayout.PropertyField(m_CostModifier);
EditorGUILayout.PropertyField(m_AutoUpdatePosition);
EditorGUILayout.PropertyField(m_Bidirectional);
NavMeshComponentsGUIUtility.AreaPopup("Area Type", m_Area);
serializedObject.ApplyModifiedProperties();
EditorGUILayout.Space();
}
static Vector3 CalcLinkRight(NavMeshLink navLink)
{
var dir = navLink.endPoint - navLink.startPoint;
return (new Vector3(-dir.z, 0.0f, dir.x)).normalized;
}
static void DrawLink(NavMeshLink navLink)
{
var right = CalcLinkRight(navLink);
var rad = navLink.width * 0.5f;
Gizmos.DrawLine(navLink.startPoint - right * rad, navLink.startPoint + right * rad);
Gizmos.DrawLine(navLink.endPoint - right * rad, navLink.endPoint + right * rad);
Gizmos.DrawLine(navLink.startPoint - right * rad, navLink.endPoint - right * rad);
Gizmos.DrawLine(navLink.startPoint + right * rad, navLink.endPoint + right * rad);
}
[DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
static void RenderBoxGizmo(NavMeshLink navLink, GizmoType gizmoType)
{
if (!EditorApplication.isPlaying)
navLink.UpdateLink();
var color = s_HandleColor;
if (!navLink.enabled)
color = s_HandleColorDisabled;
var oldColor = Gizmos.color;
var oldMatrix = Gizmos.matrix;
Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform);
Gizmos.color = color;
DrawLink(navLink);
Gizmos.matrix = oldMatrix;
Gizmos.color = oldColor;
Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true);
}
[DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)]
static void RenderBoxGizmoNotSelected(NavMeshLink navLink, GizmoType gizmoType)
{
if (NavMeshVisualizationSettings.showNavigation > 0)
{
var color = s_HandleColor;
if (!navLink.enabled)
color = s_HandleColorDisabled;
var oldColor = Gizmos.color;
var oldMatrix = Gizmos.matrix;
Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform);
Gizmos.color = color;
DrawLink(navLink);
Gizmos.matrix = oldMatrix;
Gizmos.color = oldColor;
}
Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true);
}
public void OnSceneGUI()
{
var navLink = (NavMeshLink)target;
if (!navLink.enabled)
return;
var mat = UnscaledLocalToWorldMatrix(navLink.transform);
var startPt = mat.MultiplyPoint(navLink.startPoint);
var endPt = mat.MultiplyPoint(navLink.endPoint);
var midPt = Vector3.Lerp(startPt, endPt, 0.35f);
var startSize = HandleUtility.GetHandleSize(startPt);
var endSize = HandleUtility.GetHandleSize(endPt);
var midSize = HandleUtility.GetHandleSize(midPt);
var zup = Quaternion.FromToRotation(Vector3.forward, Vector3.up);
var right = mat.MultiplyVector(CalcLinkRight(navLink));
var oldColor = Handles.color;
Handles.color = s_HandleColor;
Vector3 pos;
if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 0)
{
EditorGUI.BeginChangeCheck();
Handles.CubeHandleCap(0, startPt, zup, 0.1f * startSize, Event.current.type);
pos = Handles.PositionHandle(startPt, navLink.transform.rotation);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(navLink, "Move link point");
navLink.startPoint = mat.inverse.MultiplyPoint(pos);
}
}
else
{
if (Handles.Button(startPt, zup, 0.1f * startSize, 0.1f * startSize, Handles.CubeHandleCap))
{
s_SelectedPoint = 0;
s_SelectedID = navLink.GetInstanceID();
}
}
if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 1)
{
EditorGUI.BeginChangeCheck();
Handles.CubeHandleCap(0, endPt, zup, 0.1f * startSize, Event.current.type);
pos = Handles.PositionHandle(endPt, navLink.transform.rotation);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(navLink, "Move link point");
navLink.endPoint = mat.inverse.MultiplyPoint(pos);
}
}
else
{
if (Handles.Button(endPt, zup, 0.1f * endSize, 0.1f * endSize, Handles.CubeHandleCap))
{
s_SelectedPoint = 1;
s_SelectedID = navLink.GetInstanceID();
}
}
EditorGUI.BeginChangeCheck();
pos = Handles.Slider(midPt + right * navLink.width * 0.5f, right, midSize * 0.03f, Handles.DotHandleCap, 0);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(navLink, "Adjust link width");
navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(right, (pos - midPt)));
}
EditorGUI.BeginChangeCheck();
pos = Handles.Slider(midPt - right * navLink.width * 0.5f, -right, midSize * 0.03f, Handles.DotHandleCap, 0);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(navLink, "Adjust link width");
navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(-right, (pos - midPt)));
}
Handles.color = oldColor;
}
[MenuItem("GameObject/AI/NavMesh Link", false, 2002)]
static public void CreateNavMeshLink(MenuCommand menuCommand)
{
var parent = menuCommand.context as GameObject;
GameObject go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Link", parent);
go.AddComponent<NavMeshLink>();
var view = SceneView.lastActiveSceneView;
if (view != null)
view.MoveToView(go.transform);
}
}
}
#endif
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: b4607bcf07fdb67428d41b6bd2f9b2fb
timeCreated: 1640645560
licenseType: Free
guid: e597cc45bde363241a196cda89c66e4e
timeCreated: 1634920994
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
@@ -0,0 +1,51 @@
#if H3VR_IMPORTED
using UnityEngine.AI;
namespace UnityEditor.AI
{
[CanEditMultipleObjects]
[CustomEditor(typeof(NavMeshModifier))]
class NavMeshModifierEditor : Editor
{
SerializedProperty m_AffectedAgents;
SerializedProperty m_Area;
SerializedProperty m_IgnoreFromBuild;
SerializedProperty m_OverrideArea;
void OnEnable()
{
m_AffectedAgents = serializedObject.FindProperty("m_AffectedAgents");
m_Area = serializedObject.FindProperty("m_Area");
m_IgnoreFromBuild = serializedObject.FindProperty("m_IgnoreFromBuild");
m_OverrideArea = serializedObject.FindProperty("m_OverrideArea");
NavMeshVisualizationSettings.showNavigation++;
}
void OnDisable()
{
NavMeshVisualizationSettings.showNavigation--;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(m_IgnoreFromBuild);
EditorGUILayout.PropertyField(m_OverrideArea);
if (m_OverrideArea.boolValue)
{
EditorGUI.indentLevel++;
NavMeshComponentsGUIUtility.AreaPopup("Area Type", m_Area);
EditorGUI.indentLevel--;
}
NavMeshComponentsGUIUtility.AgentMaskPopup("Affected Agents", m_AffectedAgents);
EditorGUILayout.Space();
serializedObject.ApplyModifiedProperties();
}
}
}
#endif
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 16f4f028d3b75704fbc40b3122b0c568
timeCreated: 1641758895
licenseType: Free
guid: 9fee8ab006bfde447af976b57e626719
timeCreated: 1634920994
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
@@ -0,0 +1,156 @@
#if H3VR_IMPORTED
using UnityEditor.IMGUI.Controls;
using UnityEditorInternal;
using UnityEngine.AI;
using UnityEngine;
namespace UnityEditor.AI
{
[CanEditMultipleObjects]
[CustomEditor(typeof(NavMeshModifierVolume))]
class NavMeshModifierVolumeEditor : Editor
{
SerializedProperty m_AffectedAgents;
SerializedProperty m_Area;
SerializedProperty m_Center;
SerializedProperty m_Size;
static Color s_HandleColor = new Color(187f, 138f, 240f, 210f) / 255;
static Color s_HandleColorDisabled = new Color(187f * 0.75f, 138f * 0.75f, 240f * 0.75f, 100f) / 255;
static int s_HandleControlIDHint = typeof(NavMeshModifierVolumeEditor).Name.GetHashCode();
BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle(s_HandleControlIDHint);
bool editingCollider
{
get { return EditMode.editMode == EditMode.SceneViewEditMode.Collider && EditMode.IsOwner(this); }
}
void OnEnable()
{
m_AffectedAgents = serializedObject.FindProperty("m_AffectedAgents");
m_Area = serializedObject.FindProperty("m_Area");
m_Center = serializedObject.FindProperty("m_Center");
m_Size = serializedObject.FindProperty("m_Size");
NavMeshVisualizationSettings.showNavigation++;
}
void OnDisable()
{
NavMeshVisualizationSettings.showNavigation--;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
InspectorEditButtonGUI();
EditorGUILayout.PropertyField(m_Size);
EditorGUILayout.PropertyField(m_Center);
NavMeshComponentsGUIUtility.AreaPopup("Area Type", m_Area);
NavMeshComponentsGUIUtility.AgentMaskPopup("Affected Agents", m_AffectedAgents);
EditorGUILayout.Space();
serializedObject.ApplyModifiedProperties();
}
[DrawGizmo(GizmoType.Selected | GizmoType.Active)]
static void RenderBoxGizmo(NavMeshModifierVolume navModifier, GizmoType gizmoType)
{
var color = navModifier.enabled ? s_HandleColor : s_HandleColorDisabled;
var colorTrans = new Color(color.r * 0.75f, color.g * 0.75f, color.b * 0.75f, color.a * 0.15f);
var oldColor = Gizmos.color;
var oldMatrix = Gizmos.matrix;
Gizmos.matrix = navModifier.transform.localToWorldMatrix;
Gizmos.color = colorTrans;
Gizmos.DrawCube(navModifier.center, navModifier.size);
Gizmos.color = color;
Gizmos.DrawWireCube(navModifier.center, navModifier.size);
Gizmos.matrix = oldMatrix;
Gizmos.color = oldColor;
Gizmos.DrawIcon(navModifier.transform.position, "NavMeshModifierVolume Icon", true);
}
[DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)]
static void RenderBoxGizmoNotSelected(NavMeshModifierVolume navModifier, GizmoType gizmoType)
{
if (NavMeshVisualizationSettings.showNavigation > 0)
{
var color = navModifier.enabled ? s_HandleColor : s_HandleColorDisabled;
var oldColor = Gizmos.color;
var oldMatrix = Gizmos.matrix;
Gizmos.matrix = navModifier.transform.localToWorldMatrix;
Gizmos.color = color;
Gizmos.DrawWireCube(navModifier.center, navModifier.size);
Gizmos.matrix = oldMatrix;
Gizmos.color = oldColor;
}
Gizmos.DrawIcon(navModifier.transform.position, "NavMeshModifierVolume Icon", true);
}
void InspectorEditButtonGUI()
{
var navModifier = (NavMeshModifierVolume)target;
var bounds = new Bounds(navModifier.transform.position, navModifier.size);
EditMode.DoEditModeInspectorModeButton(
EditMode.SceneViewEditMode.Collider,
"Edit Volume",
EditorGUIUtility.IconContent("EditCollider"),
bounds,
this
);
}
void OnSceneGUI()
{
if (!editingCollider)
return;
var vol = (NavMeshModifierVolume)target;
var color = vol.enabled ? s_HandleColor : s_HandleColorDisabled;
using (new Handles.DrawingScope(color, vol.transform.localToWorldMatrix))
{
m_BoundsHandle.center = vol.center;
m_BoundsHandle.size = vol.size;
EditorGUI.BeginChangeCheck();
m_BoundsHandle.DrawHandle();
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(vol, "Modified NavMesh Modifier Volume");
Vector3 center = m_BoundsHandle.center;
Vector3 size = m_BoundsHandle.size;
vol.center = center;
vol.size = size;
EditorUtility.SetDirty(target);
}
}
}
[MenuItem("GameObject/AI/NavMesh Modifier Volume", false, 2001)]
static public void CreateNavMeshModifierVolume(MenuCommand menuCommand)
{
var parent = menuCommand.context as GameObject;
var go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Modifier Volume", parent);
go.AddComponent<NavMeshModifierVolume>();
var view = SceneView.lastActiveSceneView;
if (view != null)
view.MoveToView(go.transform);
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: dbb2ed6609af812419e32a5765378c59
timeCreated: 1634920994
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,492 @@
#if H3VR_IMPORTED
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor.IMGUI.Controls;
using UnityEditor.SceneManagement;
using UnityEditorInternal;
using UnityEngine.AI;
using UnityEngine;
namespace UnityEditor.AI
{
[CanEditMultipleObjects]
[CustomEditor(typeof(NavMeshSurface))]
class NavMeshSurfaceEditor : Editor
{
SerializedProperty m_AgentTypeID;
SerializedProperty m_BuildHeightMesh;
SerializedProperty m_Center;
SerializedProperty m_CollectObjects;
SerializedProperty m_DefaultArea;
SerializedProperty m_LayerMask;
SerializedProperty m_OverrideTileSize;
SerializedProperty m_OverrideVoxelSize;
SerializedProperty m_Size;
SerializedProperty m_TileSize;
SerializedProperty m_UseGeometry;
SerializedProperty m_VoxelSize;
class Styles
{
public readonly GUIContent m_LayerMask = new GUIContent("Include Layers");
public readonly GUIContent m_ShowInputGeom = new GUIContent("Show Input Geom");
public readonly GUIContent m_ShowVoxels = new GUIContent("Show Voxels");
public readonly GUIContent m_ShowRegions = new GUIContent("Show Regions");
public readonly GUIContent m_ShowRawContours = new GUIContent("Show Raw Contours");
public readonly GUIContent m_ShowContours = new GUIContent("Show Contours");
public readonly GUIContent m_ShowPolyMesh = new GUIContent("Show Poly Mesh");
public readonly GUIContent m_ShowPolyMeshDetail = new GUIContent("Show Poly Mesh Detail");
}
struct AsyncBakeOperation
{
public NavMeshSurface surface;
public NavMeshData bakeData;
public AsyncOperation bakeOperation;
}
static List<AsyncBakeOperation> s_BakeOperations = new List<AsyncBakeOperation>();
static Styles s_Styles;
static bool s_ShowDebugOptions;
static Color s_HandleColor = new Color(127f, 214f, 244f, 100f) / 255;
static Color s_HandleColorSelected = new Color(127f, 214f, 244f, 210f) / 255;
static Color s_HandleColorDisabled = new Color(127f * 0.75f, 214f * 0.75f, 244f * 0.75f, 100f) / 255;
static int s_HandleControlIDHint = typeof(NavMeshSurfaceEditor).Name.GetHashCode();
BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle(s_HandleControlIDHint);
bool editingCollider
{
get { return EditMode.editMode == EditMode.SceneViewEditMode.Collider && EditMode.IsOwner(this); }
}
void OnEnable()
{
m_AgentTypeID = serializedObject.FindProperty("m_AgentTypeID");
m_BuildHeightMesh = serializedObject.FindProperty("m_BuildHeightMesh");
m_Center = serializedObject.FindProperty("m_Center");
m_CollectObjects = serializedObject.FindProperty("m_CollectObjects");
m_DefaultArea = serializedObject.FindProperty("m_DefaultArea");
m_LayerMask = serializedObject.FindProperty("m_LayerMask");
m_OverrideTileSize = serializedObject.FindProperty("m_OverrideTileSize");
m_OverrideVoxelSize = serializedObject.FindProperty("m_OverrideVoxelSize");
m_Size = serializedObject.FindProperty("m_Size");
m_TileSize = serializedObject.FindProperty("m_TileSize");
m_UseGeometry = serializedObject.FindProperty("m_UseGeometry");
m_VoxelSize = serializedObject.FindProperty("m_VoxelSize");
NavMeshVisualizationSettings.showNavigation++;
}
void OnDisable()
{
NavMeshVisualizationSettings.showNavigation--;
}
static string GetAndEnsureTargetPath(NavMeshSurface surface)
{
// Create directory for the asset if it does not exist yet.
var activeScenePath = surface.gameObject.scene.path;
var targetPath = "Assets";
if (!string.IsNullOrEmpty(activeScenePath))
targetPath = Path.Combine(Path.GetDirectoryName(activeScenePath), Path.GetFileNameWithoutExtension(activeScenePath));
if (!Directory.Exists(targetPath))
Directory.CreateDirectory(targetPath);
return targetPath;
}
static void CreateNavMeshAsset(NavMeshSurface surface)
{
var targetPath = GetAndEnsureTargetPath(surface);
var combinedAssetPath = Path.Combine(targetPath, "NavMesh-" + surface.name + ".asset");
combinedAssetPath = AssetDatabase.GenerateUniqueAssetPath(combinedAssetPath);
AssetDatabase.CreateAsset(surface.navMeshData, combinedAssetPath);
}
static NavMeshData GetNavMeshAssetToDelete(NavMeshSurface navSurface)
{
var prefabType = PrefabUtility.GetPrefabType(navSurface);
if (prefabType == PrefabType.PrefabInstance || prefabType == PrefabType.DisconnectedPrefabInstance)
{
// Don't allow deleting the asset belonging to the prefab parent
var parentSurface = PrefabUtility.GetPrefabParent(navSurface) as NavMeshSurface;
if (parentSurface && navSurface.navMeshData == parentSurface.navMeshData)
return null;
}
return navSurface.navMeshData;
}
void ClearSurface(NavMeshSurface navSurface)
{
var assetToDelete = GetNavMeshAssetToDelete(navSurface);
navSurface.RemoveData();
navSurface.navMeshData = null;
EditorUtility.SetDirty(navSurface);
if (assetToDelete)
{
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(assetToDelete));
EditorSceneManager.MarkSceneDirty(navSurface.gameObject.scene);
}
}
public override void OnInspectorGUI()
{
if (s_Styles == null)
s_Styles = new Styles();
serializedObject.Update();
var bs = NavMesh.GetSettingsByID(m_AgentTypeID.intValue);
if (bs.agentTypeID != -1)
{
// Draw image
const float diagramHeight = 80.0f;
Rect agentDiagramRect = EditorGUILayout.GetControlRect(false, diagramHeight);
NavMeshEditorHelpers.DrawAgentDiagram(agentDiagramRect, bs.agentRadius, bs.agentHeight, bs.agentClimb, bs.agentSlope);
}
NavMeshComponentsGUIUtility.AgentTypePopup("Agent Type", m_AgentTypeID);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_CollectObjects);
if ((CollectObjects)m_CollectObjects.enumValueIndex == CollectObjects.Volume)
{
EditorGUI.indentLevel++;
InspectorEditButtonGUI();
EditorGUILayout.PropertyField(m_Size);
EditorGUILayout.PropertyField(m_Center);
}
else
{
if (editingCollider)
EditMode.QuitEditMode();
}
EditorGUILayout.PropertyField(m_LayerMask, s_Styles.m_LayerMask);
EditorGUILayout.PropertyField(m_UseGeometry);
EditorGUILayout.Space();
EditorGUILayout.Space();
m_OverrideVoxelSize.isExpanded = EditorGUILayout.Foldout(m_OverrideVoxelSize.isExpanded, "Advanced");
if (m_OverrideVoxelSize.isExpanded)
{
EditorGUI.indentLevel++;
NavMeshComponentsGUIUtility.AreaPopup("Default Area", m_DefaultArea);
// Override voxel size.
EditorGUILayout.PropertyField(m_OverrideVoxelSize);
using (new EditorGUI.DisabledScope(!m_OverrideVoxelSize.boolValue || m_OverrideVoxelSize.hasMultipleDifferentValues))
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_VoxelSize);
if (!m_OverrideVoxelSize.hasMultipleDifferentValues)
{
if (!m_AgentTypeID.hasMultipleDifferentValues)
{
float voxelsPerRadius = m_VoxelSize.floatValue > 0.0f ? (bs.agentRadius / m_VoxelSize.floatValue) : 0.0f;
EditorGUILayout.LabelField(" ", voxelsPerRadius.ToString("0.00") + " voxels per agent radius", EditorStyles.miniLabel);
}
if (m_OverrideVoxelSize.boolValue)
EditorGUILayout.HelpBox("Voxel size controls how accurately the navigation mesh is generated from the level geometry. A good voxel size is 2-4 voxels per agent radius. Making voxel size smaller will increase build time.", MessageType.None);
}
EditorGUI.indentLevel--;
}
// Override tile size
EditorGUILayout.PropertyField(m_OverrideTileSize);
using (new EditorGUI.DisabledScope(!m_OverrideTileSize.boolValue || m_OverrideTileSize.hasMultipleDifferentValues))
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_TileSize);
if (!m_TileSize.hasMultipleDifferentValues && !m_VoxelSize.hasMultipleDifferentValues)
{
float tileWorldSize = m_TileSize.intValue * m_VoxelSize.floatValue;
EditorGUILayout.LabelField(" ", tileWorldSize.ToString("0.00") + " world units", EditorStyles.miniLabel);
}
if (!m_OverrideTileSize.hasMultipleDifferentValues)
{
if (m_OverrideTileSize.boolValue)
EditorGUILayout.HelpBox("Tile size controls the how local the changes to the world are (rebuild or carve). Small tile size allows more local changes, while potentially generating more data in overal.", MessageType.None);
}
EditorGUI.indentLevel--;
}
// Height mesh
using (new EditorGUI.DisabledScope(true))
{
EditorGUILayout.PropertyField(m_BuildHeightMesh);
}
EditorGUILayout.Space();
EditorGUI.indentLevel--;
}
EditorGUILayout.Space();
serializedObject.ApplyModifiedProperties();
var hadError = false;
var multipleTargets = targets.Length > 1;
foreach (NavMeshSurface navSurface in targets)
{
var settings = navSurface.GetBuildSettings();
// Calculating bounds is potentially expensive when unbounded - so here we just use the center/size.
// It means the validation is not checking vertical voxel limit correctly when the surface is set to something else than "in volume".
var bounds = new Bounds(Vector3.zero, Vector3.zero);
if (navSurface.collectObjects == CollectObjects.Volume)
{
bounds = new Bounds(navSurface.center, navSurface.size);
}
var errors = settings.ValidationReport(bounds);
if (errors.Length > 0)
{
if (multipleTargets)
EditorGUILayout.LabelField(navSurface.name);
foreach (var err in errors)
{
EditorGUILayout.HelpBox(err, MessageType.Warning);
}
GUILayout.BeginHorizontal();
GUILayout.Space(EditorGUIUtility.labelWidth);
if (GUILayout.Button("Open Agent Settings...", EditorStyles.miniButton))
NavMeshEditorHelpers.OpenAgentSettings(navSurface.agentTypeID);
GUILayout.EndHorizontal();
hadError = true;
}
}
if (hadError)
EditorGUILayout.Space();
using (new EditorGUI.DisabledScope(Application.isPlaying || m_AgentTypeID.intValue == -1))
{
GUILayout.BeginHorizontal();
GUILayout.Space(EditorGUIUtility.labelWidth);
if (GUILayout.Button("Clear"))
{
foreach (NavMeshSurface s in targets)
ClearSurface(s);
SceneView.RepaintAll();
}
if (GUILayout.Button("Bake"))
{
// Remove first to avoid double registration of the callback
EditorApplication.update -= UpdateAsyncBuildOperations;
EditorApplication.update += UpdateAsyncBuildOperations;
foreach (NavMeshSurface surf in targets)
{
var oper = new AsyncBakeOperation();
oper.bakeData = InitializeBakeData(surf);
oper.bakeOperation = surf.UpdateNavMesh(oper.bakeData);
oper.surface = surf;
s_BakeOperations.Add(oper);
}
}
GUILayout.EndHorizontal();
}
// Show progress for the selected targets
for (int i = s_BakeOperations.Count - 1; i >= 0; --i)
{
if (!targets.Contains(s_BakeOperations[i].surface))
continue;
var oper = s_BakeOperations[i].bakeOperation;
if (oper == null)
continue;
var p = oper.progress;
if (oper.isDone)
{
SceneView.RepaintAll();
continue;
}
GUILayout.BeginHorizontal();
if (GUILayout.Button("Cancel", EditorStyles.miniButton))
{
var bakeData = s_BakeOperations[i].bakeData;
UnityEngine.AI.NavMeshBuilder.Cancel(bakeData);
s_BakeOperations.RemoveAt(i);
}
EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(), p, "Baking: " + (int)(100 * p) + "%");
if (p <= 1)
Repaint();
GUILayout.EndHorizontal();
}
}
static NavMeshData InitializeBakeData(NavMeshSurface surface)
{
var emptySources = new List<NavMeshBuildSource>();
var emptyBounds = new Bounds();
return UnityEngine.AI.NavMeshBuilder.BuildNavMeshData(surface.GetBuildSettings(), emptySources, emptyBounds
, surface.transform.position, surface.transform.rotation);
}
static void UpdateAsyncBuildOperations()
{
foreach (var oper in s_BakeOperations)
{
if (oper.surface == null || oper.bakeOperation == null)
continue;
if (oper.bakeOperation.isDone)
{
var surface = oper.surface;
var delete = GetNavMeshAssetToDelete(surface);
if (delete != null)
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(delete));
surface.RemoveData();
surface.navMeshData = oper.bakeData;
if (surface.isActiveAndEnabled)
surface.AddData();
CreateNavMeshAsset(surface);
EditorSceneManager.MarkSceneDirty(surface.gameObject.scene);
}
}
s_BakeOperations.RemoveAll(o => o.bakeOperation == null || o.bakeOperation.isDone);
if (s_BakeOperations.Count == 0)
EditorApplication.update -= UpdateAsyncBuildOperations;
}
[DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
static void RenderBoxGizmoSelected(NavMeshSurface navSurface, GizmoType gizmoType)
{
RenderBoxGizmo(navSurface, gizmoType, true);
}
[DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)]
static void RenderBoxGizmoNotSelected(NavMeshSurface navSurface, GizmoType gizmoType)
{
if (NavMeshVisualizationSettings.showNavigation > 0)
RenderBoxGizmo(navSurface, gizmoType, false);
else
Gizmos.DrawIcon(navSurface.transform.position, "NavMeshSurface Icon", true);
}
static void RenderBoxGizmo(NavMeshSurface navSurface, GizmoType gizmoType, bool selected)
{
var color = selected ? s_HandleColorSelected : s_HandleColor;
if (!navSurface.enabled)
color = s_HandleColorDisabled;
var oldColor = Gizmos.color;
var oldMatrix = Gizmos.matrix;
// Use the unscaled matrix for the NavMeshSurface
var localToWorld = Matrix4x4.TRS(navSurface.transform.position, navSurface.transform.rotation, Vector3.one);
Gizmos.matrix = localToWorld;
if (navSurface.collectObjects == CollectObjects.Volume)
{
Gizmos.color = color;
Gizmos.DrawWireCube(navSurface.center, navSurface.size);
if (selected && navSurface.enabled)
{
var colorTrans = new Color(color.r * 0.75f, color.g * 0.75f, color.b * 0.75f, color.a * 0.15f);
Gizmos.color = colorTrans;
Gizmos.DrawCube(navSurface.center, navSurface.size);
}
}
else
{
if (navSurface.navMeshData != null)
{
var bounds = navSurface.navMeshData.sourceBounds;
Gizmos.color = Color.grey;
Gizmos.DrawWireCube(bounds.center, bounds.size);
}
}
Gizmos.matrix = oldMatrix;
Gizmos.color = oldColor;
Gizmos.DrawIcon(navSurface.transform.position, "NavMeshSurface Icon", true);
}
void InspectorEditButtonGUI()
{
var navSurface = (NavMeshSurface)target;
var bounds = new Bounds(navSurface.transform.position, navSurface.size);
EditMode.DoEditModeInspectorModeButton(
EditMode.SceneViewEditMode.Collider,
"Edit Volume",
EditorGUIUtility.IconContent("EditCollider"),
bounds,
this
);
}
void OnSceneGUI()
{
if (!editingCollider)
return;
var navSurface = (NavMeshSurface)target;
var color = navSurface.enabled ? s_HandleColor : s_HandleColorDisabled;
var localToWorld = Matrix4x4.TRS(navSurface.transform.position, navSurface.transform.rotation, Vector3.one);
using (new Handles.DrawingScope(color, localToWorld))
{
m_BoundsHandle.center = navSurface.center;
m_BoundsHandle.size = navSurface.size;
EditorGUI.BeginChangeCheck();
m_BoundsHandle.DrawHandle();
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(navSurface, "Modified NavMesh Surface");
Vector3 center = m_BoundsHandle.center;
Vector3 size = m_BoundsHandle.size;
navSurface.center = center;
navSurface.size = size;
EditorUtility.SetDirty(target);
}
}
}
[MenuItem("GameObject/AI/NavMesh Surface", false, 2000)]
public static void CreateNavMeshSurface(MenuCommand menuCommand)
{
var parent = menuCommand.context as GameObject;
var go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Surface", parent);
go.AddComponent<NavMeshSurface>();
var view = SceneView.lastActiveSceneView;
if (view != null)
view.MoveToView(go.transform);
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 073386b7052a703489e676087c2b65b0
timeCreated: 1634920994
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -132,7 +132,17 @@ public class EnumPicker : PropertyDrawer
{
Array valuesRaw = null;
Type enumType = fieldInfo.FieldType;
if (enumType.IsArray) enumType = enumType.GetElementType(); //this turns the enum array into just the enum to prevent issues with arrays of enums
// Check if the property is an array or a list
if (enumType.IsArray) enumType = enumType.GetElementType();
else if (enumType.IsGenericType && enumType.GetGenericTypeDefinition() == typeof(List<>))
enumType = enumType.GetGenericArguments()[0];
if (enumType == null || !enumType.IsEnum)
{
Debug.LogError("Can't determine how to draw a field for " + fieldInfo.FieldType);
return;
}
valuesRaw = Enum.GetValues(enumType);
if (valuesRaw.Length <= 0)
@@ -175,6 +185,7 @@ public class EnumPicker : PropertyDrawer
[CustomPropertyDrawer(typeof(ItemSpawnerID.ESubCategory))]
[CustomPropertyDrawer(typeof(FireArmRoundType))]
[CustomPropertyDrawer(typeof(SosigEnemyID))]
[CustomPropertyDrawer(typeof(FVRFireArmAttachementMountType))]
public class EnumDrawers : EnumPicker
{
}
@@ -0,0 +1,110 @@
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.Collections.Generic;
public class HiddenGameObjectTools : EditorWindow
{
#region Menu Command
[MenuItem("Tools/Hidden GameObject Tools")]
public static void ShowWindow()
{
var window = GetWindow<HiddenGameObjectTools>();
window.titleContent = new GUIContent("Hidden GOs");
window.GatherHiddenObjects();
}
#endregion
#region GUI
private static readonly GUILayoutOption ButtonWidth = GUILayout.Width(80);
private static readonly GUILayoutOption BigButtonHeight = GUILayout.Height(35);
private void OnGUI()
{
GUILayout.Space(10f);
GUILayout.BeginHorizontal();
{
if (GUILayout.Button("Refresh", BigButtonHeight))
{
GatherHiddenObjects();
}
if (GUILayout.Button("Test", BigButtonHeight, ButtonWidth))
{
var go = new GameObject("HiddenTestObject");
go.hideFlags = HideFlags.HideInHierarchy;
GatherHiddenObjects();
}
}
GUILayout.EndHorizontal();
GUILayout.Space(10f);
EditorGUILayout.LabelField("Hidden Objects (" + HiddenObjects.Count + ")", EditorStyles.boldLabel);
for (int i = 0; i < HiddenObjects.Count; i++)
{
var hiddenObject = HiddenObjects[i];
GUILayout.BeginHorizontal();
{
var gone = hiddenObject == null;
GUILayout.Label(gone ? "null" : hiddenObject.name);
GUILayout.FlexibleSpace();
if (gone)
{
GUILayout.Box("Select", ButtonWidth);
GUILayout.Box("Reveal", ButtonWidth);
GUILayout.Box("Delete", ButtonWidth);
}
else
{
if (GUILayout.Button("Select", ButtonWidth))
{
Selection.activeGameObject = hiddenObject;
}
if (GUILayout.Button(IsHidden(hiddenObject) ? "Reveal" : "Hide", ButtonWidth))
{
hiddenObject.hideFlags ^= HideFlags.HideInHierarchy;
EditorSceneManager.MarkSceneDirty(hiddenObject.scene);
}
if (GUILayout.Button("Delete", ButtonWidth))
{
var scene = hiddenObject.scene;
DestroyImmediate(hiddenObject);
EditorSceneManager.MarkSceneDirty(scene);
}
}
}
GUILayout.EndHorizontal();
}
}
#endregion
#region Hidden Objects
private List<GameObject> HiddenObjects = new List<GameObject>();
private void GatherHiddenObjects()
{
HiddenObjects.Clear();
var allObjects = FindObjectsOfType<GameObject>();
foreach (var go in allObjects)
{
if ((go.hideFlags & HideFlags.HideInHierarchy) != 0)
{
HiddenObjects.Add(go);
}
}
Repaint();
}
private static bool IsHidden(GameObject go)
{
return (go.hideFlags & HideFlags.HideInHierarchy) != 0;
}
#endregion
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 942768540f60f2a4084fdaee6fa509db
timeCreated: 1629347480
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,73 @@
using System.Collections.Generic;
using MeatKit;
using UnityEditor;
using UnityEngine;
public class PrefabLoader : EditorWindow
{
private AssetBundle _bundle;
private string[] _assets = new string[0];
private int _selectedAsset = 0;
private static readonly Dictionary<string, string> AssemblyNameReplaceMap = new Dictionary<string, string>
{
{MeatKit.MeatKit.AssemblyName + ".dll", MeatKit.MeatKit.AssemblyRename + ".dll"},
{MeatKit.MeatKit.AssemblyFirstpassName + ".dll", MeatKit.MeatKit.AssemblyFirstpassRename + ".dll"}
};
private static readonly Dictionary<string, AssetBundle> LoadedAssetBundles = new Dictionary<string, AssetBundle>();
[MenuItem("MeatKit/Prefab Loader")]
private static void Init()
{
GetWindow<PrefabLoader>().Show();
}
private void OnGUI()
{
if (GUILayout.Button("Select Asset Bundle"))
{
// If there's already a bundle loaded, unload it.
if (_bundle) _bundle = null;
// Ask for the new bundle, load it, and get its assets
string assetBundlePath = EditorUtility.OpenFilePanel("Select Asset Bundle", string.Empty, string.Empty);
// Make sure the user actually selected a file
if (!string.IsNullOrEmpty(assetBundlePath))
{
// Check if we already loaded it
if (!LoadedAssetBundles.TryGetValue(assetBundlePath, out _bundle))
{
_bundle = AssetBundle.LoadFromFile(assetBundlePath);
LoadedAssetBundles[assetBundlePath] = _bundle;
}
// Make sure a valid bundle was selected
if (_bundle != null)
{
_assets = _bundle.GetAllAssetNames();
_selectedAsset = 0;
}
}
}
// Only show spawn button if there's at least one asset
if (_bundle != null && _assets.Length > 0)
{
_selectedAsset = EditorGUILayout.Popup(_selectedAsset, _assets);
if (GUILayout.Button("Spawn"))
{
AssetBundleIO.EnableProcessing(AssemblyNameReplaceMap, true, false);
Instantiate(_bundle.LoadAsset(_assets[_selectedAsset]));
AssetBundleIO.DisableProcessing();
}
// Warn the user about the play mode thing
if (!EditorApplication.isPlaying)
{
EditorGUILayout.HelpBox("References on a prefab loaded object will break after a restart of the editor unless you enter play mode first.", MessageType.Warning);
}
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7972e859acde43c3983695df50bff302
timeCreated: 1684891967
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine.Networking;
namespace MeatKit
{
[InitializeOnLoad]
public static class AsyncDownloader
{
private static readonly Dictionary<UnityWebRequest, Action<UnityWebRequest>> ActiveRequests = new Dictionary<UnityWebRequest, Action<UnityWebRequest>>();
static AsyncDownloader()
{
EditorApplication.update += Update;
}
public static void WaitForCompletion(UnityWebRequest request, Action<UnityWebRequest> callback)
{
if (request == null) throw new ArgumentException("Request cannot be null", "request");
request.Send();
ActiveRequests.Add(request, callback);
}
private static void Update()
{
foreach (var kv in ActiveRequests.ToArray())
{
UnityWebRequest request = kv.Key;
Action<UnityWebRequest> callback = kv.Value;
if (!request.isDone) continue;
if (callback != null) callback(request);
ActiveRequests.Remove(request);
}
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bd989610b12e49edbdc6f03afc4b598f
timeCreated: 1684959395
@@ -0,0 +1,29 @@
using System.IO;
using UnityEditor;
using UnityEngine;
namespace MeatKit
{
public static class CreateUpdatePackage
{
private static readonly string[] ExportAssets =
{
"Assets/MeatKit",
"Assets/Managed/0Harmony.dll",
"Assets/Managed/BepInEx.dll",
"Assets/Managed/DotNetZip.dll",
"Assets/Managed/Mono.Cecil.dll",
"Assets/Managed/MonoMod.RuntimeDetour.dll",
"Assets/Managed/MonoMod.Utils.dll",
"Assets/Managed/Sodalite.dll",
"Assets/Managed/Valve.Newtonsoft.Json.dll",
};
[MenuItem("MeatKit/Developer/Create update package")]
public static void Create()
{
AssetDatabase.ExportPackage(ExportAssets, Updater.UpdatePackageName, ExportPackageOptions.Recurse);
Debug.Log("Exported an update package to " + Path.Combine(Path.GetDirectoryName(Application.dataPath) , Updater.UpdatePackageName));
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9075e2699d46423fbc049d02942b6f09
timeCreated: 1684962211
@@ -0,0 +1,138 @@
using System;
using System.Text;
using System.Text.RegularExpressions;
namespace MeatKit
{
public class SimpleVersion : IComparable<SimpleVersion>
{
private const string RegexPattern = @"^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$";
public int Major { get; private set; }
public int Minor { get; private set; }
public int Patch { get; private set; }
public string Prerelease { get; private set; }
public string BuildMetadata { get; private set; }
public static SimpleVersion Parse(string version)
{
var match = Regex.Match(version, RegexPattern);
if (!match.Success) throw new ArgumentException("Provided version is not valid SemVer.", "version");
return new SimpleVersion
{
Major = int.Parse(match.Groups[1].Value),
Minor = int.Parse(match.Groups[2].Value),
Patch = int.Parse(match.Groups[3].Value),
Prerelease = match.Groups[4].Value,
BuildMetadata = match.Groups[5].Value,
};
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append(Major).Append(".").Append(Minor).Append(".").Append(Patch);
if (!string.IsNullOrEmpty(Prerelease)) sb.Append("-").Append(Prerelease);
if (!string.IsNullOrEmpty(BuildMetadata)) sb.Append("+").Append(BuildMetadata);
return sb.ToString();
}
public int CompareByPrecedence(SimpleVersion other)
{
if (other == null)
return 1;
var r = Major.CompareTo(other.Major);
if (r != 0) return r;
r = Minor.CompareTo(other.Minor);
if (r != 0) return r;
r = Patch.CompareTo(other.Patch);
if (r != 0) return r;
return CompareComponent(Prerelease, other.Prerelease, true);
}
private static int CompareComponent(string a, string b, bool nonemptyIsLower = false)
{
var aEmpty = string.IsNullOrEmpty(a);
var bEmpty = string.IsNullOrEmpty(b);
if (aEmpty && bEmpty)
return 0;
if (aEmpty)
return nonemptyIsLower ? 1 : -1;
if (bEmpty)
return nonemptyIsLower ? -1 : 1;
var aComps = a.Split('.');
var bComps = b.Split('.');
var minLen = Math.Min(aComps.Length, bComps.Length);
for (int i = 0; i < minLen; i++)
{
var ac = aComps[i];
var bc = bComps[i];
int aNum;
var aIsNum = int.TryParse(ac, out aNum);
int bNum;
var bIsNum = int.TryParse(bc, out bNum);
int r;
if (aIsNum && bIsNum)
{
r = aNum.CompareTo(bNum);
if (r != 0) return r;
}
else
{
if (aIsNum)
return -1;
if (bIsNum)
return 1;
r = string.CompareOrdinal(ac, bc);
if (r != 0)
return r;
}
}
return aComps.Length.CompareTo(bComps.Length);
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (ReferenceEquals(this, obj))
return true;
var other = (SimpleVersion)obj;
return Major == other.Major
&& Minor == other.Minor
&& Patch == other.Patch
&& string.Equals(Prerelease, other.Prerelease, StringComparison.Ordinal)
&& string.Equals(BuildMetadata, other.BuildMetadata, StringComparison.Ordinal);
}
public override int GetHashCode()
{
unchecked
{
int result = Major.GetHashCode();
result = result * 31 + Minor.GetHashCode();
result = result * 31 + Patch.GetHashCode();
result = result * 31 + Prerelease.GetHashCode();
result = result * 31 + BuildMetadata.GetHashCode();
return result;
}
}
public int CompareTo(SimpleVersion other)
{
return CompareByPrecedence(other);
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 06b3949a4ca64e09af4d019e93c4dd73
timeCreated: 1684948996
+123
View File
@@ -0,0 +1,123 @@
using System;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using Valve.Newtonsoft.Json.Linq;
namespace MeatKit
{
public static class Updater
{
public const string UpdatePackageName = "MeatKitUpdate.unitypackage";
public const string UpdateUrl = "https://api.github.com/repos/H3VR-Modding/MeatKit/releases";
public static bool CheckingForUpdate { get; private set; }
private static bool AllowPreReleases { get; set; }
public static SimpleVersion _currentVersion;
public static SimpleVersion CurrentVersion
{
get
{
if (_currentVersion == null)
{
if (File.Exists("ProjectSettings/MeatKitVersion.txt"))
_currentVersion = SimpleVersion.Parse(File.ReadAllText("ProjectSettings/MeatKitVersion.txt"));
else
{
File.WriteAllText("ProjectSettings/MeatKitVersion.txt", "0.0.0");
_currentVersion = SimpleVersion.Parse("0.0.0");
}
}
return _currentVersion;
}
}
public static SimpleVersion OnlineVersion { get; private set; }
private static long OnlineReleaseId { get; set; }
public static void CheckForUpdate(bool allowPrerelease)
{
CheckingForUpdate = true;
AllowPreReleases = allowPrerelease;
var request = UnityWebRequest.Get(UpdateUrl);
AsyncDownloader.WaitForCompletion(request, UpdateCheckComplete);
}
private static void UpdateCheckComplete(UnityWebRequest request)
{
if (request.isError)
{
Debug.LogError("Error fetching releases for " + request.url + "\n" + request.error);
}
else
{
var response = JArray.Parse(request.downloadHandler.text);
var latestRelease = response.First(r => !r["prerelease"].Value<bool>() || AllowPreReleases);
OnlineVersion = SimpleVersion.Parse(latestRelease["tag_name"].Value<string>());
OnlineReleaseId = latestRelease["id"].Value<long>();
}
MeatKitCache.LastUpdateCheckTime = DateTime.Now;
CheckingForUpdate = false;
// Force a repaint on the update window if it's open
UpdaterEditorWindow window = EditorWindow.GetWindow<UpdaterEditorWindow>();
if (window) window.Repaint();
}
public static void StartUpdate()
{
if (OnlineVersion == null || OnlineReleaseId == 0) return;
// Try and fetch the assets on the release
AsyncDownloader.WaitForCompletion(UnityWebRequest.Get(UpdateUrl + "/" + OnlineReleaseId + "/assets"), CheckForUpdateAsset);
}
private static void CheckForUpdateAsset(UnityWebRequest request)
{
var response = JArray.Parse(request.downloadHandler.text);
// Check if any of the filenames are "MeatKitUpdate.unitypackage"
var updateAsset = response.FirstOrDefault(t => t["name"].Value<string>() == "MeatKitUpdate.unitypackage");
if (updateAsset == null)
{
EditorUtility.DisplayDialog("Failed to update", "Could not find the unity package associated with the target version. Nothing has been modified.", "Ok.");
return;
}
// Start a new request to download the package.
AsyncDownloader.WaitForCompletion(UnityWebRequest.Get(updateAsset["browser_download_url"].Value<string>()), ApplyUpdatePackage);
}
private static void ApplyUpdatePackage(UnityWebRequest request)
{
// Save the downloaded file to a temp location
string tempFile = Path.GetTempFileName();
File.WriteAllBytes(tempFile, request.downloadHandler.data);
// Wipe the MeatKit folder so it's fresh and ready for the new stuff
string dataDir = Path.Combine(Application.dataPath, "MeatKit");
Directory.Delete(dataDir, true);
File.Delete(dataDir + ".meta");
// Import all the files from it
AssetDatabase.ImportPackage(tempFile, false);
// Kick the asset database to refresh now that we're done
AssetDatabase.Refresh();
// Remove the temp file
File.Delete(tempFile);
// Update the saved version number
File.WriteAllText("ProjectSettings/MeatKitVersion.txt", OnlineVersion.ToString());
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 406166d3dc514f5bb884a2b40b183e26
timeCreated: 1684892343
@@ -0,0 +1,55 @@
using System;
using UnityEditor;
using UnityEngine;
namespace MeatKit
{
public class UpdaterEditorWindow : EditorWindow
{
private bool _allowPrerelease;
[MenuItem("MeatKit/Check for updates")]
public static void Open()
{
GetWindow<UpdaterEditorWindow>("MeatKit Updater").Show();
}
private void OnGUI()
{
EditorGUILayout.LabelField("MeatKit Updater", EditorStyles.boldLabel);
EditorGUILayout.LabelField("Installed version: " + Updater.CurrentVersion);
SimpleVersion onlineVersion = Updater.OnlineVersion;
if (onlineVersion == null) EditorGUILayout.LabelField("Online version: Unknown (check for updates)");
else EditorGUILayout.LabelField("Online version: " + onlineVersion);
if (MeatKitCache.LastUpdateCheckTime != default(DateTime))
GUILayout.Label("Last update check: " + MeatKitCache.LastUpdateCheckTime);
else GUILayout.Label("Last update check: Never");
if (!Updater.CheckingForUpdate)
{
if (GUILayout.Button("Check for updates"))
{
Updater.CheckForUpdate(_allowPrerelease);
}
_allowPrerelease = GUILayout.Toggle(_allowPrerelease, "Allow pre-release versions");
if (Updater.CurrentVersion.CompareTo(onlineVersion) < 0)
{
if (GUILayout.Button("Update to " + onlineVersion, GUILayout.Height(50)))
{
Updater.StartUpdate();
}
}
}
else
{
EditorGUI.BeginDisabledGroup(true);
GUILayout.Button("Checking...");
EditorGUI.EndDisabledGroup();
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b54e300d191d47d4a2666733d6bd77e2
timeCreated: 1684891987
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e064a960324f477e9d8eb84cd5115b51
timeCreated: 1655418891
@@ -0,0 +1,95 @@
/*
* This code is from BepInEx's NStrip library, licensed under MIT
* https://github.com/BepInEx/NStrip/blob/f1e9887b3eb77c0e02acb5919b5e26a6e7c2c342/NStrip/AssemblyStripper.cs
*/
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using UnityEngine;
namespace NStrip
{
public static class AssemblyStripper
{
static IEnumerable<TypeDefinition> GetAllTypeDefinitions(AssemblyDefinition assembly)
{
var typeQueue = new Queue<TypeDefinition>(assembly.MainModule.Types);
while (typeQueue.Count > 0)
{
var type = typeQueue.Dequeue();
yield return type;
foreach (var nestedType in type.NestedTypes)
typeQueue.Enqueue(nestedType);
}
}
private static bool CheckCompilerGeneratedAttribute(IMemberDefinition member)
{
return member.CustomAttributes.Any(x =>
x.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute");
}
public static void MakePublic(AssemblyDefinition assembly, IList<string> typeNameBlacklist, bool includeCompilerGenerated, bool excludeCgEvents)
{
foreach (var type in GetAllTypeDefinitions(assembly))
{
if (typeNameBlacklist.Contains(type.Name))
continue;
if (!includeCompilerGenerated && CheckCompilerGeneratedAttribute(type))
continue;
if (type.IsNested)
type.IsNestedPublic = true;
else
type.IsPublic = true;
foreach (var method in type.Methods)
{
if (!includeCompilerGenerated &&
(CheckCompilerGeneratedAttribute(method) || method.IsCompilerControlled))
continue;
method.IsPublic = true;
}
foreach (var field in type.Fields)
{
if (!includeCompilerGenerated &&
(CheckCompilerGeneratedAttribute(field) || field.IsCompilerControlled))
continue;
if (includeCompilerGenerated && excludeCgEvents)
{
if (type.Events.Any(x => x.Name == field.Name))
continue;
}
if (field.IsPublic) continue;
field.IsPublic = true;
var attributes = field.CustomAttributes;
CustomAttribute isExplicitlySerialized = attributes.FirstOrDefault(x => x.AttributeType.Name == "SerializeField");
if (isExplicitlySerialized == null)
{
var nonSerializedAttributeCtor = typeof(NonSerializedAttribute).GetConstructor(Type.EmptyTypes);
var nonSerializedAttributeRef = assembly.MainModule.ImportReference(nonSerializedAttributeCtor);
attributes.Add(new CustomAttribute(nonSerializedAttributeRef));
var hideInInspectorCtor = typeof(MeatKit.HideInNormalInspectorAttribute).GetConstructor(Type.EmptyTypes);
var hideInInspectorRef = assembly.MainModule.ImportReference(hideInInspectorCtor);
attributes.Add(new CustomAttribute(hideInInspectorRef));
}
}
}
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4c62b8c488f64d298e5bc464fdee9f17
timeCreated: 1646326380
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace MeatKit
{
public class NativeHookFunctionOffsets
{
public long MonoScriptTransferWrite { get; set; }
public long MonoScriptTransferRead { get; set; }
public long ShutdownManaged { get; set; }
public long StringAssign { get; set; }
}
public class EditorVersion
{
public NativeHookFunctionOffsets FunctionOffsets { get; set; }
private static bool _hasShownPopup = false;
public static bool IsSupportedVersion
{
get
{
bool supported = SupportedVersions.ContainsKey(Application.unityVersion);
if (!supported && !_hasShownPopup)
{
// Show the warning popup about the wrong version if is hasn't come up already.
string validVersion = string.Join(", ", SupportedVersions.Keys.ToArray());
EditorUtility.DisplayDialog("Wrong editor version",
"You are using Unity version " + Application.unityVersion + ", MeatKit requires one of the following: " + validVersion,
"I'll go install that.");
_hasShownPopup = true;
}
return supported;
}
}
public static EditorVersion Current
{
get
{
EditorVersion currentVersion;
if (SupportedVersions.TryGetValue(Application.unityVersion, out currentVersion))
return currentVersion;
throw new NotSupportedException("The current editor version is not in the list of supported versions.");
}
}
private static readonly Dictionary<string, EditorVersion> SupportedVersions = new Dictionary<string, EditorVersion>()
{
{
"5.6.3p4", new EditorVersion
{
FunctionOffsets = new NativeHookFunctionOffsets
{
MonoScriptTransferWrite = 0xE321E0,
MonoScriptTransferRead = 0xE34000,
ShutdownManaged = 0x17542D0,
StringAssign = 0x1480
}
}
},
{
"5.6.7f1", new EditorVersion
{
FunctionOffsets = new NativeHookFunctionOffsets
{
MonoScriptTransferWrite = 0xE39BF0,
MonoScriptTransferRead = 0xE3BA10,
ShutdownManaged = 0x175D2C0,
StringAssign = 0x1480
}
}
},
};
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f6222c8b0cb74878820d6fe4c55aae88
timeCreated: 1684366513
@@ -0,0 +1,16 @@
using UnityEngine;
using UnityEditor;
namespace MeatKit
{
[CustomPropertyDrawer(typeof(HideInNormalInspectorAttribute))]
class HideInNormalInspectorDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return 0f;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { }
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0c4b5d56cc4522845a6ca6bb3d6d76f0
timeCreated: 1667603705
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using MonoMod.RuntimeDetour;
using MonoMod.Utils;
using UnityEditor;
using UnityEngine;
namespace MeatKit
{
/// <summary>
/// This class helps manage detours into the native code of the Editor.
/// Any detours into native code should be registered using this as it will automatically dispose of them
/// right before the Editor reloads the mono domain, preventing editor crashes.
/// </summary>
[InitializeOnLoad]
public static class NativeHookManager
{
// Actual name: ShutdownPlatformSupportModulesInManaged(void)
private delegate void ShutdownManaged();
private static readonly ShutdownManaged OrigShutdownManaged;
// Keep track of all the applied detours so we can quickly undo them before the mono domain is reloaded
private static readonly List<NativeDetour> Detours = new List<NativeDetour>();
static NativeHookManager()
{
if (!EditorVersion.IsSupportedVersion) return;
// Apply our detours here and save the trampoline to call the original function
OrigShutdownManaged = ApplyEditorDetour<ShutdownManaged>(EditorVersion.Current.FunctionOffsets.ShutdownManaged, new ShutdownManaged(OnShutdownManaged));
}
public static T ApplyEditorDetour<T>(long from, Delegate to) where T : class
{
// Avoid crashing the editor if we're loaded in the wrong Unity version
if (!EditorVersion.IsSupportedVersion) return null;
// Get the base address of the Unity module and the address in memory of the function
IntPtr editorBase = DynDll.OpenLibrary("Unity.exe");
IntPtr fromPtr = (IntPtr)(editorBase.ToInt64() + from);
// Get a function pointer for the managed callback
var toPtr = Marshal.GetFunctionPointerForDelegate(to);
// Make a detour and add it to the list
var detour = new NativeDetour(fromPtr, toPtr, new NativeDetourConfig { ManualApply = true });
Detours.Add(detour);
// Apply the detour and generate a trampoline for it, which we return
var original = detour.GenerateTrampoline(to.GetType().GetMethod("Invoke")).CreateDelegate(typeof(T)) as T;
detour.Apply();
return original;
}
public static Delegate GetDelegateForFunctionPointer<T>(long from)
{
// Avoid crashing the editor if we're loaded in the wrong Unity version
if (!EditorVersion.IsSupportedVersion) return null;
// Get the base address for the Unity module and apply the offset
IntPtr editorBase = DynDll.OpenLibrary("Unity.exe");
return Marshal.GetDelegateForFunctionPointer((IntPtr)(editorBase.ToInt64() + from), typeof(T));
}
private static void OnShutdownManaged()
{
// Unity is about to shutdown the mono runtime! Quickly dispose of our detours!
OrigShutdownManaged();
foreach (var detour in Detours) detour.Dispose();
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9a51d43ba1fe4baf8e3b0a90d7f8ec88
timeCreated: 1654485214
@@ -0,0 +1,45 @@
using System.IO;
using System.Text.RegularExpressions;
using Microsoft.Win32;
namespace MeatKit
{
public static class SteamAppLocator
{
private const int AppId = 450540;
private const string AppFolderName = "H3VR";
public static string LocateGame()
{
// Get the main steam installation location via registry.
var steamDir = (
Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam", "InstallPath", null) ??
Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Valve\Steam", "InstallPath", null))
as string;
// If we can't find it, return. This should really only happen if Steam isn't installed.
if (string.IsNullOrEmpty(steamDir)) return null;
// Check main steamapps library folder for h3 manifest.
var manifestFile = @"steamapps\appmanifest_" + AppId + ".acf";
var gameFolder = @"steamapps\common\" + AppFolderName + @"\";
if (File.Exists(Path.Combine(steamDir, manifestFile)))
{
return Path.Combine(steamDir, gameFolder);
}
// We didn't find it, look at other library folders by lazily parsing libraryfolders.
var libraryFolders = Path.Combine(steamDir, @"steamapps\libraryfolders.vdf");
foreach (Match match in Regex.Matches(File.ReadAllText(libraryFolders), @"^\s+\""path\""\s+\""(.+)\""$",
RegexOptions.Multiline))
{
var folder = match.Groups[1].Value;
if (!File.Exists(Path.Combine(folder, manifestFile))) continue;
return Path.Combine(folder, gameFolder);
}
// Nope. Still can't find it.
return null;
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4c50a485a68d43caa9c30a864c2d8b25
timeCreated: 1655693881
@@ -0,0 +1,60 @@
using System;
using System.Runtime.InteropServices;
namespace MeatKit
{
public static class UnityNativeHelper
{
private delegate IntPtr StringAssignType(IntPtr ptr, string str, ulong len, IntPtr nul);
private static readonly StringAssignType AssignNativeString;
static UnityNativeHelper()
{
if (!EditorVersion.IsSupportedVersion) return;
AssignNativeString = (StringAssignType) NativeHookManager.GetDelegateForFunctionPointer<StringAssignType>(EditorVersion.Current.FunctionOffsets.StringAssign);
}
/// <summary>
/// Reads a native string structure from unmanaged memory
/// </summary>
/// <param name="ptr">The pointer to the structure</param>
/// <param name="ofs">Offset to the pointer</param>
/// <returns>A copy of the structure in managed memory</returns>
public static string ReadNativeString(IntPtr ptr, int ofs)
{
// Apply the offset
var real = (IntPtr) (ptr.ToInt64() + ofs);
// Get the pointer to the string in memory
var stringPointer = Marshal.ReadIntPtr(real);
if (stringPointer == IntPtr.Zero)
{
// If the pointer is null, that means it's stored in the struct directly.
// In this format, the string is 16 chars or less.
var length = Marshal.ReadInt64(real, 24);
return Marshal.PtrToStringAnsi((IntPtr) (real.ToInt64() + 8), (int) length);
}
else
{
// If it isn't null, we can just go out into that memory location and read it.
var length = Marshal.ReadInt64(real, 24);
return Marshal.PtrToStringAnsi(stringPointer, (int) length);
}
}
/// <summary>
/// Writes a managed string to the unmanaged memory location of a string structure
/// </summary>
/// <param name="ptr">The pointer to the structure in memory</param>
/// <param name="ofs">Offset to the pointer</param>
/// <param name="str">The string to write</param>
public static void WriteNativeString(IntPtr ptr, int ofs, string str)
{
// Apply the offset and call the assign function of native Unity code
var real = (IntPtr) (ptr.ToInt64() + ofs);
AssignNativeString(real, str, (ulong) str.Length, IntPtr.Zero);
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ba90027061ca46f88e2e0cf4fefc0224
timeCreated: 1655406646
@@ -0,0 +1,5 @@
using UnityEngine;
namespace MeatKit
{
public class HideInNormalInspectorAttribute : PropertyAttribute { }
}
+12
View File
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3f2d0027e67ba7c45bebe5483a614d44
timeCreated: 1667603705
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

-76
View File
@@ -1,76 +0,0 @@
fileFormatVersion: 2
guid: f999bddab1821b94691466e97cc6891f
timeCreated: 1642657287
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 1
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: 2
aniso: -1
mipBias: -1
wrapMode: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

-76
View File
@@ -1,76 +0,0 @@
fileFormatVersion: 2
guid: 151c1f5398ee70041a49c417b23f1846
timeCreated: 1640061561
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: 2
aniso: -1
mipBias: -1
wrapMode: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

-76
View File
@@ -1,76 +0,0 @@
fileFormatVersion: 2
guid: 6fae6dfd178cd184180013acef55632c
timeCreated: 1640061322
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: 2
aniso: -1
mipBias: -1
wrapMode: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
-34
View File
@@ -1,34 +0,0 @@
fileFormatVersion: 2
guid: cfc6c4032c0e78f7c0480d3c1c93001e
timeCreated: 1637991225
licenseType: Pro
PluginImporter:
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
data:
first:
Any:
second:
enabled: 1
settings: {}
data:
first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
data:
first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
-34
View File
@@ -1,34 +0,0 @@
fileFormatVersion: 2
guid: f0ebcb063f9204b9162f28fbb60fc29c
timeCreated: 1634082208
licenseType: Pro
PluginImporter:
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
data:
first:
Any:
second:
enabled: 1
settings: {}
data:
first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
data:
first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
-34
View File
@@ -1,34 +0,0 @@
fileFormatVersion: 2
guid: 435f5990a4548dbc0126c23e6081aa8d
timeCreated: 1638843984
licenseType: Pro
PluginImporter:
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
data:
first:
Any:
second:
enabled: 1
settings: {}
data:
first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
data:
first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
-34
View File
@@ -1,34 +0,0 @@
fileFormatVersion: 2
guid: 7399badb939ce1137fff9ef0738fd1aa
timeCreated: 1637991225
licenseType: Pro
PluginImporter:
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
data:
first:
Any:
second:
enabled: 1
settings: {}
data:
first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
data:
first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
-34
View File
@@ -1,34 +0,0 @@
fileFormatVersion: 2
guid: 35077c065319ab23c8ea7477fa04223d
timeCreated: 1635021478
licenseType: Pro
PluginImporter:
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
data:
first:
Any:
second:
enabled: 1
settings: {}
data:
first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
data:
first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
-34
View File
@@ -1,34 +0,0 @@
fileFormatVersion: 2
guid: 99b8fb0fa0c1bbbbacd9654ef1e25df4
timeCreated: 1636265531
licenseType: Pro
PluginImporter:
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
data:
first:
Any:
second:
enabled: 1
settings: {}
data:
first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
data:
first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
+51 -20
View File
@@ -1,9 +1,12 @@
#if H3VR_IMPORTED
using System.Collections;
using System;
using HarmonyLib;
using System.IO;
using System.Reflection;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using BepInEx.Configuration;
using UnityEngine;
using UnityEngine.UI;
@@ -16,29 +19,31 @@ using Sodalite;
/*
* SUPER LARGE WARNING ABOUT THIS CLASS
* This class can be used to add custom behaviour to your generated BepInEx plugin.
* Please note, however, that all of the things in here already are REQUIRED and CANNOT BE CHANGED.
* There are LARGE TEXT WARNINGS above such items so you don't forget.
* You may add to this class so long as you do not modify anything with those notices (lest you want build errors)
* This is the default and fallback class that MeatKit uses as a template to generate a BepInEx plugin
* when building your mod. DO NOT MODIFY THIS FILE AT ALL, IN ANY WAY.
*
* The class name and BepInPlugin attribute are modified at build-time to reflect your build settings.
* BepInDependency attributes will automatically be generated if they're required by a build item, otherwise
* may add it yourself here.
* If you want to add custom behavior to your mod, you should make a copy of this class, and put it inside
* the main namespace of your mod (that namespace can be found by opening the 'Allowed Namespaces' list on your build
* profile). MeatKit will then detect and use that class instead of this one, for that one specific profile.
*
* HOWEVER, YOU MUST KEEP ALL OF THE STUFF FROM THIS TEMPLATE, otherwise MeatKit may fail to correctly build
* your plugin, or your mod may fail to correctly load.
*/
// DO NOT REMOVE OR CHANGE ANY OF THESE ATTRIBUTES
[BepInPlugin("MeatKit", "MeatKit Plugin", "1.0.0")]
[BepInProcess("h3vr.exe")]
// DO NOT CHANGE THE NAME OF THIS CLASS.
// DO NOT CHANGE THE NAME OF THIS CLASS OR THE BASE CLASS. If you're making a custom plugin, make sure it extends BaseUnityPlugin.
public class MeatKitPlugin : BaseUnityPlugin
{
// DO NOT CHANGE OR REMOVE THIS FIELD.
#pragma warning disable 414
private static readonly string BasePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
internal new static ManualLogSource Logger;
#pragma warning restore 414
public static AssetBundle bundle;
public static AssetBundle bundle;
public static Font fontAgencyFB;
public static Font fontBombardier;
@@ -99,13 +104,29 @@ public class MeatKitPlugin : BaseUnityPlugin
WristMenuAPI.Buttons.Remove(wmbHPToggle);
}
// TNH patches
if (GameObject.Find("_GameManager") != null || FindObjectOfType<TNH_Manager>() != null)
StartCoroutine("TryTNH");
}
private IEnumerator TryTNH()
{
for (int i = 0; i < 11; ++i)
{
Logger.LogInfo("We are in a TNH game!");
instance = new GameObject().AddComponent<InPlay>();
// TNH patches
if (GameObject.Find("_GameManager") != null || FindObjectOfType<TNH_Manager>() != null)
{
Logger.LogInfo("We are in a TNH game!");
instance = new GameObject().AddComponent<InPlay>();
break;
}
else
{
Logger.LogInfo(String.Format("Couldn't find a TNH game. Trying again...({0}/10)", i));
yield return new WaitForEndOfFrame();
}
}
else
// destroy self only if we are FOR SURE not in a TNH game
if (GameObject.Find("_GameManager") == null || FindObjectOfType<TNH_Manager>() == null)
{
Logger.LogInfo("We are NOT in a TNH game!");
Destroy(instance);
@@ -140,13 +161,20 @@ public class MeatKitPlugin : BaseUnityPlugin
public MeatKitPlugin(): base()
{
harmony = new Harmony("muskit.TNHQualityOfLifeImprovements");
lpcSearchTime = 30f + 30f * Mathf.Sin(System.DateTime.Today.DayOfYear / 365f);
lpcSearchTime = 30f + 30f * Mathf.Sin(System.DateTime.Today.DayOfYear / 365f); // lolz
}
// You are free to edit this method, however please ensure LoadAssets is still called somewhere inside it.
private void Awake()
{
// MeatKit requirement
// ----- BEGIN MEATKIT REQ. CODE -----
// This lets you use your BepInEx-provided logger from other scripts in your project
Logger = base.Logger;
// You may place code before/after this, but do not remove this call to LoadAssets
LoadAssets();
// ----- END MEATKIT REQ. CODE -----
// get Agency FB from system (BAD IDEA, NOT EVERYONE WILL HAVE IT; MAY SET TO DEFAULT FONT)
//fontAgencyFB = Font.CreateDynamicFontFromOSFont("Agency FB", 16);
@@ -224,9 +252,6 @@ public class MeatKitPlugin : BaseUnityPlugin
RunPatches();
}
// DO NOT EDIT.
private void LoadAssets() {}
private void RunPatches()
{
if (harmony == null)
@@ -292,5 +317,11 @@ public class MeatKitPlugin : BaseUnityPlugin
lpcStopSearching = true;
}
}
// DO NOT CHANGE OR REMOVE THIS METHOD. It's contents will be overwritten when building your package.
private void LoadAssets()
{
// Code to load your build items will be generated at build-time and inserted here
}
}
#endif
#endif
Binary file not shown.
-8
View File
@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: f69811f758fe69d4a8db916798dae1d0
timeCreated: 1641677517
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
-9
View File
@@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: 909a2b7b1c734764287b9acd96752fc7
folderAsset: yes
timeCreated: 1640643655
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -1,70 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(IconCamera))]
[CanEditMultipleObjects]
public class IconCameraEditor : Editor {
Texture2D previewTexture = null;
public override void OnInspectorGUI()
{
serializedObject.Update();
var property = serializedObject.GetIterator();
if (!property.NextVisible(true)) return;
do EditorGUILayout.PropertyField(property, true);
while (property.NextVisible(false));
serializedObject.ApplyModifiedProperties();
IconCamera iconCamera = serializedObject.targetObject as IconCamera;
iconCamera.thisCamera.depthTextureMode = iconCamera.CameraDepthMode;
if (previewTexture != null)
{
GUILayout.BeginVertical("Box");
GUIStyle style = new GUIStyle();
style.alignment = TextAnchor.UpperCenter;
style.fixedWidth = Screen.width - 50;
style.fixedHeight = Screen.width - 50;
GUILayout.Label(previewTexture, style);
GUILayout.EndVertical();
}
if (GUILayout.Button("Update Preview"))
{
if (iconCamera.renderTexture != null)
{
RenderTexture temp = RenderTexture.active;
RenderTexture.active = iconCamera.renderTexture;
Texture2D texture = new Texture2D(iconCamera.renderTexture.width, iconCamera.renderTexture.height);
texture.ReadPixels(new Rect(0, 0, iconCamera.renderTexture.width, iconCamera.renderTexture.height), 0, 0);
texture.Apply();
RenderTexture.active = temp;
texture = iconCamera.FlipTexture(texture);
if (iconCamera.background != null)
{
texture = iconCamera.AddBackground(texture, iconCamera.background);
}
previewTexture = texture;
}
}
if (GUILayout.Button("Take Picture"))
{
Selection.activeGameObject.GetComponent<IconCamera>().Capture();
}
}
}
@@ -1,37 +0,0 @@
using System;
using UnityEditor;
using UnityEngine;
public class PrefabLoader : EditorWindow
{
private AssetBundle _bundle;
private string[] _assets = new string[0];
private int _selectedAsset = 0;
[MenuItem("MeatKit/Asset Bundle/Prefab Loader")]
private static void Init()
{
GetWindow<PrefabLoader>().Show();
}
private void OnGUI()
{
if (GUILayout.Button("Select Asset Bundle"))
{
// If there's already a bundle loaded, unload it.
if (_bundle) _bundle.Unload(false);
// Ask for the new bundle, load it, and get its assets
string assetBundlePath = EditorUtility.OpenFilePanel("Select Asset Bundle", string.Empty, string.Empty);
_bundle = AssetBundle.LoadFromFile(assetBundlePath);
_assets = _bundle.GetAllAssetNames();
_selectedAsset = 0;
}
if (_assets.Length > 0)
{
_selectedAsset = EditorGUILayout.Popup(_selectedAsset, _assets);
if (GUILayout.Button("Spawn")) Instantiate(_bundle.LoadAsset(_assets[_selectedAsset]));
}
}
}

Some files were not shown because too many files have changed in this diff Show More