using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using ComputerysModdingUtilities;
using Fancy.Resources;
using FishNet;
using FishNet.Managing;
using FishNet.Object;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: StraftatMod(false)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Fancy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A custom cosmetics API for straftat")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("kestrel.straftat.fancy")]
[assembly: AssemblyTitle("Fancy")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace Fancy
{
public class CosmeticBundleManifest : MonoBehaviour
{
[Tooltip("The name of the cosmetic bundle.")]
public string bundleName;
[Tooltip("The author of the cosmetic bundle. Use your Thunderstore team name if applicable.")]
public string bundleAuthor;
[Tooltip("A *UNIQUE* string that identifies your cosmetic bundle. It's suggested that this follows the format <author>.<bundle name> in all lowercase without spaces.\nFor example: \"kestrel.examplebundle\"")]
public string bundleGuid;
[Tooltip("The version of the cosmetic bundle. It's suggested that you use semantic versioning (<major>.<minor>.<patch>)")]
public string bundleVersion = "1.0.0";
[Tooltip("A list of references to every cosmetic the bundle includes. Only cosmetics referenced here will be loaded ingame.")]
public CosmeticReferenceBase[] cosmeticReferences;
public string outputDirectory = "Assets/BuiltCosmeticBundles";
}
public class CosmeticReferenceBase : MonoBehaviour
{
[Tooltip("The name of the cosmetic.")]
public string cosmeticName;
[Tooltip("The icon of the cosmetic.")]
public Sprite cosmeticIcon;
[Tooltip("Whether the cosmetic requires the DLC to unlock.")]
public bool dlcOnly;
[HideInInspector]
public string sourceGuid;
}
public enum PrefabCosmeticType : byte
{
Hat,
Cig
}
public class PrefabCosmeticReference : CosmeticReferenceBase
{
[Tooltip("The type of the cosmetic. Only determines which menu it will be shown in ingame, as both cigs and hats use the same transform root.")]
public PrefabCosmeticType type;
[Tooltip("The prefab to instantiate~ this will be instantiated ingame with its parent as the cosmetics anchor.")]
public GameObject prefab;
}
public class SuitCosmeticReference : CosmeticReferenceBase
{
[Tooltip("The material that will be applied to the suit.")]
public Material suitMaterial;
[Tooltip("The material that will be applied to the suit's first person arms.")]
public Material armsMaterial;
[Tooltip("The dummy used to test these suits. Optional.")]
public SuitTestDummy dummy;
public void ApplyToDummy()
{
if (!Object.op_Implicit((Object)(object)dummy))
{
Debug.LogError((object)"[Fancy] No dummy assigned- assign one to test suits.");
return;
}
SkinnedMeshRenderer[] suitTargets = dummy.suitTargets;
for (int i = 0; i < suitTargets.Length; i++)
{
((Renderer)suitTargets[i]).material = suitMaterial;
}
suitTargets = dummy.armTargets;
for (int i = 0; i < suitTargets.Length; i++)
{
((Renderer)suitTargets[i]).material = armsMaterial;
}
}
}
public class SuitTestDummy : MonoBehaviour
{
public SkinnedMeshRenderer[] suitTargets;
public SkinnedMeshRenderer[] armTargets;
public GameObject arms;
public void ToggleArms()
{
GameObject obj = arms;
if (obj != null)
{
obj.SetActive(!arms.activeSelf);
}
}
}
public static class BundleLocator
{
private static string m_bundleDirectory = Path.Combine(Paths.PluginPath, "CosmeticBundles");
public static uint InstalledCode { get; private set; }
public static IEnumerator DiscoverAndLoadBundles()
{
if (!Directory.Exists(m_bundleDirectory))
{
Directory.CreateDirectory(m_bundleDirectory);
}
string[] files = Directory.GetFiles(Paths.PluginPath, "*.cbundle", SearchOption.AllDirectories);
foreach (string path in files)
{
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);
yield return request;
string fileName = Path.GetFileName(path);
if (Object.op_Implicit((Object)(object)request.assetBundle))
{
if (!RegisterCosmeticsFromBundle(request.assetBundle))
{
Plugin.Logger.LogError((object)("Cosmetic manifest not found for \"" + fileName + "\", it will be skipped."));
}
}
else
{
Plugin.Logger.LogError((object)("Failed to load bundle from \"" + fileName + "\", it will be skipped."));
}
}
((MonoBehaviour)Plugin.Instance).StartCoroutine(CosmeticLoader.LoadAllWhenReady());
}
private static bool RegisterCosmeticsFromBundle(AssetBundle bundle)
{
CosmeticBundleManifest cosmeticBundleManifest = bundle.mainAsset as CosmeticBundleManifest;
if (!Object.op_Implicit((Object)(object)cosmeticBundleManifest))
{
return false;
}
Plugin.Logger.LogInfo((object)("Registering cosmetics from " + cosmeticBundleManifest.bundleGuid + " (\"" + cosmeticBundleManifest.bundleName + "\") version " + cosmeticBundleManifest.bundleVersion));
int hashCode = (cosmeticBundleManifest.bundleGuid + cosmeticBundleManifest.bundleVersion).GetHashCode();
InstalledCode = (uint)((int)InstalledCode + hashCode) % 1000000000u;
CosmeticReferenceBase[] cosmeticReferences = cosmeticBundleManifest.cosmeticReferences;
for (int i = 0; i < cosmeticReferences.Length; i++)
{
CosmeticLoader.RegisterCosmetic(cosmeticReferences[i]);
}
return true;
}
}
public static class CosmeticLoader
{
[HarmonyPatch(typeof(CosmeticInstance))]
public static class CosmeticInsancePatch
{
[HarmonyPatch("Start")]
[HarmonyPostfix]
public static void SetHoverText(CosmeticInstance __instance, string ___cosmeticName)
{
((Component)__instance).GetComponent<ButtonSizeTween>().customText = ___cosmeticName.SplitCamelCase();
}
}
[HarmonyPatch(typeof(CosmeticsManager))]
internal static class CosmeticsManagerPatch
{
[HarmonyPatch("Start")]
[HarmonyPostfix]
public static void CaptureManager(CosmeticsManager __instance)
{
m_manager = __instance;
}
}
[HarmonyPatch(typeof(NetworkManager))]
internal static class NetworkManagerPatch
{
[HarmonyPatch("Awake")]
[HarmonyPostfix]
public static void RefreshPrefabs(NetworkManager __instance)
{
foreach (CosmeticReferenceBase reference in m_references)
{
if (reference is PrefabCosmeticReference prefabCosmeticReference)
{
NetworkObject component = prefabCosmeticReference.prefab.GetComponent<NetworkObject>();
if (component != null)
{
__instance.SpawnablePrefabs.AddObject(component, false);
}
}
}
}
}
private static CosmeticsManager m_manager;
private static readonly LayerMask m_dontCollideWithPlayerLayer = LayerMask.op_Implicit(LayerMask.NameToLayer("DontCollideWithPlayer"));
private static GameObject m_cosmeticInstancePrefab;
private static List<CosmeticReferenceBase> m_references = new List<CosmeticReferenceBase>();
private static int m_suitCount;
public static bool HasLoadedAllCosmetics { get; private set; }
public static void RegisterCosmetic(CosmeticReferenceBase reference)
{
if (HasLoadedAllCosmetics)
{
Plugin.Logger.LogError((object)("CosmeticLoader: tried to register \"" + reference.cosmeticName + "\" after cosmetics have been loaded; it will be ignored."));
return;
}
int index = m_references.TakeWhile((CosmeticReferenceBase r) => string.CompareOrdinal(r.sourceGuid, reference.sourceGuid) < 0).Count();
m_references.Insert(index, reference);
if (reference is SuitCosmeticReference)
{
m_suitCount++;
}
}
public static IEnumerator LoadAllWhenReady()
{
while (!Object.op_Implicit((Object)(object)m_manager))
{
yield return null;
}
Plugin.Logger.LogInfo((object)"Loading all registered cosmetics...");
m_cosmeticInstancePrefab = Assets.Load<GameObject>("CosmeticInstanceTemplate");
int num = m_manager.mats.Length;
Material[] array = (Material[])(object)new Material[m_suitCount];
Material[] array2 = (Material[])(object)new Material[m_suitCount];
int num2 = 0;
NetworkManager networkManager = InstanceFinder.NetworkManager;
foreach (CosmeticReferenceBase reference in m_references)
{
bool flag = false;
bool flag2 = false;
if (reference is PrefabCosmeticReference prefabCosmeticReference)
{
if (prefabCosmeticReference.type == PrefabCosmeticType.Hat)
{
flag = true;
object obj = prefabCosmeticReference.prefab.GetComponent<NetworkObject>();
if (obj == null)
{
GameObject prefab = prefabCosmeticReference.prefab;
obj = ((prefab != null) ? prefab.AddComponent<NetworkObject>() : null);
}
NetworkObject val = (NetworkObject)obj;
if (Object.op_Implicit((Object)(object)val))
{
networkManager.SpawnablePrefabs.AddObject(val, false);
}
Collider[] componentsInChildren = prefabCosmeticReference.prefab.GetComponentsInChildren<Collider>();
foreach (Collider obj2 in componentsInChildren)
{
((Component)obj2).gameObject.tag = "Hat";
((Component)obj2).gameObject.layer = LayerMask.op_Implicit(m_dontCollideWithPlayerLayer);
}
}
else
{
flag2 = true;
}
}
Transform val2 = (flag ? m_manager.hatsParent : ((!flag2) ? m_manager.suitsParent : m_manager.cigsParent));
CosmeticInstance component = Object.Instantiate<GameObject>(m_cosmeticInstancePrefab, val2, false).GetComponent<CosmeticInstance>();
component.isHat = flag;
component.isCig = flag2;
component.sprite = reference.cosmeticIcon ?? ((Component)((Component)component).transform.Find("Image")).GetComponent<Image>().sprite;
component.hat = (reference as PrefabCosmeticReference)?.prefab;
component.cosmeticName = reference.cosmeticName;
if (reference.dlcOnly)
{
component.acquired = false;
component.unlockWithDlc = true;
}
if (reference is SuitCosmeticReference suitCosmeticReference)
{
array[num2] = suitCosmeticReference.suitMaterial;
array2[num2] = suitCosmeticReference.armsMaterial;
component.index = num + num2;
num2++;
}
}
int num3 = num + m_suitCount;
if (num3 > num)
{
Material[] array3 = (Material[])(object)new Material[num3];
Material[] array4 = (Material[])(object)new Material[num3];
m_manager.mats.CopyTo(array3, 0);
m_manager.fparmsMats.CopyTo(array4, 0);
array.CopyTo(array3, num);
array2.CopyTo(array4, num);
m_manager.mats = array3;
m_manager.fparmsMats = array4;
}
m_manager.Start();
m_manager.cigs = (GameObject[])(object)new GameObject[m_manager.cigsChildren.Length];
for (int j = 0; j < m_manager.cigs.Length; j++)
{
m_manager.cigs[j] = m_manager.cigsChildren[j].hat;
m_manager.cigsChildren[j].index = j;
}
Plugin.Logger.LogInfo((object)"All custom cosmetics loaded!");
Plugin.Logger.LogWarning((object)$"Your cosmetics code is {BundleLocator.InstalledCode}. MAKE SURE THIS IS *IDENTICAL* TO THE ONE THAT PEOPLE YOU WANT TO PLAY WITH HAVE!");
Plugin.Logger.LogWarning((object)"If your codes do not match, you do not have the same cosmetic bundles installed and strange behaviour may occur. You have been warned!");
HasLoadedAllCosmetics = true;
m_manager.LoadDress();
}
}
[BepInPlugin("kestrel.straftat.fancy", "Fancy", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Logger;
public static readonly string loadBearingColonThree = ":3";
public static Plugin Instance { get; private set; }
private void Awake()
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
if (loadBearingColonThree != ":3")
{
Application.Quit();
}
((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
Instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
Assets.LoadBundle();
((MonoBehaviour)this).StartCoroutine(BundleLocator.DiscoverAndLoadBundles());
new Harmony("kestrel.straftat.fancy").PatchAll();
Logger.LogInfo((object)"Hiiiiiiiiiiii :3");
}
}
internal static class Extensions
{
private static readonly Regex splitCamelCaseA = new Regex("(\\p{Lu})(\\p{Lu})(\\p{Ll})", RegexOptions.Compiled);
private static readonly Regex splitCamelCaseB = new Regex("(\\p{Ll})(\\p{Lu})", RegexOptions.Compiled);
public static string SplitCamelCase(this string str)
{
return splitCamelCaseB.Replace(splitCamelCaseA.Replace(str, "$1 $2"), "$1 $2");
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "kestrel.straftat.fancy";
public const string PLUGIN_NAME = "Fancy";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace Fancy.Resources
{
public static class Assets
{
private static AssetBundle m_bundle;
internal static T Load<T>(string assetName) where T : Object
{
return m_bundle.LoadAsset<T>(assetName);
}
internal static void LoadBundle()
{
m_bundle = AssetBundle.LoadFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("Fancy.Fancy.Resources.Bundles.fancy"));
}
}
}
namespace Fancy.Patches
{
[HarmonyPatch(typeof(CosmeticsManager))]
public static class CosmeticsManagerFixes
{
[HarmonyPatch("LoadDress")]
[HarmonyPrefix]
public static void ProperBoundsCheck(ref int ___suitIndex, ref int ___hatIndex, ref int ___cigIndex, GameObject[] ___suitsChildren, GameObject[] ___hatsChildren, GameObject[] ___cigsChildren)
{
___suitIndex = Mathf.Clamp(___suitIndex, 0, ___suitsChildren.Length - 1);
___hatIndex = Mathf.Clamp(___hatIndex, 0, ___hatsChildren.Length - 1);
___cigIndex = Mathf.Clamp(___cigIndex, 0, ___suitsChildren.Length - 1);
}
[HarmonyPatch("ChangeDress")]
[HarmonyTranspiler]
public static IEnumerable<CodeInstruction> PatchChangeDressIndexException(IEnumerable<CodeInstruction> instructions)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Expected O, but got Unknown
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Expected O, but got Unknown
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[2]
{
new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.Field(typeof(CosmeticsManager), "suitsChildren"), (string)null),
new CodeMatch((OpCode?)OpCodes.Ldlen, (object)null, (string)null)
};
return new CodeMatcher(instructions, (ILGenerator)null).End().MatchBack(false, array).Set(OpCodes.Ldfld, (object)AccessTools.Field(typeof(CosmeticsManager), "cigsChildren"))
.MatchBack(false, array)
.Set(OpCodes.Ldfld, (object)AccessTools.Field(typeof(CosmeticsManager), "cigsChildren"))
.InstructionEnumeration();
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}