using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Sirdoggy.SideloaderMint.Addons;
using Sirdoggy.SideloaderMint.Addons.Data;
using Sirdoggy.SideloaderMint.AssetLoaders;
using Sirdoggy.SideloaderMint.AssetLoaders.Implementations;
using Sirdoggy.SideloaderMint.Common;
using Sirdoggy.SideloaderMint.Common.FVR;
using Sirdoggy.SideloaderMint.Common.Structures;
using Sirdoggy.SideloaderMint.Common.Validation;
using Sirdoggy.SideloaderMint.Patchers;
using UnityEngine;
using Valve.Newtonsoft.Json;
using Valve.Newtonsoft.Json.Linq;
using XUnity.ResourceRedirector;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("Sirdoggy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Updated version of Sideloader with new features")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Sirdoggy.SideloaderMint")]
[assembly: AssemblyTitle("SideloaderMint")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class ParamCollectionAttribute : Attribute
{
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace BepInEx
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
internal sealed class BepInAutoPluginAttribute : Attribute
{
public BepInAutoPluginAttribute(string id = null, string name = null, string version = null)
{
}
}
}
namespace BepInEx.Preloader.Core.Patching
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
internal sealed class PatcherAutoPluginAttribute : Attribute
{
public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null)
{
}
}
}
namespace Sirdoggy.SideloaderMint
{
internal static class Constants
{
public const char AssetSegmentDelimiter = ':';
public const char AddonDirectoryNameSegmentDelimiter = '-';
public const string ManifestFileName = "manifest.json";
public const int HarmonyPriority = 300;
}
internal static class MainAddonLoader
{
private const string AddonFolderName = "SideloaderMint";
private static readonly string LegacyAddonsPath = Path.Combine(Paths.BepInExRootPath, "SideloaderMint");
private static readonly GunSoundLoader GunSoundLoader = new GunSoundLoader();
private static readonly GunAudioSetLoader GunAudioSetLoader = new GunAudioSetLoader();
private static readonly AudioClipLoader AudioClipLoader = new AudioClipLoader();
private static readonly IAssetLoader[] AllAssetLoaders = new IAssetLoader[7]
{
AudioClipLoader,
GunSoundLoader,
GunAudioSetLoader,
new MaterialLoader(),
new MeshLoader(),
new PrefabLoader(),
new TextureLoader()
};
internal static void InitializeAssetLoadersAndLoadAddons()
{
FVRFireArmPatcher.Initialize(GunSoundLoader, GunAudioSetLoader);
AudioSourcePatcher.Initialize(AudioClipLoader);
Plugin.Log.LogMessage((object)"Loading addons...");
List<string> list = new List<string>();
string[] directories;
if (Directory.Exists(LegacyAddonsPath))
{
directories = Directory.GetDirectories(LegacyAddonsPath, "*", SearchOption.TopDirectoryOnly);
foreach (string text in directories)
{
if (File.Exists(Path.Combine(text, "manifest.json")))
{
list.Add(text);
}
}
}
directories = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.TopDirectoryOnly);
for (int i = 0; i < directories.Length; i++)
{
string text2 = Path.Combine(directories[i], "SideloaderMint");
if (!Directory.Exists(text2))
{
continue;
}
if (File.Exists(Path.Combine(text2, "manifest.json")))
{
list.Add(text2);
continue;
}
string[] directories2 = Directory.GetDirectories(text2, "*", SearchOption.TopDirectoryOnly);
foreach (string text3 in directories2)
{
if (File.Exists(Path.Combine(text3, "manifest.json")))
{
list.Add(text3);
}
}
}
Dictionary<string, Addon> dictionary = new Dictionary<string, Addon>();
int num = 0;
foreach (string item in list)
{
try
{
Addon addon = new Addon(item, requireUniqueAddonDirectoryName: false);
if (addon.Manifest.Disabled)
{
Plugin.Log.LogDebug((object)("Skipping '" + addon.Guid + "' because it's disabled in the manifest."));
num++;
}
else if (dictionary.ContainsKey(addon.Guid))
{
Plugin.Log.LogWarning((object)("Skipping '" + addon.Guid + "' because an addon with the same GUID was already loaded."));
}
else
{
dictionary.Add(addon.Guid, addon);
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to load addon from path: " + item + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
}
}
StringBuilder stringBuilder = new StringBuilder().Append($"Loaded {dictionary.Count}/{list.Count} addons!");
if (num > 0)
{
stringBuilder.Append($" {num} addons were skipped because they're set as disabled in their manifest.");
}
Plugin.Log.LogInfo((object)stringBuilder.ToString());
try
{
IAssetLoader[] allAssetLoaders = AllAssetLoaders;
foreach (IAssetLoader assetLoader in allAssetLoaders)
{
Plugin.Log.LogMessage((object)$"Initializing '{assetLoader}'...)'");
assetLoader.Initialize(dictionary.Values);
}
Plugin.Log.LogInfo((object)"Successfully initialized all asset loaders!");
}
catch (Exception ex2)
{
Plugin.Log.LogFatal((object)("An exception has occured while initializing asset loaders, some of your installed addons will likely not work!" + $"\n- Cause: {ex2.GetType()}" + "\n- Message: " + ex2.Message));
}
}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInProcess("h3vr.exe")]
[BepInPlugin("Sirdoggy.SideloaderMint", "SideloaderMint", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Log = null;
internal static readonly PluginConfig PluginConfig = new PluginConfig();
public const string Id = "Sirdoggy.SideloaderMint";
public static string Name => "SideloaderMint";
public static string Version => "1.0.0";
internal static void LogVerbose(string message)
{
if (PluginConfig.VerboseDebugLogs.Value)
{
Log.LogDebug((object)message);
}
}
private void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
ResourceRedirection.EnableSyncOverAsyncAssetLoads();
Harmony.CreateAndPatchAll(typeof(AudioSourcePatcher), (string)null);
Harmony.CreateAndPatchAll(typeof(FVRFireArmPatcher), (string)null);
Harmony.CreateAndPatchAll(typeof(FVRFireArmMagazinePatcher), (string)null);
MainAddonLoader.InitializeAssetLoadersAndLoadAddons();
}
}
internal class PluginConfig
{
private const string ConfigFileName = "Sirdoggy.SideloaderMint.cfg";
public ConfigEntry<bool> VerboseDebugLogs { get; }
public PluginConfig()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "Sirdoggy.SideloaderMint.cfg"), true);
VerboseDebugLogs = val.Bind<bool>("Developer Settings", "VerboseDebugLogs", false, "Enables verbose debug logs. These will noticeably spam the console.");
}
}
}
namespace Sirdoggy.SideloaderMint.Patchers
{
[HarmonyWrapSafe]
[HarmonyPriority(300)]
[HarmonyPatch(typeof(AudioSource))]
internal static class AudioSourcePatcher
{
private static AudioClipLoader? _audioClipLoader;
internal static void Initialize(AudioClipLoader audioClipLoader)
{
_audioClipLoader = audioClipLoader;
}
[HarmonyPrefix]
[HarmonyPatch("Play", new Type[] { typeof(ulong) })]
private static void PlayPrefix(AudioSource __instance)
{
if (!Object.op_Implicit((Object)(object)__instance.clip))
{
return;
}
Plugin.Log.LogDebug((object)$"Attempting to replace AudioClip '{__instance.clip}'");
if (_audioClipLoader == null)
{
Plugin.Log.LogError((object)(string.Format("Did not replace AudioClip '{0}' because '{1}' ", __instance.clip, "AudioSourcePatcher") + "has not been initialized yet."));
return;
}
if (!_audioClipLoader.LoadedAudioClips.TryGetValue(((Object)__instance.clip).name, out AudioClipLoader.AddonEntry value))
{
Plugin.LogVerbose($"Did not replace AudioClip '{__instance.clip}' because it has no " + "replacement sounds.");
return;
}
try
{
int num = new Random().Next(value.AudioClipPaths.Length);
string path = value.AudioClipPaths[num];
AudioClip clip = value.Addon.LoadAudioClip(path, ((Object)__instance.clip).name);
__instance.clip = clip;
float[] volumeRange = value.VolumeRange;
float[] pitchRange = value.PitchRange;
if (volumeRange != null)
{
float volume = Random.Range(volumeRange[0], volumeRange[1]);
__instance.volume = volume;
}
if (pitchRange != null)
{
float pitch = Random.Range(pitchRange[0], pitchRange[1]);
__instance.pitch = pitch;
}
Plugin.Log.LogDebug((object)$"Successfully replaced AudioClip '{__instance.clip}'");
}
catch (Exception ex)
{
Plugin.Log.LogError((object)($"Failed to load AudioClip '{__instance.clip}' from mod '{value.Addon.Guid}'" + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
}
}
}
[HarmonyWrapSafe]
[HarmonyPatch(typeof(FVRFireArmMagazine))]
internal static class FVRFireArmMagazinePatcher
{
[HarmonyPostfix]
[HarmonyPatch("Awake")]
private static void AwakePostfix(FVRFireArmMagazine __instance)
{
if (Object.op_Implicit((Object)(object)((FVRPhysicalObject)__instance).ObjectWrapper))
{
string itemID = ((FVRPhysicalObject)__instance).ObjectWrapper.ItemID;
if (itemID != null)
{
Plugin.Log.LogMessage((object)("A firearm magazine with ItemID '" + itemID + "' has spawned."));
}
}
}
}
[HarmonyWrapSafe]
[HarmonyPriority(300)]
[HarmonyPatch(typeof(FVRFireArm))]
internal static class FVRFireArmPatcher
{
private class HandleMagOverrideSharedState
{
public FVRFireArmMagazine FirearmMagReference { get; }
public bool MagUsesOverride { get; }
public AudioEvent? FirearmMagInClip { get; }
public AudioEvent? FirearmMagOutClip { get; }
public HandleMagOverrideSharedState(FVRFireArmMagazine firearmMagReference, bool magUsesOverride, AudioEvent? firearmMagInClip, AudioEvent? firearmMagOutClip)
{
FirearmMagReference = firearmMagReference;
MagUsesOverride = magUsesOverride;
FirearmMagInClip = firearmMagInClip;
FirearmMagOutClip = firearmMagOutClip;
base..ctor();
}
}
private static GunSoundLoader? _gunSoundLoader;
private static GunAudioSetLoader? _gunAudioSetLoader;
private static readonly string ReplacementAudioClipName = Guid.NewGuid().ToString();
internal static void Initialize(GunSoundLoader gunSoundLoader, GunAudioSetLoader gunAudioSetLoader)
{
_gunSoundLoader = gunSoundLoader;
_gunAudioSetLoader = gunAudioSetLoader;
}
[HarmonyPrefix]
[HarmonyPatch("LoadMag")]
private static void LoadMagPrefix(FVRFireArmMagazine mag, FVRFireArm __instance, ref HandleMagOverrideSharedState? __state)
{
HandleMagOverrideSharedPrefix(mag, __instance, ref __state, GunEvent.Value.MagazineIn);
}
[HarmonyPrefix]
[HarmonyPatch("EjectMag")]
private static void EjectMagPrefix(FVRFireArm __instance, ref HandleMagOverrideSharedState? __state)
{
HandleMagOverrideSharedPrefix(__instance.Magazine, __instance, ref __state, GunEvent.Value.MagazineOut);
}
[HarmonyPostfix]
[HarmonyPatch("LoadMag")]
private static void LoadMagPostfix(FVRFireArmMagazine mag, FVRFireArm __instance, HandleMagOverrideSharedState? __state)
{
HandleMagOverrideSharedPostfix(__instance, __state);
}
[HarmonyPostfix]
[HarmonyPatch("EjectMag")]
private static void EjectMagPostfix(FVRFireArm __instance, HandleMagOverrideSharedState? __state)
{
HandleMagOverrideSharedPostfix(__instance, __state);
}
private static void HandleMagOverrideSharedPrefix(FVRFireArmMagazine magazine, FVRFireArm firearm, ref HandleMagOverrideSharedState? state, GunEvent.Value gunEvent)
{
if (!Object.op_Implicit((Object)(object)magazine) || !Object.op_Implicit((Object)(object)((FVRPhysicalObject)magazine).ObjectWrapper))
{
return;
}
string itemID = ((FVRPhysicalObject)magazine).ObjectWrapper.ItemID;
if (itemID == null)
{
Plugin.Log.LogWarning((object)"[HandleMagOverrideSharedPrefix] Did not replace audio for magazine because its itemID is null.");
}
else
{
if (!Object.op_Implicit((Object)(object)((FVRPhysicalObject)firearm).ObjectWrapper))
{
return;
}
string itemID2 = ((FVRPhysicalObject)firearm).ObjectWrapper.ItemID;
if (itemID2 == null)
{
Plugin.Log.LogWarning((object)("[HandleMagOverrideSharedPrefix] Did not replace audio for magazine with ItemID '" + itemID + "' because its parent firearm has a null ItemID."));
return;
}
if (_gunSoundLoader == null || _gunAudioSetLoader == null)
{
Plugin.Log.LogError((object)"[HandleMagOverrideSharedPrefix] Failed to replace audio for magazine because 'FVRFireArmPatcher' has not been initialized yet.");
return;
}
if (Object.op_Implicit((Object)(object)firearm.AudioClipSet))
{
string name = ((Object)firearm.AudioClipSet).name;
state = new HandleMagOverrideSharedState(magazine, magazine.UsesOverrideInOut, firearm.AudioClipSet.MagazineIn.DeepCopy(), firearm.AudioClipSet.MagazineOut.DeepCopy());
string text = string.Join(':'.ToString(), itemID2, gunEvent.ToString(), itemID);
string text2 = string.Join(':'.ToString(), name, gunEvent.ToString(), itemID);
Plugin.LogVerbose("[HandleMagOverrideSharedPrefix] Attempting to replace firearm magazine audio for '" + text + "' and '" + text2 + "'");
AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel, new string[3]
{
name,
gunEvent.ToString(),
itemID
}).FirstOrDefault();
AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel, new string[3]
{
itemID2,
gunEvent.ToString(),
itemID
}).FirstOrDefault();
try
{
int num;
if (assetNode != null)
{
AddonAsset asset = assetNode.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
string[] paths = assetMapping.Paths;
if (paths != null)
{
num = ((paths.Length > 0) ? 1 : 0);
goto IL_0246;
}
}
}
}
num = 0;
goto IL_0246;
IL_027b:
int num2;
bool flag = (byte)num2 != 0;
if (num == 0 && !flag)
{
Plugin.LogVerbose("[HandleMagOverrideSharedPrefix] Did not replace audio for '" + text + "' and '" + text2 + " because they have no replacement sounds.");
return;
}
Plugin.LogVerbose("[HandleMagOverrideSharedPrefix] Replacing audio for '" + text + "' and " + text2);
magazine.UsesOverrideInOut = false;
if (flag)
{
AddonAsset asset2 = assetNode2.Asset;
firearm.AudioClipSet.ReplaceEntriesInAudioSetByEvent(asset2, gunEvent);
}
else
{
AddonAsset asset3 = assetNode.Asset;
firearm.AudioClipSet.ReplaceEntriesInAudioSetByEvent(asset3, gunEvent);
}
return;
IL_0246:
if (assetNode2 != null)
{
AddonAsset asset = assetNode2.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
string[] paths = assetMapping.Paths;
if (paths != null)
{
num2 = ((paths.Length > 0) ? 1 : 0);
goto IL_027b;
}
}
}
}
num2 = 0;
goto IL_027b;
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("[HandleMagOverrideSharedPrefix] Failed to replace audio for '" + text + "' and '" + text2 + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
return;
}
}
Plugin.Log.LogWarning((object)("[HandleMagOverrideSharedPrefix] Did not replace audio for magazine with ItemID '" + itemID + "' because the AudioClipSet of the parent '" + itemID2 + "' is null."));
}
}
private static void HandleMagOverrideSharedPostfix(FVRFireArm firearm, HandleMagOverrideSharedState? state)
{
if (state != null && Object.op_Implicit((Object)(object)state.FirearmMagReference))
{
Plugin.LogVerbose("[HandleMagOverrideSharedPostfix] Setting UsesOverrideInOut back " + $"to: {state.MagUsesOverride}");
state.FirearmMagReference.UsesOverrideInOut = state.MagUsesOverride;
firearm.AudioClipSet.MagazineIn = state.FirearmMagInClip;
firearm.AudioClipSet.MagazineOut = state.FirearmMagOutClip;
}
}
[HarmonyPostfix]
[HarmonyPatch("Awake")]
private static void AwakePostfix(FVRFireArm __instance)
{
if (!Object.op_Implicit((Object)(object)((FVRPhysicalObject)__instance).ObjectWrapper))
{
return;
}
string itemID = ((FVRPhysicalObject)__instance).ObjectWrapper.ItemID;
if (itemID == null)
{
Plugin.Log.LogWarning((object)"Did not replace audio for firearm because its ItemID is null.");
return;
}
if (_gunSoundLoader == null || _gunAudioSetLoader == null)
{
Plugin.Log.LogError((object)("Failed to replace audio for firearm with ItemID '" + itemID + "' because 'FVRFireArmPatcher' has not been initialized yet."));
return;
}
if (!Object.op_Implicit((Object)(object)__instance.AudioClipSet))
{
Plugin.Log.LogWarning((object)("Did not replace audio for firearm with ItemID '" + itemID + "' because the AudioClipSet of the instance is null."));
return;
}
string name = ((Object)__instance.AudioClipSet).name;
Plugin.Log.LogMessage((object)("Attempting to replace audio for firearm with ItemID '" + itemID + "' and audio set '" + name + "'"));
FVRFirearmAudioSet fvrFirearmAudioSet = (__instance.AudioClipSet = __instance.AudioClipSet.DeepCopy());
GunEvent.Value[] all = GunEvent.All;
for (int i = 0; i < all.Length; i++)
{
GunEvent.Value gunEvent = all[i];
string text = itemID + ":" + gunEvent;
string text2 = name + ":" + gunEvent;
Plugin.LogVerbose("Attempting to replace firearm audio for '" + text + "' and '" + text2 + "'");
AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQuery, new string[2]
{
name,
gunEvent.ToString()
}).FirstOrDefault();
AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQuery, new string[2]
{
itemID,
gunEvent.ToString()
}).FirstOrDefault();
try
{
int num;
if (assetNode != null)
{
AddonAsset asset = assetNode.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
string[] paths = assetMapping.Paths;
if (paths != null)
{
num = ((paths.Length > 0) ? 1 : 0);
goto IL_01f1;
}
}
}
}
num = 0;
goto IL_01f1;
IL_0226:
int num2;
bool flag = (byte)num2 != 0;
if (num == 0 && !flag)
{
Plugin.LogVerbose("Did not replace audio for '" + text + "' and '" + text2 + " because they have no replacement sounds.");
}
else if (flag)
{
AddonAsset asset2 = assetNode2.Asset;
fvrFirearmAudioSet.ReplaceEntriesInAudioSetByEvent(asset2, gunEvent);
}
else
{
AddonAsset asset3 = assetNode.Asset;
fvrFirearmAudioSet.ReplaceEntriesInAudioSetByEvent(asset3, gunEvent);
}
goto end_IL_01bc;
IL_01f1:
if (assetNode2 != null)
{
AddonAsset asset = assetNode2.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
string[] paths = assetMapping.Paths;
if (paths != null)
{
num2 = ((paths.Length > 0) ? 1 : 0);
goto IL_0226;
}
}
}
}
num2 = 0;
goto IL_0226;
end_IL_01bc:;
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to replace audio for '" + text + "' and '" + text2 + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
}
}
}
private static void ReplaceEntriesInAudioSetByEvent(this FVRFirearmAudioSet fvrFirearmAudioSet, AddonAsset addonAsset, GunEvent.Value gunEvent)
{
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
AddonAsset addonAsset2 = addonAsset;
AudioEvent gunEventBy = fvrFirearmAudioSet.GetGunEventBy(gunEvent);
List<AudioClip> clips = addonAsset2.AssetMapping.Paths.Select((string path) => addonAsset2.SourceAddon.LoadAudioClip(path, ReplacementAudioClipName)).ToList();
gunEventBy.Clips = clips;
float[] array = (addonAsset2.AssetMapping as AddonManifest.AssetMapping.Audio)?.VolumeRange;
float[] array2 = (addonAsset2.AssetMapping as AddonManifest.AssetMapping.Audio)?.PitchRange;
if (array != null)
{
Vector2 volumeRange = default(Vector2);
((Vector2)(ref volumeRange))..ctor(array[0], array[1]);
gunEventBy.VolumeRange = volumeRange;
}
if (array2 != null)
{
Vector2 pitchRange = default(Vector2);
((Vector2)(ref pitchRange))..ctor(array2[0], array2[1]);
gunEventBy.PitchRange = pitchRange;
}
}
}
}
namespace Sirdoggy.SideloaderMint.Common
{
internal static class StreamExtensions
{
public static void CopyTo(this Stream from, Stream to)
{
byte[] array = new byte[4096];
int count;
while ((count = from.Read(array, 0, array.Length)) > 0)
{
to.Write(array, 0, count);
}
}
}
internal static class StringUtils
{
public static string FormatTypeProperties<T>(string nameOfType, [ParamCollection] IEnumerable<T> properties)
{
if (properties is string)
{
return $"{nameOfType}({properties})";
}
return nameOfType + "(" + JoinValues(properties) + ")";
}
public static string JoinValues<T>(IEnumerable<T> values, string seperator = ", ")
{
string[] value = values.Select((T element) => element?.ToString()).ToArray();
return string.Join(seperator, value);
}
}
public class WavUtility
{
private class BitReader
{
public int SizeOf { get; set; }
public Func<BinaryReader, float> Reader { get; set; }
public int MaxValue { get; set; }
}
private static readonly Dictionary<int, BitReader> readers = new Dictionary<int, BitReader>
{
[8] = new BitReader
{
MaxValue = 127,
SizeOf = 1,
Reader = (BinaryReader br) => br.ReadSByte()
},
[16] = new BitReader
{
MaxValue = 32767,
SizeOf = 2,
Reader = (BinaryReader br) => br.ReadInt16()
},
[24] = new BitReader
{
MaxValue = int.MaxValue,
SizeOf = 3,
Reader = delegate(BinaryReader br)
{
byte[] array = new byte[4];
br.Read(array, 1, 3);
return BitConverter.ToInt32(array, 0);
}
},
[32] = new BitReader
{
MaxValue = int.MaxValue,
SizeOf = 4,
Reader = (BinaryReader br) => br.ReadInt32()
}
};
public static AudioClip ToAudioClip(BinaryReader br, string name = "wav")
{
br.BaseStream.Position = 16L;
int num = br.ReadInt32();
ushort num2 = br.ReadUInt16();
string arg = FormatCode(num2);
if (num2 != 1 && num2 != 65534)
{
throw new Exception($"Detected format code '{arg}' ({num2}), but only PCM and WaveFormatExtensable uncompressed formats are currently supported.");
}
ushort num3 = br.ReadUInt16();
int num4 = br.ReadInt32();
br.ReadInt32();
br.ReadUInt16();
ushort key = br.ReadUInt16();
br.BaseStream.Position = 20 + num + 4;
int dataSize = br.ReadInt32();
if (readers.TryGetValue(key, out BitReader value))
{
float[] array = ReadAudioClipSamples(br, value, dataSize);
AudioClip obj = AudioClip.Create(name, array.Length, (int)num3, num4, false);
obj.SetData(array, 0);
return obj;
}
throw new Exception(key + " bit depth is not supported.");
}
private static float[] ReadAudioClipSamples(BinaryReader br, BitReader reader, int dataSize)
{
float[] array = new float[dataSize / reader.SizeOf];
for (int i = 0; i < array.Length; i++)
{
array[i] = reader.Reader(br) / (float)reader.MaxValue;
}
return array;
}
private static string FormatCode(ushort code)
{
switch (code)
{
case 1:
return "PCM";
case 2:
return "ADPCM";
case 3:
return "IEEE";
case 7:
return "μ-law";
case 65534:
return "WaveFormatExtensable";
default:
Debug.LogWarning((object)("Unknown wav code format:" + code));
return "";
}
}
}
}
namespace Sirdoggy.SideloaderMint.Common.Validation
{
internal static class PathValidator
{
public static void Validate(string basePath, string relativePath)
{
string fullPath = Path.GetFullPath(basePath);
if (!Path.GetFullPath(Path.Combine(fullPath, relativePath)).StartsWith(fullPath, StringComparison.OrdinalIgnoreCase))
{
throw new UnauthorizedAccessException("Path '" + relativePath + "' is not allowed to access resource outside of its base path '" + basePath + "'");
}
}
}
internal static class StrictDeserializer
{
private static readonly JsonSerializer Serializer = JsonSerializer.Create(new JsonSerializerSettings
{
MissingMemberHandling = (MissingMemberHandling)1
});
public static T Deserialize<T>(JObject jObject)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
JsonReader val = ((JToken)jObject).CreateReader();
T val2 = Serializer.Deserialize<T>(val);
if (val2 == null)
{
throw new JsonSerializationException("Deserialization failed");
}
return val2;
}
}
}
namespace Sirdoggy.SideloaderMint.Common.Structures
{
public class AssetTree<TAsset>
{
public enum FindBehaviour
{
GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment,
GetMostSpecificThatMatchesQuery,
GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel
}
public interface INode
{
int Level { get; }
}
public abstract class TraversableNode : INode
{
public abstract int Level { get; }
public List<INode> Children { get; } = new List<INode>();
protected abstract string ReadableName { get; }
protected abstract string[] ReadableProperties { get; }
public override string ToString()
{
string value = StringUtils.FormatTypeProperties(ReadableName, ReadableProperties);
StringBuilder stringBuilder = new StringBuilder().Append(' ', Level * 2 + 2).Append((Level == 0) ? " " : "└─").Append(value);
foreach (INode child in Children)
{
stringBuilder.Append($"\n{child}");
}
return stringBuilder.ToString();
}
}
public sealed class RootNode : TraversableNode
{
public override int Level => 0;
protected override string ReadableName => "RootNode";
protected override string[] ReadableProperties => new string[1] { string.Format("{0}: {1}", "Level", Level) };
}
public sealed class IntermediateNode : TraversableNode
{
public override int Level { get; }
public string? TargetSegment { get; }
protected override string ReadableName => "IntermediateNode";
protected override string[] ReadableProperties => new string[2]
{
string.Format("{0}: {1}", "Level", Level),
"TargetSegment: " + (TargetSegment ?? "*")
};
public IntermediateNode(int level, string? targetSegment)
{
Level = level;
TargetSegment = targetSegment;
base..ctor();
}
}
public sealed class AssetNode : INode
{
public int Level { get; }
public TAsset Asset { get; }
public string? FinalTargetSegment { get; }
public AssetNode(int level, TAsset asset, string? finalTargetSegment)
{
Level = level;
Asset = asset;
FinalTargetSegment = finalTargetSegment;
base..ctor();
}
public override string ToString()
{
string value = StringUtils.FormatTypeProperties("AssetNode", new <>z__ReadOnlyArray<string>(new string[3]
{
string.Format("{0}: {1}", "Level", Level),
string.Format("{0}: {1}", "Asset", Asset),
"FinalTargetSegment: " + (FinalTargetSegment ?? "null")
}));
return new StringBuilder().Append(' ', Level * 2 + 2).Append("└─").Append(value)
.ToString();
}
}
[CompilerGenerated]
private int <maxIntermediateLevels>P;
private readonly RootNode _rootNode;
public AssetTree(int maxIntermediateLevels)
{
<maxIntermediateLevels>P = maxIntermediateLevels;
_rootNode = new RootNode();
base..ctor();
}
public void AddAssetToTree(string target, TAsset asset, bool parseAsterisksAsWildcards = true)
{
string[] array = (from part in target.Split(new char[1] { ':' })
select part.Trim() into part
select (part.Length != 0) ? part : null).Reverse().SkipWhile((string part) => part == null).Reverse()
.ToArray();
if (parseAsterisksAsWildcards)
{
array = array.Select((string part) => (!(part == "*")) ? part : null).ToArray();
}
if (array.Length > <maxIntermediateLevels>P)
{
throw new ArgumentException("Can't add asset to AssetTree because target '" + target + "' consists " + $"of more than {<maxIntermediateLevels>P} segments.");
}
TraversableNode traversableNode = _rootNode;
string[] array2 = array;
foreach (string segment in array2)
{
IntermediateNode intermediateNode = traversableNode.Children.Where((INode node) => node is IntermediateNode).Cast<IntermediateNode>().FirstOrDefault((IntermediateNode node) => node.TargetSegment == segment);
if (intermediateNode == null)
{
intermediateNode = new IntermediateNode(traversableNode.Level + 1, segment);
traversableNode.Children.Add(intermediateNode);
}
traversableNode = intermediateNode;
}
AssetNode item = new AssetNode(traversableNode.Level + 1, asset, (array.Length == <maxIntermediateLevels>P && <maxIntermediateLevels>P > 0) ? array[<maxIntermediateLevels>P - 1] : null);
traversableNode.Children.Add(item);
}
public AssetNode[] Find(FindBehaviour behaviour, params string[] segmentedQuery)
{
string[] segmentedQuery2 = segmentedQuery;
AssetNode[] array = SearchIntermediateNodesInNode(_rootNode);
if (array.Length != 0)
{
return array;
}
if (behaviour == FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel && segmentedQuery2.Length != 0)
{
return new AssetNode[0];
}
return _rootNode.Children.Where((INode node) => node is AssetNode).Cast<AssetNode>().ToArray();
static void CollectAllChildNodesFromCurrent(TraversableNode currentNode, List<AssetNode> collectedAssetNodes)
{
foreach (INode child in currentNode.Children)
{
if (!(child is AssetNode item))
{
if (child is TraversableNode currentNode2)
{
CollectAllChildNodesFromCurrent(currentNode2, collectedAssetNodes);
}
}
else
{
collectedAssetNodes.Add(item);
}
}
}
AssetNode[] FindInIntermediateLevel(IntermediateNode nodeToSearch)
{
string text = ((nodeToSearch.Level <= segmentedQuery2.Length) ? segmentedQuery2[nodeToSearch.Level - 1] : null);
if (nodeToSearch.TargetSegment != null && nodeToSearch.TargetSegment != text)
{
return new AssetNode[0];
}
if (behaviour == FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment && nodeToSearch.Level >= segmentedQuery2.Length)
{
List<AssetNode> list = new List<AssetNode>();
CollectAllChildNodesFromCurrent(nodeToSearch, list);
return list.ToArray();
}
AssetNode[] array2 = SearchIntermediateNodesInNode(nodeToSearch);
if (array2.Length != 0)
{
return array2;
}
if (behaviour == FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel && nodeToSearch.Level <= segmentedQuery2.Length - 1)
{
return new AssetNode[0];
}
return nodeToSearch.Children.Where((INode node) => node is AssetNode).Cast<AssetNode>().ToArray();
}
AssetNode[] SearchIntermediateNodesInNode(TraversableNode nodeToSearch)
{
foreach (IntermediateNode item2 in from IntermediateNode node in nodeToSearch.Children.Where((INode node) => node is IntermediateNode)
where node.TargetSegment != null
select node)
{
AssetNode[] array3 = FindInIntermediateLevel(item2);
if (array3.Length != 0)
{
return array3;
}
}
foreach (IntermediateNode item3 in from IntermediateNode node in nodeToSearch.Children.Where((INode node) => node is IntermediateNode)
where node.TargetSegment == null
select node)
{
AssetNode[] array4 = FindInIntermediateLevel(item3);
if (array4.Length != 0)
{
return array4;
}
}
return new AssetNode[0];
}
}
public override string ToString()
{
return string.Format("AssetTree({0}: {1})", "maxIntermediateLevels", <maxIntermediateLevels>P) + $"\n{_rootNode}";
}
}
}
namespace Sirdoggy.SideloaderMint.Common.FVR
{
internal static class AudioEventExtensions
{
public static AudioEvent? DeepCopy(this AudioEvent? original)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Expected O, but got Unknown
if (original == null)
{
return null;
}
AudioEvent val = (AudioEvent)FormatterServices.GetUninitializedObject(typeof(AudioEvent));
val.Clips = ((original.Clips != null) ? original.Clips.ToList() : null);
val.VolumeRange = original.VolumeRange;
val.PitchRange = original.PitchRange;
val.ClipLengthRange = original.ClipLengthRange;
return val;
}
}
internal static class FVRFirearmAudioSetExtensions
{
public static FVRFirearmAudioSet DeepCopy(this FVRFirearmAudioSet original)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
FVRFirearmAudioSet obj = ScriptableObject.CreateInstance<FVRFirearmAudioSet>();
((Object)obj).name = ((Object)original).name;
((Object)obj).hideFlags = ((Object)original).hideFlags;
obj.Loudness_Primary = original.Loudness_Primary;
obj.Loudness_Suppressed = original.Loudness_Suppressed;
obj.Loudness_OperationMult = original.Loudness_OperationMult;
obj.FTP = original.FTP;
obj.Shots_Main = original.Shots_Main.DeepCopy();
obj.Shots_Suppressed = original.Shots_Suppressed.DeepCopy();
obj.Shots_LowPressure = original.Shots_LowPressure.DeepCopy();
obj.TailPitchMod_Main = original.TailPitchMod_Main;
obj.TailPitchMod_Suppressed = original.TailPitchMod_Suppressed;
obj.TailPitchMod_LowPressure = original.TailPitchMod_LowPressure;
obj.TailConcurrentLimit = original.TailConcurrentLimit;
obj.UsesTail_Main = original.UsesTail_Main;
obj.UsesTail_Suppressed = original.UsesTail_Suppressed;
obj.UsesLowPressureSet = original.UsesLowPressureSet;
obj.BoltRelease = original.BoltRelease.DeepCopy();
obj.BoltSlideBack = original.BoltSlideBack.DeepCopy();
obj.BoltSlideBackHeld = original.BoltSlideBackHeld.DeepCopy();
obj.BoltSlideBackLocked = original.BoltSlideBackLocked.DeepCopy();
obj.BoltSlideForward = original.BoltSlideForward.DeepCopy();
obj.BoltSlideForwardHeld = original.BoltSlideForwardHeld.DeepCopy();
obj.BreachOpen = original.BreachOpen.DeepCopy();
obj.BreachClose = original.BreachClose.DeepCopy();
obj.BeltBulletSet = original.BeltBulletSet.DeepCopy();
obj.CatchOnSear = original.CatchOnSear.DeepCopy();
obj.ChamberManual = original.ChamberManual.DeepCopy();
obj.FireSelector = original.FireSelector.DeepCopy();
obj.HammerHit = original.HammerHit.DeepCopy();
obj.HandleBack = original.HandleBack.DeepCopy();
obj.HandleBackEmpty = original.HandleBackEmpty.DeepCopy();
obj.HandleForward = original.HandleForward.DeepCopy();
obj.HandleForwardEmpty = original.HandleForwardEmpty.DeepCopy();
obj.HandleUp = original.HandleUp.DeepCopy();
obj.HandleDown = original.HandleDown.DeepCopy();
obj.HandleGrab = original.HandleGrab.DeepCopy();
obj.MagazineIn = original.MagazineIn.DeepCopy();
obj.MagazineOut = original.MagazineOut.DeepCopy();
obj.MagazineInsertRound = original.MagazineInsertRound.DeepCopy();
obj.MagazineEjectRound = original.MagazineEjectRound.DeepCopy();
obj.Prefire = original.Prefire.DeepCopy();
obj.Safety = original.Safety.DeepCopy();
obj.TriggerReset = original.TriggerReset.DeepCopy();
obj.TopCoverRelease = original.TopCoverRelease.DeepCopy();
obj.TopCoverUp = original.TopCoverUp.DeepCopy();
obj.TopCoverDown = original.TopCoverDown.DeepCopy();
obj.StockOpen = original.StockOpen.DeepCopy();
obj.StockClosed = original.StockClosed.DeepCopy();
obj.BipodOpen = original.BipodOpen.DeepCopy();
obj.BipodClosed = original.BipodClosed.DeepCopy();
obj.BeltGrab = original.BeltGrab.DeepCopy();
obj.BeltRelease = original.BeltRelease.DeepCopy();
obj.BeltSeat = original.BeltSeat.DeepCopy();
obj.BeltSettle = original.BeltSettle.DeepCopy();
obj.BeltSettlingLimit = original.BeltSettlingLimit;
return obj;
}
public static AudioEvent GetGunEventBy(this FVRFirearmAudioSet clipSet, GunEvent.Value gunEvent)
{
return (AudioEvent)(gunEvent switch
{
GunEvent.Value.Shot => clipSet.Shots_Main,
GunEvent.Value.ShotSuppressed => clipSet.Shots_Suppressed,
GunEvent.Value.ShotLowPressure => clipSet.Shots_LowPressure,
GunEvent.Value.BoltRelease => clipSet.BoltRelease,
GunEvent.Value.BoltSlideBack => clipSet.BoltSlideBack,
GunEvent.Value.BoltSlideBackHeld => clipSet.BoltSlideBackHeld,
GunEvent.Value.BoltSlideBackLocked => clipSet.BoltSlideBackLocked,
GunEvent.Value.BoltSlideForward => clipSet.BoltSlideForward,
GunEvent.Value.BoltSlideForwardHeld => clipSet.BoltSlideForwardHeld,
GunEvent.Value.BreachOpen => clipSet.BreachOpen,
GunEvent.Value.BreachClose => clipSet.BreachClose,
GunEvent.Value.BeltBulletSet => clipSet.BeltBulletSet,
GunEvent.Value.CatchOnSear => clipSet.CatchOnSear,
GunEvent.Value.ChamberManual => clipSet.ChamberManual,
GunEvent.Value.FireSelector => clipSet.FireSelector,
GunEvent.Value.HammerHit => clipSet.HammerHit,
GunEvent.Value.HandleBack => clipSet.HandleBack,
GunEvent.Value.HandleBackEmpty => clipSet.HandleBackEmpty,
GunEvent.Value.HandleForward => clipSet.HandleForward,
GunEvent.Value.HandleForwardEmpty => clipSet.HandleForwardEmpty,
GunEvent.Value.HandleUp => clipSet.HandleUp,
GunEvent.Value.HandleDown => clipSet.HandleDown,
GunEvent.Value.HandleGrab => clipSet.HandleGrab,
GunEvent.Value.MagazineOut => clipSet.MagazineOut,
GunEvent.Value.MagazineIn => clipSet.MagazineIn,
GunEvent.Value.MagazineInsertRound => clipSet.MagazineInsertRound,
GunEvent.Value.MagazineEjectRound => clipSet.MagazineEjectRound,
GunEvent.Value.Prefire => clipSet.Prefire,
GunEvent.Value.Safety => clipSet.Safety,
GunEvent.Value.TriggerReset => clipSet.TriggerReset,
GunEvent.Value.TopCoverRelease => clipSet.TopCoverRelease,
GunEvent.Value.TopCoverUp => clipSet.TopCoverUp,
GunEvent.Value.TopCoverDown => clipSet.TopCoverDown,
GunEvent.Value.StockOpen => clipSet.StockOpen,
GunEvent.Value.StockClosed => clipSet.StockClosed,
GunEvent.Value.BipodOpen => clipSet.BipodOpen,
GunEvent.Value.BipodClosed => clipSet.BipodClosed,
GunEvent.Value.BeltGrab => clipSet.BeltGrab,
GunEvent.Value.BeltRelease => clipSet.BeltRelease,
GunEvent.Value.BeltSeat => clipSet.BeltSeat,
GunEvent.Value.BeltSettle => clipSet.BeltSettle,
_ => throw new NotSupportedException("Unknown GunEvent"),
});
}
}
internal static class FVRFirearmMagazineAudioSetExtensions
{
public static FVRFirearmMagazineAudioSet DeepCopy(this FVRFirearmMagazineAudioSet original)
{
FVRFirearmMagazineAudioSet obj = ScriptableObject.CreateInstance<FVRFirearmMagazineAudioSet>();
obj.MagazineIn = original.MagazineIn.DeepCopy();
obj.MagazineOut = original.MagazineOut.DeepCopy();
obj.MagazineInsertRound = original.MagazineInsertRound.DeepCopy();
obj.MagazineEjectRound = original.MagazineEjectRound.DeepCopy();
return obj;
}
}
internal static class GunEvent
{
public enum Value
{
Shot,
ShotSuppressed,
ShotLowPressure,
BoltRelease,
BoltSlideBack,
BoltSlideBackHeld,
BoltSlideBackLocked,
BoltSlideForward,
BoltSlideForwardHeld,
BreachOpen,
BreachClose,
BeltBulletSet,
CatchOnSear,
ChamberManual,
FireSelector,
HammerHit,
HandleBack,
HandleBackEmpty,
HandleForward,
HandleForwardEmpty,
HandleUp,
HandleDown,
HandleGrab,
MagazineIn,
MagazineOut,
MagazineInsertRound,
MagazineEjectRound,
Prefire,
Safety,
TriggerReset,
TopCoverRelease,
TopCoverUp,
TopCoverDown,
StockOpen,
StockClosed,
BipodOpen,
BipodClosed,
BeltGrab,
BeltRelease,
BeltSeat,
BeltSettle
}
public static readonly Value[] All = Enum.GetValues(typeof(Value)).Cast<Value>().ToArray();
}
}
namespace Sirdoggy.SideloaderMint.Common.Coroutines
{
internal class CoroutineRunner : MonoBehaviour
{
private static CoroutineRunner _instance;
public static Coroutine Run(IEnumerator coroutine)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Expected O, but got Unknown
if (!Object.op_Implicit((Object)(object)_instance))
{
GameObject val = new GameObject("CoroutineRunner")
{
hideFlags = (HideFlags)61
};
Object.DontDestroyOnLoad((Object)val);
_instance = val.AddComponent<CoroutineRunner>();
}
return ((MonoBehaviour)_instance).StartCoroutine(coroutine);
}
}
}
namespace Sirdoggy.SideloaderMint.AssetLoaders
{
internal class AddonAsset
{
public AddonManifest.AssetMapping AssetMapping { get; }
public Addon SourceAddon { get; }
public AddonAsset(AddonManifest.AssetMapping assetMapping, Addon addon)
{
AssetMapping = assetMapping;
SourceAddon = addon;
base..ctor();
}
}
internal interface IAssetLoader
{
void Initialize(IEnumerable<Addon> addons);
}
}
namespace Sirdoggy.SideloaderMint.AssetLoaders.Implementations
{
internal class AudioClipLoader : IAssetLoader
{
internal class AddonEntry
{
public Addon Addon { get; }
public string[] AudioClipPaths { get; }
public float[]? VolumeRange { get; }
public float[]? PitchRange { get; }
public AddonEntry(Addon addon, string[] audioClipPaths, float[]? volumeRange, float[]? pitchRange)
{
Addon = addon;
AudioClipPaths = audioClipPaths;
VolumeRange = volumeRange;
PitchRange = pitchRange;
base..ctor();
}
}
internal readonly Dictionary<string, AddonEntry> LoadedAudioClips = new Dictionary<string, AddonEntry>(StringComparer.OrdinalIgnoreCase);
public void Initialize(IEnumerable<Addon> addons)
{
foreach (Addon addon in addons)
{
foreach (AddonManifest.AssetMapping item in addon.Manifest.AssetMappings.Where((AddonManifest.AssetMapping assetMapping) => assetMapping.AssetType == AddonManifest.AssetType.AudioClip))
{
float[] volumeRange = (item as AddonManifest.AssetMapping.Audio)?.VolumeRange;
float[] pitchRange = (item as AddonManifest.AssetMapping.Audio)?.PitchRange;
AddonEntry value = new AddonEntry(addon, item.Paths, volumeRange, pitchRange);
string[] targets = item.Targets;
foreach (string text in targets)
{
if (LoadedAudioClips.TryGetValue(text, out AddonEntry value2))
{
Plugin.Log.LogWarning((object)("[" + addon.Guid + "] AudioClip " + text + " is already replaced by '" + value2.Addon.Guid + "', skipping."));
}
else
{
LoadedAudioClips[text] = value;
}
}
}
}
}
}
internal abstract class BaseAssetTreeLoader : IAssetLoader
{
protected abstract AddonManifest.AssetType SupportedAssetType { get; }
protected abstract int TargetSegmentsCount { get; }
internal AssetTree<AddonAsset>? AssetTree { get; private set; }
public virtual void Initialize(IEnumerable<Addon> addons)
{
AssetTree = new AssetTree<AddonAsset>(TargetSegmentsCount);
foreach (Addon addon in addons)
{
AddAssetsFromAddon(addon);
}
}
private void AddAssetsFromAddon(Addon addon)
{
Addon addon2 = addon;
foreach (AddonManifest.AssetMapping item in addon2.Manifest.AssetMappings.Where((AddonManifest.AssetMapping mapping) => mapping.AssetType == SupportedAssetType))
{
try
{
if (item.Paths.Length == 0)
{
throw new ArgumentException("Asset mapping in '" + addon2.Guid + "' for target " + $"'{item.Targets}' has no asset paths.");
}
string assetPath;
using IEnumerator<string> enumerator2 = item.Paths.Where((string path) => !addon2.FileExists(addon2.GetAssetPath(path, out assetPath))).GetEnumerator();
if (enumerator2.MoveNext())
{
string current2 = enumerator2.Current;
throw new FileNotFoundException($"[{addon2.Guid}] Asset '{current2}' of type '{SupportedAssetType}' could " + "not be resolved.");
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to add assets from addon: " + addon2.Guid + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
continue;
}
AddonAsset asset = new AddonAsset(item, addon2);
string[] targets = item.Targets;
foreach (string target in targets)
{
AssetTree?.AddAssetToTree(target, asset, addon2.Manifest.UsesAsterisksAsWildcardsInTargetField());
}
}
}
}
internal class GunAudioSetLoader : BaseAssetTreeLoader
{
protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.GunAudioSet;
protected override int TargetSegmentsCount => 3;
}
internal class GunSoundLoader : BaseAssetTreeLoader
{
protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.GunSound;
protected override int TargetSegmentsCount => 3;
}
internal class MaterialLoader : BaseAssetTreeLoader
{
private static readonly string[] MaterialPathSchema = new string[2] { "prefabPath", "materialName" };
protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.Material;
protected override int TargetSegmentsCount { get; } = MaterialPathSchema.Length;
public override void Initialize(IEnumerable<Addon> addons)
{
base.Initialize(addons);
ResourceRedirection.RegisterAssetLoadedHook((HookBehaviour)2, 100, (Action<AssetLoadedContext>)PatchLoadedAsset);
}
private void PatchLoadedAsset(AssetLoadedContext ctx)
{
Object[] assets = ctx.Assets;
foreach (Object val in assets)
{
string uniqueFileSystemAssetPath = ctx.GetUniqueFileSystemAssetPath(val);
GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null);
if (val2 != null)
{
ReplaceMaterials(val2, uniqueFileSystemAssetPath);
}
}
}
private void ReplaceMaterials(GameObject go, string path)
{
MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>();
foreach (MeshRenderer val in componentsInChildren)
{
Material[] materials = ((Renderer)val).materials;
if (materials == null)
{
continue;
}
for (int j = 0; j < materials.Length; j++)
{
string text = ((Object)materials[j]).name.Replace(" (Instance)", "");
Plugin.LogVerbose("Material: " + string.Join(":", path, text));
AssetTree<AddonAsset>.AssetNode assetNode = base.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment, new string[2] { path, text }).FirstOrDefault();
if (assetNode != null)
{
materials[j] = assetNode.Asset.SourceAddon.LoadMaterial(assetNode.Asset.AssetMapping.Paths.First());
}
}
((Renderer)val).materials = materials;
}
}
}
internal class MeshLoader : BaseAssetTreeLoader
{
private static readonly string[] MeshPathSchema = new string[3] { "prefabPath", "meshContainerName", "meshName" };
protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.Mesh;
protected override int TargetSegmentsCount { get; } = MeshPathSchema.Length;
public override void Initialize(IEnumerable<Addon> addons)
{
base.Initialize(addons);
ResourceRedirection.RegisterAssetLoadedHook((HookBehaviour)2, (Action<AssetLoadedContext>)PatchLoadedAsset);
}
private void PatchLoadedAsset(AssetLoadedContext ctx)
{
Object[] assets = ctx.Assets;
foreach (Object val in assets)
{
string uniqueFileSystemAssetPath = ctx.GetUniqueFileSystemAssetPath(val);
GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null);
if (val2 != null)
{
ReplaceMeshes(val2, uniqueFileSystemAssetPath);
}
}
}
private void ReplaceMeshes(GameObject go, string path)
{
MeshFilter[] componentsInChildren = go.GetComponentsInChildren<MeshFilter>();
foreach (MeshFilter val in componentsInChildren)
{
string name = ((Object)val).name;
string text = ((Object)val.mesh).name.Replace(" Instance", "");
Plugin.LogVerbose("Mesh: " + string.Join(":", path, name, text));
AssetTree<AddonAsset>.AssetNode assetNode = base.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment, new string[3] { path, name, text }).FirstOrDefault();
if (assetNode != null)
{
val.mesh = assetNode.Asset.SourceAddon.LoadMesh(assetNode.Asset.AssetMapping.Paths.First());
}
}
}
}
internal class PrefabLoader : IAssetLoader
{
private readonly Dictionary<string, Addon> _prefabReplacements = new Dictionary<string, Addon>();
public void Initialize(IEnumerable<Addon> addons)
{
foreach (Addon addon in addons)
{
RegisterPrefabReplacements(addon);
}
ResourceRedirection.RegisterAsyncAndSyncAssetLoadingHook(500, (Action<IAssetLoadingContext>)ReplacePrefab);
}
private void ReplacePrefab(IAssetLoadingContext ctx)
{
string text = (ctx.GetNormalizedAssetBundlePath() + "\\" + ctx.Parameters.Name).ToLowerInvariant();
if (_prefabReplacements.TryGetValue(text, out Addon value))
{
ctx.Asset = (Object)(object)value.LoadPrefab(text);
bool? flag = false;
ctx.Complete(true, (bool?)true, flag);
}
}
private void RegisterPrefabReplacements(Addon addon)
{
foreach (AddonManifest.AssetMapping item in addon.Manifest.AssetMappings.Where((AddonManifest.AssetMapping assetMapping) => assetMapping.AssetType == AddonManifest.AssetType.Prefab))
{
if (!addon.FileExists(addon.GetAssetPath(item.Paths.First(), out string _)))
{
Plugin.Log.LogWarning((object)("[" + addon.Guid + "] Asset '" + item.Paths.First() + "' of type " + $"'{AddonManifest.AssetType.Prefab}' does not exist in the mod, skipping."));
}
string[] targets = item.Targets;
foreach (string text in targets)
{
if (_prefabReplacements.TryGetValue(text, out Addon value))
{
Plugin.Log.LogWarning((object)("[" + addon.Guid + "] prefab " + text + " is already being replaced by '" + value.Guid + "', skipping."));
}
else
{
_prefabReplacements[text] = addon;
}
}
}
}
}
internal class TextureLoader : BaseAssetTreeLoader
{
private static readonly string[] TexturePathSchema = new string[4] { "prefabPath", "materialName", "textureName", "materialParameter" };
protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.Texture;
protected override int TargetSegmentsCount { get; } = TexturePathSchema.Length;
public override void Initialize(IEnumerable<Addon> addons)
{
base.Initialize(addons);
ResourceRedirection.RegisterAssetLoadedHook((HookBehaviour)2, (Action<AssetLoadedContext>)PatchLoadedAsset);
ResourceRedirection.RegisterResourceLoadedHook((HookBehaviour)2, (Action<ResourceLoadedContext>)PatchLoadedResource);
}
private void PatchLoadedResource(ResourceLoadedContext ctx)
{
Plugin.LogVerbose($"Loaded resource to load resource {ctx.Parameters.Path}, {ctx.Parameters.Type}");
Object[] assets = ctx.Assets;
foreach (Object val in assets)
{
string uniqueFileSystemAssetPath = ctx.GetUniqueFileSystemAssetPath(val);
ItemSpawnerID val2 = (ItemSpawnerID)(object)((val is ItemSpawnerID) ? val : null);
if (val2 != null)
{
ReplaceItemSpawnerIcon(val2, uniqueFileSystemAssetPath);
}
}
}
private void ReplaceItemSpawnerIcon(ItemSpawnerID itemSpawnerId, string path)
{
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)itemSpawnerId.Sprite))
{
Plugin.LogVerbose("ItemSpawnerID Icon: " + string.Join(":", path, ((Object)itemSpawnerId.Sprite).name, ((Object)itemSpawnerId.Sprite.texture).name));
AssetTree<AddonAsset>.AssetNode assetNode = base.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment, new string[3]
{
path,
((Object)itemSpawnerId.Sprite).name,
((Object)itemSpawnerId.Sprite.texture).name
}).FirstOrDefault();
if (assetNode != null)
{
Sprite sprite = Sprite.Create(assetNode.Asset.SourceAddon.LoadTexture(assetNode.Asset.AssetMapping.Paths.First()), itemSpawnerId.Sprite.rect, itemSpawnerId.Sprite.pivot, itemSpawnerId.Sprite.pixelsPerUnit, 0u, (SpriteMeshType)1, itemSpawnerId.Sprite.border);
itemSpawnerId.Sprite = sprite;
}
}
}
private void PatchLoadedAsset(AssetLoadedContext ctx)
{
Object[] assets = ctx.Assets;
foreach (Object val in assets)
{
string uniqueFileSystemAssetPath = ctx.GetUniqueFileSystemAssetPath(val);
GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null);
if (val2 != null)
{
ReplaceTextures(val2, uniqueFileSystemAssetPath);
}
}
}
private void ReplaceTextures(GameObject go, string path)
{
MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>();
foreach (MeshRenderer val in componentsInChildren)
{
Material[] materials = ((Renderer)val).materials;
if (materials == null)
{
continue;
}
Material[] array = materials;
foreach (Material val2 in array)
{
string text = ((Object)val2).name.Replace("(Instance)", "").Trim();
string text2 = (Object.op_Implicit((Object)(object)val2.mainTexture) ? ((Object)val2.mainTexture).name : "NULL");
Plugin.LogVerbose("Texture: " + string.Join(":", path, text, text2));
AssetTree<AddonAsset>.AssetNode[] array2 = base.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment, new string[3] { path, text, text2 });
if (array2 == null || array2.Length == 0)
{
continue;
}
AssetTree<AddonAsset>.AssetNode[] array3 = array2;
foreach (AssetTree<AddonAsset>.AssetNode assetNode in array3)
{
Texture2D val3 = assetNode.Asset.SourceAddon.LoadTexture(assetNode.Asset.AssetMapping.Paths.First());
if (assetNode.FinalTargetSegment == null)
{
val2.mainTexture = (Texture)(object)val3;
}
else
{
val2.SetTexture(assetNode.FinalTargetSegment, (Texture)(object)val3);
}
}
}
((Renderer)val).materials = materials;
}
}
}
}
namespace Sirdoggy.SideloaderMint.Addons
{
internal class Addon
{
private readonly Dictionary<string, AssetBundle> _assetBundles = new Dictionary<string, AssetBundle>();
private readonly Dictionary<string, AudioClip> _audioClips = new Dictionary<string, AudioClip>();
private readonly Dictionary<string, Material> _materials = new Dictionary<string, Material>();
private readonly Dictionary<string, Mesh> _meshes = new Dictionary<string, Mesh>();
private readonly Dictionary<string, Texture2D> _textures = new Dictionary<string, Texture2D>();
public AddonManifest Manifest { get; }
public string Path { get; }
public string Guid => Path.Replace(Paths.BepInExRootPath, "") ?? "";
public Addon(string path, bool requireUniqueAddonDirectoryName)
{
if (!Directory.Exists(path))
{
throw new DirectoryNotFoundException("Could not resolve directory.");
}
if (requireUniqueAddonDirectoryName)
{
string[] array = new DirectoryInfo(path).Name.Split(new char[1] { '-' });
if (array.Length != 2)
{
throw new InvalidDirectoryNameException("Addon directory name does not match naming convention. Directory name should match: {AddonAuthor}" + $"{'-'}{{AddonName}}. " + "The directory name must contain only one " + $"'{'-'}' character.");
}
string text = array[0].Trim();
string text2 = array[1].Trim();
if (text.Length == 0)
{
throw new InvalidDirectoryNameException("Addon directory name does not match naming convention. Author name cannot be blank.");
}
if (text2.Length == 0)
{
throw new InvalidDirectoryNameException("Addon directory name does not match naming convention. Addon name cannot be blank.");
}
}
string path2 = System.IO.Path.Combine(path, "manifest.json");
if (!File.Exists(path2))
{
throw new FileNotFoundException("The manifest file is missing. The full file name should be 'manifest.json'.");
}
ManifestParser.ParsingResult parsingResult = ManifestParser.ParseJson(File.ReadAllText(path2));
if (!(parsingResult is ManifestParser.ParsingResult.InvalidManifest invalidManifest))
{
if (parsingResult is ManifestParser.ParsingResult.Success success)
{
AddonManifest manifest = success.Manifest;
AddonManifest addonManifest = manifest;
AddonManifest.AssetMapping[] assetMappings = addonManifest.AssetMappings;
for (int i = 0; i < assetMappings.Length; i++)
{
string[] paths = assetMappings[i].Paths;
foreach (string relativePath in paths)
{
PathValidator.Validate(path, relativePath);
}
}
Manifest = addonManifest;
Path = path;
return;
}
throw new NotSupportedException("Unknown validation result");
}
throw new InvalidManifestException("The manifest is not valid. Errors:\n" + StringUtils.JoinValues(invalidManifest.ValidationErrors, "\n"));
}
public GameObject? LoadPrefab(string target)
{
if (FileExists(GetAssetPath(target, out string _)))
{
return this.LoadAssetBundleAsset<GameObject>(target, (IDictionary<string, GameObject>)null);
}
Plugin.Log.LogWarning((object)("[" + Guid + "] no prefab defined at '" + target + "'"));
return null;
}
public Texture2D LoadTexture(string path)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Expected O, but got Unknown
//IL_004e: Expected O, but got Unknown
if (!FileExists(path))
{
throw new FileNotFoundException("Tried to load non-existent texture '" + path + "' from mod " + Guid);
}
if (_textures.TryGetValue(path, out Texture2D value))
{
return value;
}
Dictionary<string, Texture2D> textures = _textures;
Texture2D val = new Texture2D(1, 1, (TextureFormat)5, false);
Texture2D val2 = val;
textures[path] = val;
value = val2;
value.LoadImage(LoadBytes(path));
return value;
}
public Material LoadMaterial(string path)
{
return this.LoadAssetBundleAsset<Material>(path, (IDictionary<string, Material>)_materials);
}
public Mesh LoadMesh(string path)
{
return this.LoadAssetBundleAsset<Mesh>(path, (IDictionary<string, Mesh>)_meshes);
}
public AudioClip LoadAudioClip(string path, string name)
{
if (!FileExists(path))
{
throw new FileNotFoundException("Tried to load non-existent audio clip '" + path + "' from mod " + Guid);
}
if (_audioClips.TryGetValue(path, out AudioClip value))
{
return value;
}
long size;
using Stream from = GetInputStream(path, out size);
using MemoryStream memoryStream = new MemoryStream();
StreamExtensions.CopyTo(from, memoryStream);
using BinaryReader br = new BinaryReader(memoryStream);
return _audioClips[path] = WavUtility.ToAudioClip(br, name);
}
public AssetBundle LoadAssetBundle(string path, out string assetPath)
{
string assetPath2 = GetAssetPath(path, out assetPath);
if (!_assetBundles.TryGetValue(assetPath2, out AssetBundle value))
{
return _assetBundles[assetPath2] = AssetBundle.LoadFromMemory(LoadBytes(assetPath2));
}
return value;
}
public T LoadAssetBundleAsset<T>(string path, IDictionary<string, T> assetCache = null) where T : Object
{
Plugin.LogVerbose("Loading asset from " + path);
if (assetCache != null && assetCache.TryGetValue(path, out T value))
{
return value;
}
value = LoadAssetBundle(path, out string assetPath).LoadAsset<T>(assetPath);
if (assetCache != null)
{
assetCache[path] = value;
}
return value;
}
public string GetAssetPath(string path, out string assetPath)
{
assetPath = null;
string[] array = path.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (array.Length == 0)
{
return null;
}
assetPath = ((array.Length >= 2) ? array[^1] : null);
return array[0];
}
private Stream GetInputStream(string path, out long size)
{
if (!FileExists(path))
{
throw new FileNotFoundException("'" + path + "' does not exist in " + Guid);
}
FileStream fileStream = File.OpenRead(System.IO.Path.Combine(Path, path));
size = fileStream.Length;
return fileStream;
}
private byte[] LoadBytes(string path)
{
long size;
using Stream stream = GetInputStream(path, out size);
byte[] array = new byte[size];
stream.Read(array, 0, array.Length);
return array;
}
public bool FileExists(string relativePath)
{
return File.Exists(System.IO.Path.Combine(Path, relativePath));
}
}
internal class InvalidManifestException : Exception
{
public InvalidManifestException(string message)
: base(message)
{
}
}
internal class InvalidDirectoryNameException : Exception
{
public InvalidDirectoryNameException(string message)
: base(message)
{
}
}
internal class AddonManifest
{
public class AssetMapping
{
public sealed class Audio : AssetMapping
{
public float[]? VolumeRange { get; }
public float[]? PitchRange { get; }
public Audio(AssetType assetType, string[] targets, string[] paths, float[]? volumeRange, float[]? pitchRange)
{
VolumeRange = volumeRange;
PitchRange = pitchRange;
base..ctor(assetType, targets, paths);
}
}
public AssetType AssetType { get; }
public string[] Targets { get; }
public string[] Paths { get; }
public AssetMapping(AssetType assetType, string[] targets, string[] paths)
{
AssetType = assetType;
Targets = targets;
Paths = paths;
base..ctor();
}
}
public enum AssetType
{
Texture,
Prefab,
Mesh,
Material,
AudioClip,
GunSound,
GunAudioSet,
Unknown
}
public string ManifestRevision { get; }
public AssetMapping[] AssetMappings { get; }
public bool Disabled { get; }
public AddonManifest(string manifestRevision, AssetMapping[] assetMappings, bool disabled)
{
ManifestRevision = manifestRevision;
AssetMappings = assetMappings;
Disabled = disabled;
base..ctor();
}
public bool UsesAsterisksAsWildcardsInTargetField()
{
return ManifestRevision != "1";
}
}
internal static class ManifestParser
{
public abstract class ParsingResult
{
public sealed class Success : ParsingResult
{
public AddonManifest Manifest { get; }
public Success(AddonManifest manifest)
{
Manifest = manifest;
base..ctor();
}
}
public sealed class InvalidManifest : ParsingResult
{
public List<string> ValidationErrors { get; }
public InvalidManifest(List<string> validationErrors)
{
ValidationErrors = validationErrors;
base..ctor();
}
}
}
private const string ManifestRevision1 = "1";
private const string ManifestRevision2 = "2";
private const string ManifestRevisionPropertyKey = "ManifestRevision";
private static readonly string[] SupportedManifestRevisions = new string[2] { "1", "2" };
public static ParsingResult ParseJson(string manifestJson)
{
JObject val = JObject.Parse(manifestJson);
string text = ((object)(val.GetValue("ManifestRevision", StringComparison.OrdinalIgnoreCase) ?? throw new MissingFieldException("Manifest does not contain 'ManifestRevision' property."))).ToString();
object obj;
if (!(text == "1"))
{
if (!(text == "2"))
{
throw new NotSupportedException("Unsupported manifest revision, supported values are: [" + StringUtils.JoinValues(SupportedManifestRevisions) + "]");
}
obj = StrictDeserializer.Deserialize<AddonManifestRevision2Dto>(val);
}
else
{
obj = ((JToken)val).ToObject<AddonManifestRevision1Dto>();
}
object manifestDtoObject = obj;
List<string> list = ValidateManifest(manifestDtoObject);
if (list.Count > 0)
{
return new ParsingResult.InvalidManifest(list);
}
return new ParsingResult.Success(MapManifestToDomain(manifestDtoObject));
}
private static List<string> ValidateManifest(object manifestDtoObject)
{
List<string> errors = new List<string>();
if (!(manifestDtoObject is AddonManifestRevision1Dto dto2))
{
if (!(manifestDtoObject is AddonManifestRevision2Dto dto3))
{
throw new NotSupportedException("Unknown manifest dto object");
}
ValidateRevision2(dto3);
}
else
{
ValidateRevision1(dto2);
}
return errors;
void AddErrorInvalidArraySizeForProperty(string property, int actualSize, int allowedSize)
{
errors.Add($"Property '{property}' contains an array of size {actualSize} which is not " + $"allowed - it should be of size {allowedSize}.");
}
void AddErrorMissingProperty(string missingProperty)
{
errors.Add("Missing required property: '" + missingProperty + "'.");
}
void AddErrorNegativeValue(string property, string value)
{
errors.Add("Property '" + property + "' contains a negative value '" + value + "' which is not allowed.");
}
void AddErrorNeitherOfMultipleSpecified(string[] properties)
{
errors.Add("Neither of the following properties is specified: '" + StringUtils.JoinValues(properties) + "'. At least one of them must be specified.");
}
void AddErrorUnknownAssetType(string assetType)
{
errors.Add("Unknown asset mapping asset type: '" + assetType + "'.");
}
void AddErrorUnsupportedPropertyForType(string unsupportedProperty, string assetType)
{
errors.Add("Property '" + unsupportedProperty + "' is not supported for asset mapping of type '" + assetType + "'.");
}
void ValidateRevision1(AddonManifestRevision1Dto dto)
{
if (dto.Guid == null)
{
AddErrorMissingProperty("Guid");
}
if (dto.Name == null)
{
AddErrorMissingProperty("Name");
}
if (dto.Version == null)
{
AddErrorMissingProperty("Version");
}
if (dto.AssetMappings == null)
{
AddErrorMissingProperty("AssetMappings");
}
else
{
AddonManifestRevision1Dto.AssetMappingDto[] assetMappings = dto.AssetMappings;
foreach (AddonManifestRevision1Dto.AssetMappingDto obj in assetMappings)
{
if (obj.Path == null)
{
AddErrorMissingProperty("Path");
}
if (obj.Target == null)
{
AddErrorMissingProperty("Target");
}
}
}
}
void ValidateRevision2(AddonManifestRevision2Dto dto)
{
if (dto.AssetMappings == null)
{
AddErrorMissingProperty("AssetMappings");
}
else
{
AddonManifestRevision2Dto.AssetMappingDto[] assetMappings2 = dto.AssetMappings;
foreach (AddonManifestRevision2Dto.AssetMappingDto assetMappingDto in assetMappings2)
{
if (!assetMappingDto.Disabled.GetValueOrDefault())
{
if (!assetMappingDto.Type.HasValue)
{
AddErrorMissingProperty("Type");
}
switch (assetMappingDto.Type)
{
case AddonManifestRevision2Dto.AssetTypeDto.Texture:
case AddonManifestRevision2Dto.AssetTypeDto.Prefab:
case AddonManifestRevision2Dto.AssetTypeDto.Mesh:
case AddonManifestRevision2Dto.AssetTypeDto.Material:
if (assetMappingDto.Path == null)
{
AddErrorMissingProperty("Path");
}
break;
case AddonManifestRevision2Dto.AssetTypeDto.AudioClip:
case AddonManifestRevision2Dto.AssetTypeDto.GunSound:
case AddonManifestRevision2Dto.AssetTypeDto.GunAudioSet:
if (assetMappingDto.Path == null && assetMappingDto.Paths == null)
{
AddErrorNeitherOfMultipleSpecified(new string[2] { "Path", "Paths" });
}
break;
default:
AddErrorUnknownAssetType(assetMappingDto.Type.ToString());
break;
}
switch (assetMappingDto.Type)
{
case AddonManifestRevision2Dto.AssetTypeDto.AudioClip:
case AddonManifestRevision2Dto.AssetTypeDto.GunSound:
case AddonManifestRevision2Dto.AssetTypeDto.GunAudioSet:
if (assetMappingDto.SoundPitch != null)
{
if (assetMappingDto.SoundPitch.Length != 2)
{
AddErrorInvalidArraySizeForProperty("SoundPitch", assetMappingDto.SoundPitch.Length, 2);
}
float[] soundPitch = assetMappingDto.SoundPitch;
for (int k = 0; k < soundPitch.Length; k++)
{
float num = soundPitch[k];
if (num < 0f)
{
AddErrorNegativeValue("SoundPitch", num.ToString(CultureInfo.InvariantCulture));
}
}
}
if (assetMappingDto.SoundVolume != null)
{
if (assetMappingDto.SoundVolume.Length != 2)
{
AddErrorInvalidArraySizeForProperty("SoundVolume", assetMappingDto.SoundVolume.Length, 2);
}
float[] soundPitch = assetMappingDto.SoundVolume;
for (int k = 0; k < soundPitch.Length; k++)
{
float num2 = soundPitch[k];
if (num2 < 0f)
{
AddErrorNegativeValue("SoundVolume", num2.ToString(CultureInfo.InvariantCulture));
}
}
}
break;
case AddonManifestRevision2Dto.AssetTypeDto.Texture:
case AddonManifestRevision2Dto.AssetTypeDto.Prefab:
case AddonManifestRevision2Dto.AssetTypeDto.Mesh:
case AddonManifestRevision2Dto.AssetTypeDto.Material:
if (assetMappingDto.SoundPitch != null)
{
AddErrorUnsupportedPropertyForType("SoundPitch", assetMappingDto.Type.ToString());
}
if (assetMappingDto.SoundVolume != null)
{
AddErrorUnsupportedPropertyForType("SoundVolume", assetMappingDto.Type.ToString());
}
break;
default:
AddErrorUnknownAssetType(assetMappingDto.Type.ToString());
break;
}
if (assetMappingDto.Target == null && assetMappingDto.Targets == null)
{
AddErrorNeitherOfMultipleSpecified(new string[2] { "Target", "Targets" });
}
}
}
}
}
}
private static AddonManifest MapManifestToDomain(object manifestDtoObject)
{
if (!(manifestDtoObject is AddonManifestRevision1Dto dto))
{
if (manifestDtoObject is AddonManifestRevision2Dto dto2)
{
return dto2.ToDomain();
}
throw new NotSupportedException("Unknown manifest dto object");
}
return dto.ToDomain();
}
}
}
namespace Sirdoggy.SideloaderMint.Addons.Data
{
internal class AddonManifestRevision1Dto
{
public class AssetMappingDto
{
public AssetTypeDto? Type { get; set; }
public string? Target { get; set; }
public string? Path { get; set; }
}
public enum AssetTypeDto
{
Texture,
Prefab,
Mesh,
Material,
AudioClip,
FVRObject,
ItemSpawnerID
}
public string? ManifestRevision { get; set; }
public string? Guid { get; set; }
public string? Name { get; set; }
public string? Version { get; set; }
public string? Description { get; set; }
public AssetMappingDto[]? AssetMappings { get; set; }
}
internal class AddonManifestRevision2Dto
{
public class AssetMappingDto
{
public bool? Disabled { get; set; }
public string? Comment { get; set; }
public AssetTypeDto? Type { get; set; }
public string? Target { get; set; }
public string[]? Targets { get; set; }
public string? Path { get; set; }
public string[]? Paths { get; set; }
public float[]? SoundVolume { get; set; }
public float[]? SoundPitch { get; set; }
}
public enum AssetTypeDto
{
Texture,
Prefab,
Mesh,
Material,
AudioClip,
GunSound,
GunAudioSet
}
public string? ManifestRevision { get; set; }
[Obsolete]
public string? Guid { get; set; }
[Obsolete]
public string? Name { get; set; }
[Obsolete]
public string? Version { get; set; }
[Obsolete]
public string? Description { get; set; }
public bool? Disabled { get; set; }
public string? Comment { get; set; }
public AssetMappingDto[]? AssetMappings { get; set; }
}
internal static class ManifestMappings
{
public static AddonManifest ToDomain(this AddonManifestRevision1Dto dto)
{
return new AddonManifest(dto.ManifestRevision ?? throw new NullReferenceException(), (dto.AssetMappings ?? new AddonManifestRevision1Dto.AssetMappingDto[0]).Select((AddonManifestRevision1Dto.AssetMappingDto assetMappingDto) => assetMappingDto.ToDomain()).ToArray(), disabled: false);
}
public static AddonManifest.AssetMapping ToDomain(this AddonManifestRevision1Dto.AssetMappingDto dto)
{
return new AddonManifest.AssetMapping(dto.Type.ToDomain(), new string[1] { dto.Target ?? throw new NullReferenceException() }, new string[1] { dto.Path ?? throw new NullReferenceException() });
}
public static AddonManifest.AssetType ToDomain(this AddonManifestRevision1Dto.AssetTypeDto? dto)
{
return dto switch
{
AddonManifestRevision1Dto.AssetTypeDto.Texture => AddonManifest.AssetType.Texture,
AddonManifestRevision1Dto.AssetTypeDto.Prefab => AddonManifest.AssetType.Prefab,
AddonManifestRevision1Dto.AssetTypeDto.Mesh => AddonManifest.AssetType.Mesh,
AddonManifestRevision1Dto.AssetTypeDto.Material => AddonManifest.AssetType.Material,
AddonManifestRevision1Dto.AssetTypeDto.AudioClip => AddonManifest.AssetType.AudioClip,
_ => AddonManifest.AssetType.Unknown,
};
}
public static AddonManifest ToDomain(this AddonManifestRevision2Dto dto)
{
return new AddonManifest(dto.ManifestRevision ?? throw new NullReferenceException(), disabled: dto.Disabled.GetValueOrDefault(), assetMappings: (from assetMappingDto in dto.AssetMappings ?? new AddonManifestRevision2Dto.AssetMappingDto[0]
where ((!assetMappingDto.Disabled) ?? true) ? true : false
select assetMappingDto.ToDomain()).ToArray());
}
public static AddonManifest.AssetMapping ToDomain(this AddonManifestRevision2Dto.AssetMappingDto dto)
{
List<string> list = dto.Targets?.ToList() ?? new List<string>();
if (dto.Target != null)
{
list.Add(dto.Target);
}
List<string> list2 = dto.Paths?.ToList() ?? new List<string>();
if (dto.Path != null)
{
list2.Add(dto.Path);
}
AddonManifestRevision2Dto.AssetTypeDto? type = dto.Type;
if (type.HasValue)
{
AddonManifestRevision2Dto.AssetTypeDto valueOrDefault = type.GetValueOrDefault();
if ((uint)(valueOrDefault - 4) <= 2u)
{
return new AddonManifest.AssetMapping.Audio(dto.Type.ToDomain(), list.ToArray(), list2.ToArray(), dto.SoundVolume, dto.SoundPitch);
}
}
return new AddonManifest.AssetMapping(dto.Type.ToDomain(), list.ToArray(), list2.ToArray());
}
public static AddonManifest.AssetType ToDomain(this AddonManifestRevision2Dto.AssetTypeDto? dto)
{
return dto switch
{
AddonManifestRevision2Dto.AssetTypeDto.Texture => AddonManifest.AssetType.Texture,
AddonManifestRevision2Dto.AssetTypeDto.Prefab => AddonManifest.AssetType.Prefab,
AddonManifestRevision2Dto.AssetTypeDto.Mesh => AddonManifest.AssetType.Mesh,
AddonManifestRevision2Dto.AssetTypeDto.Material => AddonManifest.AssetType.Material,
AddonManifestRevision2Dto.AssetTypeDto.AudioClip => AddonManifest.AssetType.AudioClip,
AddonManifestRevision2Dto.AssetTypeDto.GunSound => AddonManifest.AssetType.GunSound,
AddonManifestRevision2Dto.AssetTypeDto.GunAudioSet => AddonManifest.AssetType.GunAudioSet,
_ => AddonManifest.AssetType.Unknown,
};
}
}
}
[CompilerGenerated]
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, ICollection<T>, IList<T>
{
int ICollection.Count => _items.Length;
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => this;
object IList.this[int index]
{
get
{
return _items[index];
}
set
{
throw new NotSupportedException();
}
}
bool IList.IsFixedSize => true;
bool IList.IsReadOnly => true;
int ICollection<T>.Count => _items.Length;
bool ICollection<T>.IsReadOnly => true;
T IList<T>.this[int index]
{
get
{
return _items[index];
}
set
{
throw new NotSupportedException();
}
}
public <>z__ReadOnlyArray(T[] items)
{
_items = items;
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_items).GetEnumerator();
}
void ICollection.CopyTo(Array array, int index)
{
((ICollection)_items).CopyTo(array, index);
}
int IList.Add(object value)
{
throw new NotSupportedException();
}
void IList.Clear()
{
throw new NotSupportedException();
}
bool IList.Contains(object value)
{
return ((IList)_items).Contains(value);
}
int IList.IndexOf(object value)
{
return ((IList)_items).IndexOf(value);
}
void IList.Insert(int index, object value)
{
throw new NotSupportedException();
}
void IList.Remove(object value)
{
throw new NotSupportedException();
}
void IList.RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return ((IEnumerable<T>)_items).GetEnumerator();
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException();
}
void ICollection<T>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<T>.Contains(T item)
{
return ((ICollection<T>)_items).Contains(item);
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
((ICollection<T>)_items).CopyTo(array, arrayIndex);
}
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
int IList<T>.IndexOf(T item)
{
return ((IList<T>)_items).IndexOf(item);
}
void IList<T>.Insert(int index, T item)
{
throw new NotSupportedException();
}
void IList<T>.RemoveAt(int index)
{
throw new NotSupportedException();
}
}