mirror of
https://github.com/muskit/H3VR-TNH-Quality-of-Life-Improvements.git
synced 2026-06-02 20:24:26 -07:00
update MeatKit (9a1a68ab68cd0650227af944ffa30d1166b9e056)
This commit is contained in:
Generated
-31
@@ -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
@@ -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
|
||||
Generated
+2
-2
@@ -1,6 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b545caf63c55b0143bd5c4ce2e5eef7c
|
||||
timeCreated: 1642332594
|
||||
guid: ef60ed33189250d4c8b65b237758ad95
|
||||
timeCreated: 1645904809
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 11400000
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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:
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
-16
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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
|
||||
+3
-3
@@ -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
|
||||
+3
-3
@@ -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:
|
||||
+12
-1
@@ -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
|
||||
{
|
||||
}
|
||||
Generated
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
Generated
+3
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06b3949a4ca64e09af4d019e93c4dd73
|
||||
timeCreated: 1684948996
|
||||
@@ -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
@@ -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
|
||||
Generated
+3
@@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba90027061ca46f88e2e0cf4fefc0224
|
||||
timeCreated: 1655406646
|
||||
@@ -0,0 +1,5 @@
|
||||
using UnityEngine;
|
||||
namespace MeatKit
|
||||
{
|
||||
public class HideInNormalInspectorAttribute : PropertyAttribute { }
|
||||
}
|
||||
@@ -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
@@ -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 |
@@ -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
@@ -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.
Generated
-34
@@ -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.
Generated
-34
@@ -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
@@ -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
@@ -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.
Generated
-34
@@ -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.
@@ -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:
|
||||
@@ -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.
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f69811f758fe69d4a8db916798dae1d0
|
||||
timeCreated: 1641677517
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Generated
-9
@@ -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
Reference in New Issue
Block a user