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.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ModularWorkshop;
using Sirdoggy.SideloaderMint.Addons;
using Sirdoggy.SideloaderMint.Addons.Data;
using Sirdoggy.SideloaderMint.Addons.Data.Model;
using Sirdoggy.SideloaderMint.AssetLoaders;
using Sirdoggy.SideloaderMint.AssetLoaders.Implementations;
using Sirdoggy.SideloaderMint.Common;
using Sirdoggy.SideloaderMint.Common.Coroutines;
using Sirdoggy.SideloaderMint.Common.Structures;
using Sirdoggy.SideloaderMint.Common.Validation;
using Sirdoggy.SideloaderMint.Model;
using Sirdoggy.SideloaderMint.Patchers;
using Sirdoggy.SideloaderMint.Patchers.Extensions;
using Sirdoggy.SideloaderMint.Patchers.Tags;
using UnityEngine;
using UnityEngine.SceneManagement;
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("Text-based asset replacer for H3VR")]
[assembly: AssemblyFileVersion("1.5.0.0")]
[assembly: AssemblyInformationalVersion("1.5.0")]
[assembly: AssemblyProduct("Sirdoggy.SideloaderMint")]
[assembly: AssemblyTitle("SideloaderMint")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[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();
}
}
[CompilerGenerated]
internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, ICollection<T>, IList<T>
{
private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T>
{
object IEnumerator.Current => _item;
T IEnumerator<T>.Current => _item;
public Enumerator(T item)
{
_item = item;
}
bool IEnumerator.MoveNext()
{
if (!_moveNextCalled)
{
return _moveNextCalled = true;
}
return false;
}
void IEnumerator.Reset()
{
_moveNextCalled = false;
}
void IDisposable.Dispose()
{
}
}
int ICollection.Count => 1;
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => this;
object IList.this[int index]
{
get
{
if (index != 0)
{
throw new IndexOutOfRangeException();
}
return _item;
}
set
{
throw new NotSupportedException();
}
}
bool IList.IsFixedSize => true;
bool IList.IsReadOnly => true;
int ICollection<T>.Count => 1;
bool ICollection<T>.IsReadOnly => true;
T IList<T>.this[int index]
{
get
{
if (index != 0)
{
throw new IndexOutOfRangeException();
}
return _item;
}
set
{
throw new NotSupportedException();
}
}
public <>z__ReadOnlySingleElementList(T item)
{
_item = item;
}
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator(_item);
}
void ICollection.CopyTo(Array array, int index)
{
array.SetValue(_item, index);
}
int IList.Add(object value)
{
throw new NotSupportedException();
}
void IList.Clear()
{
throw new NotSupportedException();
}
bool IList.Contains(object value)
{
return EqualityComparer<T>.Default.Equals(_item, (T)value);
}
int IList.IndexOf(object value)
{
if (!EqualityComparer<T>.Default.Equals(_item, (T)value))
{
return -1;
}
return 0;
}
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 new Enumerator(_item);
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException();
}
void ICollection<T>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<T>.Contains(T item)
{
return EqualityComparer<T>.Default.Equals(_item, item);
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
array[arrayIndex] = _item;
}
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
int IList<T>.IndexOf(T item)
{
if (!EqualityComparer<T>.Default.Equals(_item, item))
{
return -1;
}
return 0;
}
void IList<T>.Insert(int index, T item)
{
throw new NotSupportedException();
}
void IList<T>.RemoveAt(int index)
{
throw new NotSupportedException();
}
}
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class IsReadOnlyAttribute : Attribute
{
}
[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;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class ExtensionMarkerAttribute : Attribute
{
private readonly string <Name>k__BackingField;
public string Name => <Name>k__BackingField;
public ExtensionMarkerAttribute(string name)
{
<Name>k__BackingField = name;
}
}
}
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 string AddonFolderName = "SideloaderMint";
public const int HarmonyPriority = 300;
public static string PluginDirectory => Path.Combine(Paths.PluginPath, "Sirdoggy.SideloaderMint".Replace('.', '-'));
}
internal static class MainLoader
{
private class ResolvedAddonDirectory
{
public enum Type
{
LegacyDirectoryAddon,
PluginsAddon,
PluginsSubAddon
}
public string FileAccessBoundaryPath { get; }
public string AddonFullPath { get; }
public Type AddonType { get; }
public string? InvalidDirectoryNameError { get; }
public ResolvedAddonDirectory(string fileAccessBoundaryPath, string addonFullPath, Type addonType, string? invalidDirectoryNameError)
{
FileAccessBoundaryPath = fileAccessBoundaryPath;
AddonFullPath = addonFullPath;
AddonType = addonType;
InvalidDirectoryNameError = invalidDirectoryNameError;
base..ctor();
}
public override string ToString()
{
return StringUtils.FormatTypeProperties("ResolvedAddonDirectory", new <>z__ReadOnlyArray<string>(new string[3]
{
"AddonFullPath: " + AddonFullPath,
string.Format("{0}: {1}", "AddonType", AddonType),
"InvalidDirectoryNameError: " + InvalidDirectoryNameError
}));
}
}
[SpecialName]
public sealed class <G>$75E6429709F2538C8DBED7BDB4D59AC5
{
[SpecialName]
public static class <M>$2D6E795AA6D0AF6F09DB47CF4AC4FB04
{
}
[ExtensionMarker("<M>$2D6E795AA6D0AF6F09DB47CF4AC4FB04")]
private void AddAddonsFromLegacyDirectory()
{
throw new NotSupportedException();
}
[ExtensionMarker("<M>$2D6E795AA6D0AF6F09DB47CF4AC4FB04")]
private void AddAddonsFromPluginDirectories()
{
throw new NotSupportedException();
}
}
public static int TargetConflictsDuringLoadCount;
public static readonly MaterialLoader MaterialLoader = new MaterialLoader();
public static readonly MeshLoader MeshLoader = new MeshLoader();
public static readonly TextureLoader TextureLoader = new TextureLoader();
private static readonly GunSoundLoader GunSoundLoader = new GunSoundLoader();
private static readonly GunAudioSetLoader GunAudioSetLoader = new GunAudioSetLoader();
private static readonly AudioClipLoader AudioClipLoader = new AudioClipLoader();
private static readonly string LegacyAddonsPath = Path.Combine(Paths.BepInExRootPath, "SideloaderMint");
private static readonly IAssetLoader[] AllAssetLoaders = new IAssetLoader[7]
{
AudioClipLoader,
GunSoundLoader,
GunAudioSetLoader,
MaterialLoader,
MeshLoader,
new PrefabLoader(),
TextureLoader
};
public static void ReloadAddons()
{
TargetConflictsDuringLoadCount = 0;
IAssetLoader[] allAssetLoaders = AllAssetLoaders;
for (int i = 0; i < allAssetLoaders.Length; i++)
{
allAssetLoaders[i].Clear();
}
InitializeAssetLoadersAndLoadAddons();
}
public static void InitializeAssetLoadersAndLoadAddons()
{
FVRFireArmPatcher.Initialize(GunSoundLoader, GunAudioSetLoader);
AudioSourcePatcher.Initialize(AudioClipLoader);
Plugin.Log.LogMessage((object)"Loading addons...");
List<ResolvedAddonDirectory> list = new List<ResolvedAddonDirectory>();
list.AddAddonsFromLegacyDirectory();
list.AddAddonsFromPluginDirectories();
Dictionary<string, Addon> dictionary = new Dictionary<string, Addon>();
int num = 0;
int num2 = 0;
foreach (ResolvedAddonDirectory item in list)
{
try
{
Addon addon2 = new Addon(item.AddonFullPath, item.FileAccessBoundaryPath);
if (item.InvalidDirectoryNameError != null)
{
Plugin.Log.LogError((object)("Failed to load addon '" + addon2.GUID + "'. " + item.InvalidDirectoryNameError));
num2++;
continue;
}
Plugin.PluginConfig.BindConfigForAddon(addon2);
if (!addon2.Enabled)
{
Plugin.Log.LogInfo((object)("Skipped addon '" + addon2.GUID + "' because it's disabled."));
num++;
}
else if (dictionary.ContainsKey(addon2.GUID))
{
Plugin.Log.LogError((object)("Failed to load addon '" + addon2.GUID + "' because an addon with the same GUID was already loaded!"));
}
else
{
Plugin.Log.LogInfo((object)("Loaded addon '" + addon2.GUID + "'"));
dictionary.Add(addon2.GUID, addon2);
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to load addon from path: " + item.AddonFullPath + "\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.");
}
if (num2 > 0)
{
stringBuilder.Append($" {num2} addons were skipped because they have incorrect directory names.");
}
Plugin.Log.LogInfo((object)stringBuilder.ToString());
if (Plugin.PluginConfig.ClearUninstalledAddons)
{
Plugin.Log.LogMessage((object)"Clearing uninstalled addons from config file.");
Plugin.PluginConfig.ClearUninstalledAddonsConfigEntries();
}
try
{
List<Addon> addons = dictionary.Values.OrderByDescending((Addon addon) => addon.Priority).ToList();
IAssetLoader[] allAssetLoaders = AllAssetLoaders;
foreach (IAssetLoader assetLoader in allAssetLoaders)
{
Plugin.Log.LogMessage((object)$"Initializing '{assetLoader}'...)'");
assetLoader.Initialize(addons);
}
StringBuilder stringBuilder2 = new StringBuilder().Append("Asset loaders initialized successfully!");
if (TargetConflictsDuringLoadCount > 0)
{
stringBuilder2.Append($" Resolved {TargetConflictsDuringLoadCount} conflicts based on addon" + " priorities in config file.");
}
Plugin.Log.LogInfo((object)stringBuilder2.ToString());
}
catch (Exception arg)
{
Plugin.Log.LogFatal((object)("An exception has occured while initializing asset loaders, some of your installed addons will likely not work!" + $"\n- Exception: {arg}"));
}
}
private static void AddAddonsFromLegacyDirectory(this List<ResolvedAddonDirectory> output)
{
if (!Directory.Exists(LegacyAddonsPath))
{
return;
}
string[] directories = Directory.GetDirectories(LegacyAddonsPath, "*", SearchOption.TopDirectoryOnly);
foreach (string text in directories)
{
if (File.Exists(Path.Combine(text, "manifest.json")))
{
string invalidDirectoryNameError = IsAddonDirectoryNameValid(text);
ResolvedAddonDirectory item = new ResolvedAddonDirectory(LegacyAddonsPath, text, ResolvedAddonDirectory.Type.LegacyDirectoryAddon, invalidDirectoryNameError);
output.Add(item);
}
}
}
private static void AddAddonsFromPluginDirectories(this List<ResolvedAddonDirectory> output)
{
string[] directories = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.TopDirectoryOnly);
foreach (string text in directories)
{
string text2 = Path.Combine(text, "SideloaderMint");
if (!Directory.Exists(text2))
{
continue;
}
if (File.Exists(Path.Combine(text2, "manifest.json")))
{
string addonFullPath = text2;
ResolvedAddonDirectory item = new ResolvedAddonDirectory(text, addonFullPath, ResolvedAddonDirectory.Type.PluginsAddon, null);
output.Add(item);
continue;
}
string[] directories2 = Directory.GetDirectories(text2, "*", SearchOption.TopDirectoryOnly);
foreach (string text3 in directories2)
{
if (File.Exists(Path.Combine(text3, "manifest.json")))
{
string invalidDirectoryNameError = IsAddonDirectoryNameValid(text3);
ResolvedAddonDirectory item2 = new ResolvedAddonDirectory(text, text3, ResolvedAddonDirectory.Type.PluginsSubAddon, invalidDirectoryNameError);
output.Add(item2);
}
}
}
}
private static string? IsAddonDirectoryNameValid(string directoryPath)
{
string name = new DirectoryInfo(directoryPath).Name;
if (!SubAddonNameValidator.IsValid(name))
{
return "Directory name '" + name + "' contains invalid characters. Allowed characters are: a-z A-Z 0-9 _ . , ( )";
}
return null;
}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInProcess("h3vr.exe")]
[BepInPlugin("Sirdoggy.SideloaderMint", "SideloaderMint", "1.5.0")]
public class Plugin : BaseUnityPlugin
{
private const string ModularWorkshopPluginID = "h3vr.cityrobo.ModularWorkshopManager";
private const string OldSideloaderPluginID = "horse.coder.h3vr.sideloader";
internal static ManualLogSource Log = null;
internal static PluginConfig PluginConfig = new PluginConfig();
internal static ExceptionCatcher ExceptionCatcher = null;
private static bool _isFinishedLoading;
private static SharedAssetInfo _sharedAssetInfo = SharedAssetInfo.SharedAllowNew;
public const string Id = "Sirdoggy.SideloaderMint";
public static string Name => "SideloaderMint";
public static string Version => "1.5.0";
internal static void LogVerbose(string message)
{
if (PluginConfig.VerboseDebugLogsEnabled)
{
Log.LogDebug((object)message);
}
}
private void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
ExceptionCatcher = new ExceptionCatcher(Log);
ResourceRedirection.EnableSyncOverAsyncAssetLoads();
ExceptionCatcher.Run(delegate
{
Harmony.CreateAndPatchAll(typeof(AudioSourcePatcher), (string)null);
});
ExceptionCatcher.Run(delegate
{
Harmony.CreateAndPatchAll(typeof(FVRFireArmPatcher), (string)null);
});
ExceptionCatcher.Run(delegate
{
Harmony.CreateAndPatchAll(typeof(FVRFireArmMagazinePatcher), (string)null);
});
ExceptionCatcher.Run(delegate
{
Harmony.CreateAndPatchAll(typeof(ClosedBoltHandlePatcher), (string)null);
});
ExceptionCatcher.Run(delegate
{
Harmony.CreateAndPatchAll(typeof(ClosedBoltPatcher), (string)null);
});
ExceptionCatcher.Run(delegate
{
Harmony.CreateAndPatchAll(typeof(HandgunSlidePatcher), (string)null);
});
ExceptionCatcher.Run(delegate
{
Harmony.CreateAndPatchAll(typeof(TubeFedShotgunBoltPatcher), (string)null);
});
ExceptionCatcher.Run(delegate
{
Harmony.CreateAndPatchAll(typeof(TubeFedShotgunHandlePatcher), (string)null);
});
if (Chainloader.PluginInfos != null)
{
if (Chainloader.PluginInfos.ContainsKey("h3vr.cityrobo.ModularWorkshopManager"))
{
Log.LogDebug((object)"ModularWorkshop is installed, patching...");
ExceptionCatcher.Run(delegate
{
Harmony.CreateAndPatchAll(typeof(ModularBarrelExtensionPatcher), (string)null);
});
}
else
{
Log.LogDebug((object)"ModularWorkshop is not installed.");
}
if (Chainloader.PluginInfos.ContainsKey("horse.coder.h3vr.sideloader"))
{
Log.LogDebug((object)"Old Sideloader is installed, patching...");
ExceptionCatcher.Run(OldSideloaderPatcher.ApplyPatch);
}
else
{
Log.LogDebug((object)"Old Sideloader is not installed.");
}
}
MainLoader.InitializeAssetLoadersAndLoadAddons();
SceneManager.sceneLoaded += OnSceneLoaded;
_isFinishedLoading = true;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
ReplaceAllSharedAssets();
}
private void ReplaceAllSharedAssets()
{
GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
foreach (GameObject gameO in array)
{
MainLoader.MaterialLoader.ReplaceMaterials(gameO, "SharedAssets", _sharedAssetInfo);
MainLoader.MeshLoader.ReplaceMeshes(gameO, "SharedAssets", _sharedAssetInfo);
MainLoader.TextureLoader.ReplaceTextures(gameO, "SharedAssets", _sharedAssetInfo);
}
_sharedAssetInfo = SharedAssetInfo.SharedDoNotAllowNew;
}
private void Update()
{
if (Input.GetKey((KeyCode)306) && Input.GetKeyDown((KeyCode)114) && _isFinishedLoading && PluginConfig.EnableAddonReloading)
{
_isFinishedLoading = false;
PluginConfig = new PluginConfig();
MainLoader.ReloadAddons();
ReplaceAllSharedAssets();
_isFinishedLoading = true;
}
MainLoader.MaterialLoader.TryReplaceQueuedMaterials();
MainLoader.MeshLoader.TryReplaceQueuedMeshes();
MainLoader.TextureLoader.TryReplaceQueuedTextures();
}
}
internal class PluginConfig
{
private const string ConfigFileName = "Sirdoggy.SideloaderMint.cfg";
private readonly ConfigFileWrapper _configFile;
public bool ClearUninstalledAddons { get; }
public bool EnableAddonReloading { get; }
public bool VerboseDebugLogsEnabled { get; }
public PluginConfig()
{
_configFile = new ConfigFileWrapper("Sirdoggy.SideloaderMint.cfg");
ClearUninstalledAddons = _configFile.BindBool(new ConfigFileWrapper.SimpleConfigEntry<bool>("General Settings", "Clear Uninstalled Addons", defaultValue: true, "If set to true, uninstalled addons will be removed from the config file upon launching the game."));
EnableAddonReloading = _configFile.BindBool(new ConfigFileWrapper.SimpleConfigEntry<bool>("General Settings", "Enable Addon Reloading", defaultValue: true, "Allows you to reload all addons by pressing Ctrl + R. New assets might not load in until the scene is also reloaded."));
VerboseDebugLogsEnabled = _configFile.BindBool(new ConfigFileWrapper.SimpleConfigEntry<bool>("Developer Settings", "VerboseDebugLogs", defaultValue: false, "Enables verbose debug logs. These will noticeably spam the console."));
}
public void BindConfigForAddon(Addon addon)
{
addon.Enabled = _configFile.BindBool(new ConfigFileWrapper.SimpleConfigEntry<bool>("Addons - Enabled addons", "Addon Enabled: " + addon.GUID, addon.Enabled));
addon.Priority = _configFile.BindInt(new ConfigFileWrapper.SimpleConfigEntry<int>("Addons - Priorities of addons", "Addon Priority: " + addon.GUID, addon.Priority));
}
public void ClearUninstalledAddonsConfigEntries()
{
_configFile.ClearUntrackedEntries();
}
}
public enum SharedAssetInfo
{
NotShared,
SharedAllowNew,
SharedDoNotAllowNew
}
}
namespace Sirdoggy.SideloaderMint.Patchers
{
[HarmonyWrapSafe]
[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)
{
AudioClip clip = __instance.clip;
if (((clip != null) ? ((Object)clip).name : null) == null)
{
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.AddonEntriesByTarget.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.ResourceReferences.Length);
AddonManifest.AssetReference replacement = value.ResourceReferences[num];
AudioClip val = value.Addon.LoadAudioClip(replacement);
((Object)val).name = ((Object)__instance.clip).name;
__instance.clip = val;
float[] volumeRange = value.VolumeRange;
float[] volumeMultiplierRange = value.VolumeMultiplierRange;
float[] pitchRange = value.PitchRange;
float[] pitchMultiplierRange = value.PitchMultiplierRange;
if (volumeRange != null)
{
float volume = Random.Range(volumeRange[0], volumeRange[1]);
__instance.volume = volume;
}
if (volumeMultiplierRange != null)
{
float num2 = Random.Range(volumeMultiplierRange[0], volumeMultiplierRange[1]);
__instance.volume *= num2;
}
if (pitchRange != null)
{
float pitch = Random.Range(pitchRange[0], pitchRange[1]);
__instance.pitch = pitch;
}
if (pitchMultiplierRange != null)
{
float num3 = Random.Range(pitchMultiplierRange[0], pitchMultiplierRange[1]);
__instance.pitch *= num3;
}
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]
[HarmonyPriority(300)]
[HarmonyPatch(typeof(ClosedBoltHandle))]
internal static class ClosedBoltHandlePatcher
{
private class UpdateHandleSharedState
{
public readonly bool BoltCanBeSlappedInPrefix;
public UpdateHandleSharedState(bool boltCanBeSlappedInPrefix)
{
BoltCanBeSlappedInPrefix = boltCanBeSlappedInPrefix;
base..ctor();
}
}
[HarmonyPostfix]
[HarmonyPatch("UpdateInteraction")]
private static void UpdateInteractionPostfix(ClosedBoltHandle __instance)
{
FirearmTag component = ((Component)__instance.Weapon).gameObject.GetComponent<FirearmTag>();
if (Object.op_Implicit((Object)(object)component))
{
string itemID = ((FVRPhysicalObject)__instance.Weapon).ObjectWrapper.ItemID;
Plugin.LogVerbose($"[UpdateInteractionPostfix] Updating tag for firearm '{itemID}' ({component})");
if (__instance.Weapon.IsBoltHeldOpen())
{
Plugin.LogVerbose("[UpdateInteractionPostfix] Bolt of firearm '" + itemID + "' is held open");
return;
}
component.OnManualCharge();
Plugin.LogVerbose($"[UpdateInteractionPostfix] Successfully updated tag for firearm '{itemID}' ({component})");
}
}
[HarmonyPrefix]
[HarmonyPatch("UpdateHandle")]
private static void UpdateHandlePrefix(ClosedBoltHandle __instance, ref UpdateHandleSharedState? __state)
{
if (__instance != null && __instance.m_hasRotCatch && __instance.IsSlappable && __instance.m_isAtLockAngle)
{
__state = new UpdateHandleSharedState(boltCanBeSlappedInPrefix: true);
}
}
[HarmonyPostfix]
[HarmonyPatch("UpdateHandle")]
private static void UpdateHandlePostfix(ClosedBoltHandle __instance, ref UpdateHandleSharedState? __state)
{
if (__state != null)
{
FirearmTag component = ((Component)__instance.Weapon).gameObject.GetComponent<FirearmTag>();
if (Object.op_Implicit((Object)(object)component) && __state.BoltCanBeSlappedInPrefix && !__instance.m_isAtLockAngle)
{
component.OnHandleSlap();
}
}
}
}
[HarmonyWrapSafe]
[HarmonyPriority(300)]
[HarmonyPatch(typeof(ClosedBolt))]
internal static class ClosedBoltPatcher
{
[HarmonyPostfix]
[HarmonyPatch("UpdateInteraction")]
private static void UpdateInteractionPostfix(ClosedBolt __instance)
{
FirearmTag component = ((Component)__instance.Weapon).gameObject.GetComponent<FirearmTag>();
if (Object.op_Implicit((Object)(object)component))
{
string itemID = ((FVRPhysicalObject)__instance.Weapon).ObjectWrapper.ItemID;
Plugin.LogVerbose($"[UpdateInteractionPostfix] Updating tag for firearm '{itemID}' ({component})");
if (__instance.Weapon.IsBoltHeldOpen())
{
Plugin.LogVerbose("[UpdateInteractionPostfix] Bolt of firearm '" + itemID + "' is held open");
return;
}
component.OnManualCharge();
Plugin.LogVerbose($"[UpdateInteractionPostfix] Successfully updated tag for firearm '{itemID}' ({component})");
}
}
}
[HarmonyWrapSafe]
[HarmonyPriority(300)]
[HarmonyPatch(typeof(HandgunSlide))]
internal static class HandgunSlidePatcher
{
[HarmonyPostfix]
[HarmonyPatch("EndInteraction")]
private static void EndInteractionPostfix(HandgunSlide __instance)
{
FirearmTag component = ((Component)__instance.Handgun).gameObject.GetComponent<FirearmTag>();
if (Object.op_Implicit((Object)(object)component))
{
string itemID = ((FVRPhysicalObject)__instance.Handgun).ObjectWrapper.ItemID;
Plugin.LogVerbose($"[EndInteractionPostfix] Updating tag for handgun '{itemID}' ({component})");
if (__instance.Handgun.IsSlideHeldOpen())
{
Plugin.LogVerbose("[EndInteractionPostfix] Slide of handgun '" + itemID + "' is being held open");
return;
}
component.OnManualCharge();
Plugin.LogVerbose($"[EndInteractionPostfix] Successfully updated tag for handgun '{itemID}' ({component})");
}
}
}
[HarmonyWrapSafe]
[HarmonyPriority(300)]
[HarmonyPatch(typeof(TubeFedShotgunBolt))]
internal static class TubeFedShotgunBoltPatcher
{
[HarmonyPostfix]
[HarmonyPatch("UpdateBolt")]
private static void UpdateInteractionPostfix(TubeFedShotgunBolt __instance)
{
FirearmTag component = ((Component)__instance.Shotgun).gameObject.GetComponent<FirearmTag>();
if (Object.op_Implicit((Object)(object)component) && ((FVRInteractiveObject)__instance).IsHeld && !__instance.Shotgun.IsTubeFedShotgunBoltHeldOpen())
{
component.OnManualCharge();
}
}
}
[HarmonyWrapSafe]
[HarmonyPriority(300)]
[HarmonyPatch(typeof(TubeFedShotgunHandle))]
internal static class TubeFedShotgunHandlePatcher
{
[HarmonyPostfix]
[HarmonyPatch("UpdateInteraction")]
private static void UpdateInteractionPostfix(TubeFedShotgunHandle __instance)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Invalid comparison between Unknown and I4
FirearmTag component = ((Component)__instance.Shotgun).gameObject.GetComponent<FirearmTag>();
if (Object.op_Implicit((Object)(object)component))
{
string itemID = ((FVRPhysicalObject)__instance.Shotgun).ObjectWrapper.ItemID;
Plugin.LogVerbose($"[UpdateInteractionPostfix] Updating tag for shotgun '{itemID}' ({component})");
if ((int)__instance.Shotgun.Mode == 1)
{
Plugin.LogVerbose("[UpdateInteractionPostfix] Shotgun '" + itemID + "' is in automatic mode");
return;
}
component.OnManualCharge();
Plugin.LogVerbose("[UpdateInteractionPostfix] Successfully updated tag for " + $"shotgun '{itemID}' ({component})");
}
}
}
[HarmonyWrapSafe]
[HarmonyPriority(300)]
[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 class PlayAudioEventSharedState
{
public AudioEvent? OriginalAudioEvent { get; }
public GunEvent.Value Type { get; }
public PlayAudioEventSharedState(GunEvent.Value type, AudioEvent? originalAudioEvent)
{
OriginalAudioEvent = originalAudioEvent;
Type = type;
base..ctor();
}
}
[CompilerGenerated]
private sealed class <ReplaceFirearmAudioSetRoutine>d__19 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public FVRFirearmAudioSet firearmClipSetCopied;
public string itemID;
public string gunAudioSetName;
public FirearmTag firearmTag;
private GunEvent.Value[] <>7__wrap1;
private int <>7__wrap2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ReplaceFirearmAudioSetRoutine>d__19(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>7__wrap1 = null;
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
ProcessGunEvent(firearmClipSetCopied, itemID, gunAudioSetName, GunEvent.Value.MagazineIn);
<>2__current = null;
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
<>7__wrap1 = GunEvent.All;
<>7__wrap2 = 0;
goto IL_00b6;
case 2:
{
<>1__state = -1;
goto IL_00a8;
}
IL_00b6:
if (<>7__wrap2 < <>7__wrap1.Length)
{
GunEvent.Value value = <>7__wrap1[<>7__wrap2];
if (value != GunEvent.Value.MagazineIn)
{
ProcessGunEvent(firearmClipSetCopied, itemID, gunAudioSetName, value);
<>2__current = null;
<>1__state = 2;
return true;
}
goto IL_00a8;
}
<>7__wrap1 = null;
SaveSlideForwardOverrideAudioEventsInFirearmTag(itemID, gunAudioSetName, firearmTag, firearmClipSetCopied);
SaveHandleForwardOverrideAudioEventsInFirearmTag(itemID, gunAudioSetName, firearmTag, firearmClipSetCopied);
Plugin.LogVerbose($"FirearmTag initialization finished ({firearmTag})");
return false;
IL_00a8:
<>7__wrap2++;
goto IL_00b6;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
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("Fire")]
private static void FirePrefix(FVRFireArm __instance)
{
FirearmTag component = ((Component)__instance).gameObject.GetComponent<FirearmTag>();
if (!Object.op_Implicit((Object)(object)component))
{
return;
}
string itemID = ((FVRPhysicalObject)__instance).ObjectWrapper.ItemID;
Plugin.LogVerbose($"[FirePrefix] Updating tag for firearm '{itemID}' ({component})");
ClosedBoltWeapon val = (ClosedBoltWeapon)(object)((__instance is ClosedBoltWeapon) ? __instance : null);
if (val != null && val.WillBoltBeHeldOpenAfterNextShot())
{
Plugin.LogVerbose("[FirePrefix] Bolt of firearm '" + itemID + "' will be held open");
return;
}
Handgun val2 = (Handgun)(object)((__instance is Handgun) ? __instance : null);
if (val2 != null && val2.WillSlideBeHeldOpenAfterNextShot())
{
Plugin.LogVerbose("[FirePrefix] Slide of handgun '" + itemID + "' will be held open");
return;
}
TubeFedShotgun val3 = (TubeFedShotgun)(object)((__instance is TubeFedShotgun) ? __instance : null);
if (val3 != null && val3.WillTubeFedShotgunBoltBeHeldOpenAfterNextShot())
{
Plugin.LogVerbose("[FirePrefix] Bolt of shotgun '" + itemID + "' will be held open, or shotgunis in pump mode");
return;
}
component.OnShot();
Plugin.LogVerbose($"[FirePrefix] Successfully updated tag for firearm '{itemID}' ({component})");
}
[HarmonyPrefix]
[HarmonyPatch(typeof(FVRFireArm), "PlayAudioEvent")]
private static void PlayAudioEventPrefix(FVRFireArm __instance, FirearmAudioEventType eType, ref PlayAudioEventSharedState? __state)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
PlayAudioEventSharedPrefix(__instance, eType, ref __state);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(FVRFireArm), "PlayAudioEvent")]
private static void PlayAudioEventPostfix(FVRFireArm __instance, ref PlayAudioEventSharedState? __state)
{
PlayAudioEventSharedPostfix(__instance, ref __state);
}
[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(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel(), name, gunEvent.ToString(), itemID).FirstOrDefault();
AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel(), 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)
{
AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
if (resourceReferences != null)
{
num = ((resourceReferences.Length > 0) ? 1 : 0);
goto IL_024e;
}
}
}
}
num = 0;
goto IL_024e;
IL_0283:
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.ReplaceAudioEventByGunEventFromAddonAsset(asset2, gunEvent);
}
else
{
AddonAsset asset3 = assetNode.Asset;
firearm.AudioClipSet.ReplaceAudioEventByGunEventFromAddonAsset(asset3, gunEvent);
}
return;
IL_024e:
if (assetNode2 != null)
{
AddonAsset asset = assetNode2.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
if (resourceReferences != null)
{
num2 = ((resourceReferences.Length > 0) ? 1 : 0);
goto IL_0283;
}
}
}
}
num2 = 0;
goto IL_0283;
}
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;
}
}
private static void PlayAudioEventSharedPrefix(FVRFireArm firearm, FirearmAudioEventType fvrAudioEventType, ref PlayAudioEventSharedState? state)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Invalid comparison between Unknown and I4
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Invalid comparison between Unknown and I4
GunEvent.Value? value = (((int)fvrAudioEventType == 0) ? new GunEvent.Value?(GunEvent.Value.BoltSlideForward) : (((int)fvrAudioEventType != 11) ? null : new GunEvent.Value?(GunEvent.Value.HandleForward)));
GunEvent.Value? value2 = value;
if (!value2.HasValue || !Object.op_Implicit((Object)(object)((FVRPhysicalObject)firearm).ObjectWrapper))
{
return;
}
string itemID = ((FVRPhysicalObject)firearm).ObjectWrapper.ItemID;
if (itemID == null)
{
Plugin.Log.LogWarning((object)"[PlayAudioEventSharedPrefix] Did not replace audio for firearm because its ItemID is null.");
return;
}
if (_gunSoundLoader == null || _gunAudioSetLoader == null)
{
Plugin.Log.LogError((object)"[PlayAudioEventSharedPrefix] Failed to replace audio for magazine because 'FVRFireArmPatcher' has not been initialized yet.");
return;
}
if (!Object.op_Implicit((Object)(object)firearm.AudioClipSet))
{
Plugin.Log.LogWarning((object)("[PlayAudioEventSharedPrefix] Did not replace slide audio for firearm with ItemID '" + itemID + "' because the AudioClipSet of the instance is null."));
return;
}
FirearmTag component = ((Component)firearm).GetComponent<FirearmTag>();
if (!Object.op_Implicit((Object)(object)component))
{
Plugin.Log.LogError((object)("[PlayAudioEventSharedPrefix] Did not replace slide audio for firearm with ItemID '" + itemID + "' because FirearmTag is null."));
return;
}
AudioEvent val = (((int)fvrAudioEventType == 0) ? component.GetLatestSlideForwardCircumstanceAudioEvent() : (((int)fvrAudioEventType != 11) ? null : component.GetLatestHandleForwardCircumstanceAudioEvent()));
AudioEvent val2 = val;
if (val2 == null)
{
Plugin.LogVerbose("[PlayAudioEventSharedPrefix] Did not replace audio for firearm with ItemID '" + itemID + "' because there is no available circumstance override.");
return;
}
AudioEvent audioEventBy = firearm.AudioClipSet.GetAudioEventBy(value2.Value);
state = new PlayAudioEventSharedState(value2.Value, audioEventBy.DeepCopy());
firearm.AudioClipSet.ReplaceAudioEventBy(value2.Value, val2);
}
private static void PlayAudioEventSharedPostfix(FVRFireArm firearm, ref PlayAudioEventSharedState? state)
{
if (state?.OriginalAudioEvent != null)
{
Plugin.LogVerbose($"[PlayAudioEventSharedPostfix] Setting {state.Type} back to default clip.");
firearm.AudioClipSet.ReplaceAudioEventBy(state.Type, state.OriginalAudioEvent);
}
}
[HarmonyPostfix]
[HarmonyPatch("Awake")]
private static void AwakePostfix(FVRFireArm __instance)
{
ReplaceFirearmAudioSet(__instance, isModular: false);
}
public static void ReplaceFirearmAudioSet(FVRFireArm fvrFirearm, bool isModular)
{
if ((Object)(object)((FVRPhysicalObject)fvrFirearm).ObjectWrapper == (Object)null)
{
return;
}
string itemID = ((FVRPhysicalObject)fvrFirearm).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)(object)fvrFirearm.AudioClipSet == (Object)null)
{
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)fvrFirearm.AudioClipSet).name;
if (isModular)
{
Plugin.Log.LogMessage((object)("Replacing/updating audio for modular firearm with ItemID '" + itemID + "' and audio set '" + name + "'"));
}
else
{
Plugin.Log.LogMessage((object)("Attempting to replace audio for firearm with ItemID '" + itemID + "' and audio set '" + name + "'"));
}
FVRFirearmAudioSet firearmClipSetCopied = (fvrFirearm.AudioClipSet = fvrFirearm.AudioClipSet.DeepCopy());
FirearmTag firearmTag = ((Component)fvrFirearm).GetComponent<FirearmTag>();
if (!Object.op_Implicit((Object)(object)firearmTag))
{
firearmTag = ((Component)fvrFirearm).gameObject.AddComponent<FirearmTag>();
((Object)firearmTag).hideFlags = (HideFlags)61;
}
CoroutineRunner.Run(ReplaceFirearmAudioSetRoutine(firearmClipSetCopied, itemID, name, firearmTag));
}
private static IEnumerator ReplaceFirearmAudioSetRoutine(FVRFirearmAudioSet firearmClipSetCopied, string itemID, string gunAudioSetName, FirearmTag firearmTag)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ReplaceFirearmAudioSetRoutine>d__19(0)
{
firearmClipSetCopied = firearmClipSetCopied,
itemID = itemID,
gunAudioSetName = gunAudioSetName,
firearmTag = firearmTag
};
}
private static void ProcessGunEvent(FVRFirearmAudioSet firearmClipSetCopied, string itemID, string gunAudioSetName, GunEvent.Value gunEvent)
{
string text = itemID + ":" + gunEvent;
string text2 = gunAudioSetName + ":" + gunEvent;
Plugin.LogVerbose("Attempting to replace firearm audio for '" + text + "' and '" + text2 + "'");
AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader?.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQuery(), gunAudioSetName, gunEvent.ToString()).FirstOrDefault();
AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader?.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQuery(), 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)
{
AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
if (resourceReferences != null)
{
num = ((resourceReferences.Length > 0) ? 1 : 0);
goto IL_0119;
}
}
}
}
num = 0;
goto IL_0119;
IL_014c:
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;
firearmClipSetCopied.ReplaceAudioEventByGunEventFromAddonAsset(asset2, gunEvent);
}
else
{
AddonAsset asset3 = assetNode.Asset;
firearmClipSetCopied.ReplaceAudioEventByGunEventFromAddonAsset(asset3, gunEvent);
}
return;
IL_0119:
if (assetNode2 != null)
{
AddonAsset asset = assetNode2.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
if (resourceReferences != null)
{
num2 = ((resourceReferences.Length > 0) ? 1 : 0);
goto IL_014c;
}
}
}
}
num2 = 0;
goto IL_014c;
}
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 SaveSlideForwardOverrideAudioEventsInFirearmTag(string itemID, string gunAudioSetName, FirearmTag firearmTag, FVRFirearmAudioSet firearmAudioSet)
{
if (_gunAudioSetLoader == null || _gunSoundLoader == null)
{
return;
}
BoltSlideForwardCircumstance.Value[] all = BoltSlideForwardCircumstance.All;
foreach (BoltSlideForwardCircumstance.Value value in all)
{
Plugin.LogVerbose("[SaveSlideForwardOverrideAudioEventsInFirearmTag] " + $"Attempting to find sound replacements for '{value}' for " + "'" + itemID + "' and '" + gunAudioSetName + "'");
string[] targetPath = value.GetTargetPath();
List<string> list = new List<string>(2) { gunAudioSetName, "BoltSlideForward" };
List<string> list2 = new List<string>(2) { itemID, "BoltSlideForward" };
list.AddRange(targetPath);
list2.AddRange(targetPath);
string text = StringUtils.JoinValues(list, ':'.ToString());
string text2 = StringUtils.JoinValues(list2, ':'.ToString());
Plugin.LogVerbose("[SaveSlideForwardOverrideAudioEventsInFirearmTag] Attempting to load '" + text + "' and '" + text2 + "'");
AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndSpecifications(3, 4), list.ToArray()).FirstOrDefault();
AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndSpecifications(3, 4), list2.ToArray()).FirstOrDefault();
try
{
int num;
if (assetNode != null)
{
AddonAsset asset = assetNode.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
if (resourceReferences != null)
{
num = ((resourceReferences.Length > 0) ? 1 : 0);
goto IL_019b;
}
}
}
}
num = 0;
goto IL_019b;
IL_01d0:
int num2;
bool flag = (byte)num2 != 0;
if (num == 0 && !flag)
{
Plugin.LogVerbose("[SaveSlideForwardOverrideAudioEventsInFirearmTag] Could not find '" + text + "' and '" + text2 + "'");
continue;
}
Plugin.LogVerbose("[SaveSlideForwardOverrideAudioEventsInFirearmTag] Saving '" + text + "' and '" + text2 + "' in firearm tag");
AudioEvent val = firearmAudioSet.BoltSlideForward.DeepCopy();
if (val != null)
{
AddonAsset asset = ((!flag) ? assetNode.Asset : assetNode2.Asset);
AddonAsset addonAsset = asset;
val.ReplaceClipsInAudioEvent(addonAsset);
firearmTag.SaveBoltSlideForwardCircumstanceAudioEvent(val, value);
}
goto end_IL_0166;
IL_019b:
if (assetNode2 != null)
{
AddonAsset asset = assetNode2.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
if (resourceReferences != null)
{
num2 = ((resourceReferences.Length > 0) ? 1 : 0);
goto IL_01d0;
}
}
}
}
num2 = 0;
goto IL_01d0;
end_IL_0166:;
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("[SaveSlideForwardOverrideAudioEventsInFirearmTag] Failed to replace audio for '" + text + "' and '" + text2 + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
}
}
}
private static void SaveHandleForwardOverrideAudioEventsInFirearmTag(string itemID, string gunAudioSetName, FirearmTag firearmTag, FVRFirearmAudioSet firearmAudioSet)
{
if (_gunAudioSetLoader == null || _gunSoundLoader == null)
{
return;
}
HandleForwardCircumstance.Value[] all = HandleForwardCircumstance.All;
foreach (HandleForwardCircumstance.Value value in all)
{
Plugin.LogVerbose("[SaveHandleForwardOverrideAudioEventsInFirearmTag] " + $"Attempting to find sound replacements for '{value}' for " + "'" + itemID + "' and '" + gunAudioSetName + "'");
string[] targetPath = value.GetTargetPath();
List<string> list = new List<string>(2) { gunAudioSetName, "HandleForward" };
List<string> list2 = new List<string>(2) { itemID, "HandleForward" };
list.AddRange(targetPath);
list2.AddRange(targetPath);
string text = StringUtils.JoinValues(list, ':'.ToString());
string text2 = StringUtils.JoinValues(list2, ':'.ToString());
Plugin.LogVerbose("[SaveHandleForwardOverrideAudioEventsInFirearmTag] Attempting to load '" + text + "' and '" + text2 + "'");
AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndSpecifications(3, 4), list.ToArray()).FirstOrDefault();
AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndSpecifications(3, 4), list2.ToArray()).FirstOrDefault();
try
{
int num;
if (assetNode != null)
{
AddonAsset asset = assetNode.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
if (resourceReferences != null)
{
num = ((resourceReferences.Length > 0) ? 1 : 0);
goto IL_019b;
}
}
}
}
num = 0;
goto IL_019b;
IL_01d0:
int num2;
bool flag = (byte)num2 != 0;
if (num == 0 && !flag)
{
Plugin.LogVerbose("[SaveHandleForwardOverrideAudioEventsInFirearmTag] Could not find '" + text + "' and '" + text2 + "'");
continue;
}
Plugin.LogVerbose("[SaveHandleForwardOverrideAudioEventsInFirearmTag] Saving '" + text + "' and '" + text2 + "' in firearm tag");
AudioEvent val = firearmAudioSet.HandleForward.DeepCopy();
if (val != null)
{
AddonAsset asset = ((!flag) ? assetNode.Asset : assetNode2.Asset);
AddonAsset addonAsset = asset;
val.ReplaceClipsInAudioEvent(addonAsset);
firearmTag.SaveHandleForwardCircumstanceAudioEvent(val, value);
}
goto end_IL_0166;
IL_019b:
if (assetNode2 != null)
{
AddonAsset asset = assetNode2.Asset;
if (asset != null)
{
AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
if (assetMapping != null)
{
AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
if (resourceReferences != null)
{
num2 = ((resourceReferences.Length > 0) ? 1 : 0);
goto IL_01d0;
}
}
}
}
num2 = 0;
goto IL_01d0;
end_IL_0166:;
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("[SaveHandleForwardOverrideAudioEventsInFirearmTag] Failed to replace audio for '" + text + "' and '" + text2 + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
}
}
}
private static void ReplaceAudioEventByGunEventFromAddonAsset(this FVRFirearmAudioSet fvrFirearmAudioSet, AddonAsset addonAsset, GunEvent.Value gunEvent)
{
fvrFirearmAudioSet.GetAudioEventBy(gunEvent).ReplaceClipsInAudioEvent(addonAsset);
}
private static void ReplaceClipsInAudioEvent(this AudioEvent audioEvent, AddonAsset addonAsset)
{
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_011b: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
List<AudioClip> list = new List<AudioClip>();
AddonManifest.AssetReference[] resourceReferences = addonAsset.AssetMapping.ResourceReferences;
foreach (AddonManifest.AssetReference replacement in resourceReferences)
{
AudioClip val = addonAsset.SourceAddon.LoadAudioClip(replacement, gunSound: true);
((Object)val).name = ReplacementAudioClipName;
list.Add(val);
}
audioEvent.Clips = list;
float[] array = (addonAsset.AssetMapping as AddonManifest.AssetMapping.Audio)?.VolumeRange;
float[] array2 = (addonAsset.AssetMapping as AddonManifest.AssetMapping.Audio)?.VolumeMultiplierRange;
float[] array3 = (addonAsset.AssetMapping as AddonManifest.AssetMapping.Audio)?.PitchRange;
float[] array4 = (addonAsset.AssetMapping as AddonManifest.AssetMapping.Audio)?.PitchMultiplierRange;
if (array != null)
{
audioEvent.VolumeRange = new Vector2(array[0], array[1]);
}
if (array2 != null)
{
float num = Random.Range(array2[0], array2[1]);
float num2 = Random.Range(array2[0], array2[1]);
audioEvent.VolumeRange = new Vector2(audioEvent.VolumeRange.x * num, audioEvent.VolumeRange.y * num2);
}
if (array3 != null)
{
audioEvent.PitchRange = new Vector2(array3[0], array3[1]);
}
if (array4 != null)
{
float num3 = Random.Range(array4[0], array4[1]);
float num4 = Random.Range(array4[0], array4[1]);
audioEvent.PitchRange = new Vector2(audioEvent.PitchRange.x * num3, audioEvent.PitchRange.y * num4);
}
}
}
[HarmonyPatch(typeof(ModularBarrelExtension))]
internal static class ModularBarrelExtensionPatcher
{
private static readonly FieldInfo _firearm = AccessTools.Field(typeof(ModularBarrelExtension), "_firearm");
[HarmonyPostfix]
[HarmonyPatch("DisablePart")]
private static void DisablePart_Postfix(ModularBarrelExtension __instance)
{
ModularBarrelExtension __instance2 = __instance;
Plugin.ExceptionCatcher.Run(delegate
{
Plugin.Log.LogDebug((object)"ModularBarrel DisablePart patcher");
FVRFireArm val = __instance2.Access<FVRFireArm>(_firearm);
if ((Object)(object)val != (Object)null)
{
FVRFireArmPatcher.ReplaceFirearmAudioSet(val, isModular: true);
}
});
}
[HarmonyPostfix]
[HarmonyPatch("EnablePart")]
private static void EnablePart_Postfix(ModularBarrelExtension __instance)
{
ModularBarrelExtension __instance2 = __instance;
Plugin.ExceptionCatcher.Run(delegate
{
Plugin.Log.LogDebug((object)"ModularBarrel EnablePart patcher");
FVRFireArm val = __instance2.Access<FVRFireArm>(_firearm);
if ((Object)(object)val != (Object)null)
{
FVRFireArmPatcher.ReplaceFirearmAudioSet(val, isModular: true);
}
});
}
}
internal static class OldSideloaderPatcher
{
public static void ApplyPatch()
{
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Expected O, but got Unknown
Type type = AccessTools.TypeByName("H3VR.Sideloader.AssetLoaders.AudioClipLoader");
if ((object)type == null)
{
Plugin.Log.LogError((object)"Old Sideloader type is null.");
return;
}
MethodInfo methodInfo = AccessTools.Method(type, "OnAudioSourcePlay", (Type[])null, (Type[])null);
if ((object)methodInfo == null)
{
Plugin.Log.LogError((object)"Old Sideloader method is null.");
}
else
{
new Harmony("Sirdoggy.SideloaderMint/OldSideloaderPatcher").Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(OldSideloaderPatcher), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
}
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Expected O, but got Unknown
List<CodeInstruction> list = instructions.ToList();
try
{
for (int i = 0; i < list.Count; i++)
{
if (CodeInstructionExtensions.Calls(list[i], AccessTools.PropertySetter(typeof(AudioSource), "clip")))
{
list[i] = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(OldSideloaderPatcher), "SetClipWithPreservedName", (Type[])null, (Type[])null));
break;
}
}
return list;
}
catch (Exception arg)
{
Plugin.Log.LogError((object)$"Exception in transpiler: {arg}");
return list;
}
}
private static void SetClipWithPreservedName(AudioSource instance, AudioClip newClip)
{
string name = ((Object)newClip).name;
AudioClip clip = instance.clip;
string text = ((clip != null) ? ((Object)clip).name : null);
instance.clip = newClip;
if (text != null)
{
((Object)instance.clip).name = text;
Plugin.LogVerbose("Patched old Sideloader method, restoring clip name: " + name + " => " + text);
}
}
}
}
namespace Sirdoggy.SideloaderMint.Patchers.Tags
{
internal class FirearmTag : MonoBehaviour
{
private const double CircumstanceValidityTimeSpanMillis = 250.0;
private AudioEvent? _boltSlideForwardAfterManualChargeAudioEvent;
private AudioEvent? _boltSlideForwardAfterHandleSlapAudioEvent;
private AudioEvent? _boltSlideForwardAfterShotAudioEvent;
private AudioEvent? _handleForwardAfterHandleSlapAudioEvent;
private float? _lastManualChargeTime;
private float? _lastHandleSlapTimeSlideForward;
private float? _lastHandleSlapTimeHandleForward;
private float? _lastShotTime;
public void SaveBoltSlideForwardCircumstanceAudioEvent(AudioEvent audioEvent, BoltSlideForwardCircumstance.Value circumstance)
{
switch (circumstance)
{
case BoltSlideForwardCircumstance.Value.Shot:
_boltSlideForwardAfterShotAudioEvent = audioEvent;
break;
case BoltSlideForwardCircumstance.Value.HandleSlap:
_boltSlideForwardAfterHandleSlapAudioEvent = audioEvent;
break;
case BoltSlideForwardCircumstance.Value.ManualCharge:
_boltSlideForwardAfterManualChargeAudioEvent = audioEvent;
break;
}
}
public void SaveHandleForwardCircumstanceAudioEvent(AudioEvent audioEvent, HandleForwardCircumstance.Value circumstance)
{
if (circumstance == HandleForwardCircumstance.Value.HandleSlap)
{
_handleForwardAfterHandleSlapAudioEvent = audioEvent;
}
}
public void OnManualCharge()
{
_lastManualChargeTime = Time.time;
_lastHandleSlapTimeHandleForward = null;
}
public void OnHandleSlap()
{
_lastHandleSlapTimeSlideForward = Time.time;
_lastHandleSlapTimeHandleForward = Time.time;
}
public void OnShot()
{
_lastShotTime = Time.time;
}
public AudioEvent? GetLatestSlideForwardCircumstanceAudioEvent()
{
List<KeyValuePair<AudioEvent, float?>> list = (from pair in new List<KeyValuePair<AudioEvent, float?>>
{
new KeyValuePair<AudioEvent, float?>(_boltSlideForwardAfterManualChargeAudioEvent, _lastManualChargeTime),
new KeyValuePair<AudioEvent, float?>(_boltSlideForwardAfterHandleSlapAudioEvent, _lastHandleSlapTimeSlideForward),
new KeyValuePair<AudioEvent, float?>(_boltSlideForwardAfterShotAudioEvent, _lastShotTime)
}
where IsValidLastTime(pair.Value)
orderby pair.Value descending
select pair).ToList();
_lastManualChargeTime = null;
_lastHandleSlapTimeSlideForward = null;
_lastShotTime = null;
if (list.Count == 0)
{
return null;
}
return list.First().Key;
}
public AudioEvent? GetLatestHandleForwardCircumstanceAudioEvent()
{
List<KeyValuePair<AudioEvent, float?>> list = (from pair in new List<KeyValuePair<AudioEvent, float?>>
{
new KeyValuePair<AudioEvent, float?>(_handleForwardAfterHandleSlapAudioEvent, _lastHandleSlapTimeHandleForward)
}
where IsValidLastTime(pair.Value)
orderby pair.Value descending
select pair).ToList();
_lastHandleSlapTimeHandleForward = null;
if (list.Count == 0)
{
return null;
}
return list.First().Key;
}
private static bool IsValidLastTime(float? time)
{
if (!time.HasValue)
{
return false;
}
return (double?)((Time.time - time) * 1000f) < 250.0;
}
public override string ToString()
{
return StringUtils.FormatTypeProperties("FirearmTag", new <>z__ReadOnlyArray<string>(new string[4]
{
string.Format("{0}: {1}", "_lastManualChargeTime", _lastManualChargeTime),
string.Format("{0}: {1}", "_lastHandleSlapTimeSlideForward", _lastHandleSlapTimeSlideForward),
string.Format("{0}: {1}", "_lastShotTime", _lastShotTime),
string.Format("{0}: {1}", "_lastHandleSlapTimeHandleForward", _lastHandleSlapTimeHandleForward)
}));
}
}
}
namespace Sirdoggy.SideloaderMint.Patchers.Extensions
{
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 BoltStateExtensions
{
public static bool IsBoltHeldOpen(this ClosedBoltWeapon firearm)
{
if (!firearm.Bolt.IsBoltLocked() && !firearm.IsBoltCatchButtonHeld)
{
if (firearm.Bolt.HasLastRoundBoltHoldOpen && Object.op_Implicit((Object)(object)((FVRFireArm)firearm).Magazine) && !((FVRFireArm)firearm).Magazine.HasARound())
{
return !firearm.Chamber.IsFull;
}
return false;
}
return true;
}
public static bool WillBoltBeHeldOpenAfterNextShot(this ClosedBoltWeapon firearm)
{
if (!firearm.IsBoltCatchButtonHeld)
{
if (firearm.Bolt.HasLastRoundBoltHoldOpen && Object.op_Implicit((Object)(object)((FVRFireArm)firearm).Magazine))
{
return !((FVRFireArm)firearm).Magazine.HasARound();
}
return false;
}
return true;
}
public static bool IsSlideHeldOpen(this Handgun handgun)
{
if ((handgun == null || !handgun.DoesSafetyLockSlide || !handgun.IsSafetyEngaged) && !handgun.IsSLideLockMechanismEngaged)
{
return handgun.IsSlideCatchEngaged();
}
return true;
}
public static bool WillSlideBeHeldOpenAfterNextShot(this Handgun handgun)
{
if (handgun.HasSlideRelease && Object.op_Implicit((Object)(object)((FVRFireArm)handgun).Magazine))
{
return !((FVRFireArm)handgun).Magazine.HasARound();
}
return false;
}
public static bool IsTubeFedShotgunBoltHeldOpen(this TubeFedShotgun shotgun)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
if ((int)shotgun.Mode == 1)
{
if (!shotgun.Bolt.m_isBoltLocked)
{
if (shotgun.Bolt.HasLastRoundBoltHoldOpen && Object.op_Implicit((Object)(object)((FVRFireArm)shotgun).Magazine) && !((FVRFireArm)shotgun).Magazine.HasARound())
{
return !shotgun.Chamber.IsFull;
}
return false;
}
return true;
}
return false;
}
public static bool WillTubeFedShotgunBoltBeHeldOpenAfterNextShot(this TubeFedShotgun shotgun)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
if ((int)shotgun.Mode == 1 && shotgun.Bolt.HasLastRoundBoltHoldOpen && Object.op_Implicit((Object)(object)((FVRFireArm)shotgun).Magazine))
{
return !((FVRFireArm)shotgun).Magazine.HasARound();
}
return false;
}
}
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 GetAudioEventBy(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("Unsupported GunEvent"),
});
}
public static void ReplaceAudioEventBy(this FVRFirearmAudioSet clipSet, GunEvent.Value gunEvent, AudioEvent audioEvent)
{
switch (gunEvent)
{
case GunEvent.Value.BoltSlideForward:
clipSet.BoltSlideForward = audioEvent;
break;
case GunEvent.Value.HandleForward:
clipSet.HandleForward = audioEvent;
break;
default:
throw new NotSupportedException("Unsupported 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;
}
}
}
namespace Sirdoggy.SideloaderMint.Model
{
internal static class BoltSlideForwardCircumstance
{
public enum Value
{
ManualCharge,
HandleSlap,
Shot
}
public static Value[] All => Enum.GetValues(typeof(Value)).Cast<Value>().ToArray();
public static string[] GetTargetPath(this Value value)
{
return value switch
{
Value.Shot => new string[1] { "AfterShot" },
Value.HandleSlap => new string[2] { "AfterManualCharge", "AfterHKSlap" },
Value.ManualCharge => new string[1] { "AfterManualCharge" },
_ => throw new NotSupportedException("Unknown BoltSlideForwardCircumstance value"),
};
}
}
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 Value[] All => Enum.GetValues(typeof(Value)).Cast<Value>().ToArray();
}
internal static class HandleForwardCircumstance
{
public enum Value
{
HandleSlap
}
public static Value[] All => Enum.GetValues(typeof(Value)).Cast<Value>().ToArray();
public static string[] GetTargetPath(this Value value)
{
if (value == Value.HandleSlap)
{
return new string[1] { "AfterHKSlap" };
}
throw new NotSupportedException("Unknown BoltSlideForwardCircumstance value");
}
}
}
namespace Sirdoggy.SideloaderMint.Common
{
internal class ConfigFileWrapper
{
public class SimpleConfigEntry<T>
{
public string Section { get; }
public string Key { get; }
public T DefaultValue { get; }
public string? Description { get; }
public NullableGeneric<T> SavedConfigValue { get; set; }
public SimpleConfigEntry(string section, string key, T defaultValue, string? description = null)
{
Section = section;
Key = key;
DefaultValue = defaultValue;
Description = description;
SavedConfigValue = NullableGeneric<T>.Null;
base..ctor();
}
public override string ToString()
{
return StringUtils.FormatTypeProperties("SimpleConfigEntry", new <>z__ReadOnlyArray<string>(new string[5]
{
"Section: " + Section,
"Key: " + Key,
string.Format("{0}: {1}", "DefaultValue", DefaultValue),
"Description: " + Description,
string.Format("{0}: {1}", "SavedConfigValue", SavedConfigValue)
}));
}
}
private readonly string _configFilePath;
private ConfigFile _configFile;
private readonly List<SimpleConfigEntry<bool>> _trackedBoolEntries = new List<SimpleConfigEntry<bool>>();
private readonly List<SimpleConfigEntry<int>> _trackedIntEntries = new List<SimpleConfigEntry<int>>();
public ConfigFileWrapper()
{
}
public ConfigFileWrapper(string configFileName)
: this()
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Expected O, but got Unknown
_configFilePath = Path.Combine(Paths.ConfigPath, configFileName);
_configFile = new ConfigFile(_configFilePath, true);
}
public bool BindBool(SimpleConfigEntry<bool> simpleConfigEntry)
{
ConfigEntry<bool> val = BindFromSimpleConfigEntry(simpleConfigEntry);
simpleConfigEntry.SavedConfigValue = val.Value;
_trackedBoolEntries.Add(simpleConfigEntry);
return val.Value;
}
public int BindInt(SimpleConfigEntry<int> simpleConfigEntry)
{
ConfigEntry<int> val = BindFromSimpleConfigEntry(simpleConfigEntry);
simpleConfigEntry.SavedConfigValue = val.Value;
_trackedIntEntries.Add(simpleConfigEntry);
return val.Value;
}
public void ClearUntrackedEntries()
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
Plugin.Log.LogDebug((object)"Recreating config file...");
File.Delete(_configFilePath);
_configFile = new ConfigFile(_configFilePath, true);
foreach (SimpleConfigEntry<bool> trackedBoolEntry in _trackedBoolEntries)
{
Plugin.Log.LogDebug((object)$"Recreating {trackedBoolEntry}...");
BindFromSimpleConfigEntry(trackedBoolEntry);
}
foreach (SimpleConfigEntry<int> trackedIntEntry in _trackedIntEntries)
{
Plugin.Log.LogDebug((object)$"Recreating {trackedIntEntry}...");
BindFromSimpleConfigEntry(trackedIntEntry);
}
Plugin.Log.LogInfo((object)"Finished removing untracked config keys!");
}
private ConfigEntry<T> BindFromSimpleConfigEntry<T>(SimpleConfigEntry<T> simpleConfigEntry)
{
ConfigEntry<T> val = ((simpleConfigEntry.Description == null) ? _configFile.Bind<T>(simpleConfigEntry.Section, simpleConfigEntry.Key, simpleConfigEntry.DefaultValue, (ConfigDescription)null) : _configFile.Bind<T>(simpleConfigEntry.Section, simpleConfigEntry.Key, simpleConfigEntry.DefaultValue, simpleConfigEntry.Description));
if (val == null)
{
throw new NullReferenceException("configEntry is null, this shouldn't happen");
}
if (simpleConfigEntry.SavedConfigValue.HasValue)
{
val.Value = simpleConfigEntry.SavedConfigValue.Value;
_configFile.Save();
}
return val;
}
}
internal static class DictionaryExtensions
{
public static TValue GetOrCreateDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key) where TValue : new()
{
if (!dictionary.ContainsKey(key))
{
dictionary.Add(key, new TValue());
}
return dictionary[key];
}
public static bool AddIfUnique<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (!dictionary.ContainsKey(key))
{
dictionary.Add(key, value);
return true;
}
return false;
}
public static TValue? GetValueOrNull<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key) where TKey : notnull where TValue : class
{
if (!dictionary.TryGetValue(key, out TValue value))
{
return null;
}
return value;
}
}
internal static class ListExtensions
{
public static bool AddIfUnique<T>(this List<T> list, T value)
{
if (!list.Contains(value))
{
list.Add(value);
return true;
}
return false;
}
}
internal class ExceptionCatcher
{
private readonly ManualLogSource _log;
public ExceptionCatcher(ManualLogSource log)
{
_log = log;
}
public void Run(Action action)
{
try
{
action();
}
catch (Exception ex)
{
_log.LogError((object)ex);
}
}
}
internal readonly struct NullableGeneric<T>
{
private readonly T _value;
public bool HasValue { get; }
public T Value
{
get
{
if (!HasValue)
{
throw new InvalidOperationException("NullableGeneric has no value.");
}
return _value;
}
}
public static NullableGeneric<T> Null => default(NullableGeneric<T>);
public NullableGeneric(T value)
{
HasValue = false;
_value = value;
HasValue = true;
}
public override string ToString()
{
if (!HasValue)
{
return "null";
}
T value = _value;
return ((value != null) ? value.ToString() : null) ?? "null";
}
public static implicit operator NullableGeneric<T>(T value)
{
return new NullableGeneric<T>(value);
}
}
internal static class ReflectionExtensions
{
public static T Access<T>(this object obj, FieldInfo field)
{
return (T)field.GetValue(obj);
}
public static Action<T> Delegate<T>(string methodName)
{
return (Action<T>)System.Delegate.CreateDelegate(typeof(Action<T>), AccessTools.Method(typeof(T), methodName, (Type[])null, (Type[])null));
}
public static Action<T, TParam1> Delegate<T, TParam1>(string methodName)
{
return (Action<T, TParam1>)System.Delegate.CreateDelegate(typeof(Action<T, TParam1>), AccessTools.Method(typeof(T), methodName, (Type[])null, (Type[])null));
}
}
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 static string RemoveFirstOccurenceOf(string input, string toRemove)
{
int num = input.IndexOf(toRemove, StringComparison.Ordinal);
if (num < 0)
{
return input;
}
return input.Remove(num, toRemove.Length);
}
}
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 ValidatePathIsPartOfBasePath(string basePath, string actualFullPath)
{
string text = Path.GetFullPath(basePath).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
char directorySeparatorChar = Path.DirectorySeparatorChar;
string value = text + directorySeparatorChar;
if (!Path.GetFullPath(actualFullPath).StartsWith(value, StringComparison.OrdinalIgnoreCase))
{
throw new UnauthorizedAccessException("Path '" + actualFullPath + "' is not allowed to access resource outside of 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_0059: Unknown result type (might be due to invalid IL or missing references)
JToken val = default(JToken);
if (jObject.TryGetValue("$schema", ref val))
{
Plugin.Log.LogDebug((object)"Removing $schema from jObject");
jObject.Remove("$schema");
}
JsonReader val2 = ((JToken)jObject).CreateReader() ?? throw new Exception("Failed to create json reader.");
T val3 = Serializer.Deserialize<T>(val2);
if (val3 == null)
{
throw new JsonSerializationException("Json deserialization failed.");
}
return val3;
}
}
public static class ThunderstoreNameValidator
{
public static bool IsValid(string text)
{
return Regex.IsMatch(text, "^[a-zA-Z0-9_]+$");
}
}
public static class SubAddonNameValidator
{
public static bool IsValid(string text)
{
return Regex.IsMatch(text, "^[a-zA-Z0-9_ .,()]+$");
}
}
}
namespace Sirdoggy.SideloaderMint.Common.Structures
{
public class AssetTree<TAsset>
{
public abstract class FindBehaviour
{
public sealed class GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment : FindBehaviour
{
}
public sealed class GetMostSpecificThatMatchesQuery : FindBehaviour
{
}
public sealed class GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel : FindBehaviour
{
}
public sealed class GetMostSpecificThatMatchesQueryAndSpecifications : FindBehaviour
{
public int MinLevel { get; }
public int MaxLevel { get; }
public GetMostSpecificThatMatchesQueryAndSpecifications(int minLevel, int maxLevel)
{
MinLevel = minLevel;
MaxLevel = maxLevel;
base..ctor();
}
}
}
public interface INode
{
}
public abstract class TraversableNode : INode
{
public IntermediateNode? IntermediateWildcardChild;
public AssetNode? AssetNodeChild;
public abstract int Level { get; }
public Dictionary<string, IntermediateNode> IntermediateChildren { get; } = new Dictionary<string, IntermediateNode>();
public List<INode> Children
{
get
{
List<INode> list = new List<INode>();
list.AddRange(IntermediateChildren.Values.Cast<INode>());
if (IntermediateWildcardChild != null)
{
list.Add(IntermediateWildcardChild);
}
if (AssetNodeChild != null)
{
list.Add(AssetNodeChild);
}
return list;
}
}
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;
[CompilerGenerated]
private Action<string>? <onTargetConflict>P;
private readonly RootNode _rootNode;
public AssetTree(int maxIntermediateLevels, Action<string>? onTargetConflict = null)
{
<maxIntermediateLevels>P = maxIntermediateLevels;
<onTargetConflict>P = onTargetConflict;
_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 text in array2)
{
IntermediateNode intermediateNode;
if (text == null)
{
intermediateNode = ((traversableNode.IntermediateWildcardChild != null) ? traversableNode.IntermediateWildcardChild : (traversableNode.IntermediateWildcardChild = new IntermediateNode(traversableNode.Level + 1, null)));
}
else
{
IntermediateNode valueOrNull = traversableNode.IntermediateChildren.GetValueOrNull(text);
if (valueOrNull == null)
{
intermediateNode = new IntermediateNode(traversableNode.Level + 1, text);
traversableNode.IntermediateChildren.Add(text, intermediateNode);
}
else
{
intermediateNode = valueOrNull;
}
}
traversableNode = intermediateNode;
}
if (traversableNode.AssetNodeChild != null)
{
<onTargetConflict>P?.Invoke(target);
return;
}
AssetNode assetNodeChild = new AssetNode(traversableNode.Level + 1, asset, (array.Length == <maxIntermediateLevels>P && <maxIntermediateLevels>P > 0) ? array[<maxIntermediateLevels>P - 1] : null);
traversableNode.AssetNodeChild = assetNodeChild;
}
public AssetNode[] Find(FindBehaviour behaviour, params string[] segmentedQuery)
{
string[] segmentedQuery2 = segmentedQuery;
FindBehaviour behaviour2 = behaviour;
if (segmentedQuery2.Length > <maxIntermediateLevels>P)
{
throw new ArgumentException("Segmented query is longer than max intermediate levels");
}
AssetNode[] array = SearchIntermediateNodesInNode(_rootNode);
if (array.Length != 0)
{
return array;
}
if (behaviour2 is FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel && segmentedQuery2.Length != 0)
{
return new AssetNode[0];
}
if (_rootNode.AssetNodeChild != null)
{
return new AssetNode[1] { _rootNode.AssetNodeChild };
}
return new AssetNode[0];
static void CollectAllChildNodesFromCurrent(TraversableNode currentNode, List<AssetNode> collectedAssetNodes)
{
foreach (IntermediateNode value in currentNode.IntermediateChildren.Values)
{
CollectAllChildNodesFromCurrent(value, collectedAssetNodes);
}
if (currentNode.IntermediateWildcardChild != null)
{
CollectAllChildNodesFromCurrent(currentNode.IntermediateWildcardChild, collectedAssetNodes);
}
if (currentNode.AssetNodeChild != n