using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LethalLib.Modules; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("LethalLib")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LoquatScrapPack")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.4.0")] [assembly: AssemblyInformationalVersion("0.3.4")] [assembly: AssemblyProduct("LoquatScrapPack")] [assembly: AssemblyTitle("LoquatScrapPack")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.4.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 LoquatScrapPack { internal sealed class BalbalGlowMarker : MonoBehaviour { private MeshRenderer targetRenderer; private Material runtimeMaterial; private Light pointLight; private int pulseVersion; private Color baseColor = Color.white; private static readonly Color GlowColor = new Color(0.23f, 0.64f, 1f, 1f); private void Awake() { try { InitializeVisuals(); } catch (Exception ex) { Plugin.Log.LogDebug((object)("Balbal glow setup was disabled: " + ex.GetBaseException().Message)); ((Behaviour)this).enabled = false; } } private void InitializeVisuals() { //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)this).transform.Find("FGS_Visual"); targetRenderer = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent() : ((Component)this).GetComponentInChildren(true)); if ((Object)(object)targetRenderer != (Object)null && (Object)(object)((Renderer)targetRenderer).sharedMaterial != (Object)null) { runtimeMaterial = new Material(((Renderer)targetRenderer).sharedMaterial) { name = ((Object)((Renderer)targetRenderer).sharedMaterial).name + "_BalbalRuntime" }; ((Renderer)targetRenderer).sharedMaterial = runtimeMaterial; if (runtimeMaterial.HasProperty("_BaseColor")) { baseColor = runtimeMaterial.GetColor("_BaseColor"); } else if (runtimeMaterial.HasProperty("_Color")) { baseColor = runtimeMaterial.GetColor("_Color"); } } Transform val2 = ((Component)this).transform.Find("FGS_BalbalGlowLight"); if ((Object)(object)val2 != (Object)null) { GameObject gameObject = ((Component)val2).gameObject; pointLight = gameObject.GetComponent() ?? gameObject.AddComponent(); } else { GameObject gameObject = new GameObject("FGS_BalbalGlowLight"); gameObject.transform.SetParent(((Component)this).transform, false); gameObject.transform.localPosition = new Vector3(0f, 0.5f, 0f); pointLight = gameObject.AddComponent(); } pointLight.type = (LightType)2; pointLight.color = GlowColor; pointLight.range = 1.8f; pointLight.intensity = 8f; pointLight.shadows = (LightShadows)0; ((Behaviour)pointLight).enabled = false; SetGlow(enabled: false); } internal void Pulse(float seconds) { pulseVersion++; int version = pulseVersion; ((MonoBehaviour)this).StopAllCoroutines(); ((MonoBehaviour)this).StartCoroutine(PulseRoutine(Mathf.Max(0.25f, seconds), version)); } internal void PulseForCurrentPlayback(float fallbackSeconds = 4f) { pulseVersion++; int version = pulseVersion; ((MonoBehaviour)this).StopAllCoroutines(); ((MonoBehaviour)this).StartCoroutine(PulseForCurrentPlaybackRoutine(Mathf.Max(0.25f, fallbackSeconds), version)); } private IEnumerator PulseRoutine(float seconds, int version) { SetGlow(enabled: true); yield return (object)new WaitForSeconds(seconds); if (version == pulseVersion) { SetGlow(enabled: false); } } private IEnumerator PulseForCurrentPlaybackRoutine(float fallbackSeconds, int version) { SetGlow(enabled: true); AudioSource active = null; float startWait = 0f; while ((Object)(object)active == (Object)null && startWait < 0.4f) { AudioSource[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null && componentsInChildren[i].isPlaying) { active = componentsInChildren[i]; break; } } if ((Object)(object)active != (Object)null) { break; } startWait += Time.deltaTime; yield return null; } if ((Object)(object)active == (Object)null) { yield return (object)new WaitForSeconds(fallbackSeconds); } else { float safety = 0f; while ((Object)(object)active != (Object)null && active.isPlaying && safety < 60f) { safety += Time.deltaTime; yield return null; } } if (version == pulseVersion) { SetGlow(enabled: false); } } private void SetGlow(bool enabled) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_00a4: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)pointLight != (Object)null) { ((Behaviour)pointLight).enabled = enabled; } if ((Object)(object)runtimeMaterial == (Object)null) { return; } Color val = (enabled ? Color.Lerp(baseColor, GlowColor, 0.1f) : baseColor); if (runtimeMaterial.HasProperty("_BaseColor")) { runtimeMaterial.SetColor("_BaseColor", val); } if (runtimeMaterial.HasProperty("_Color")) { runtimeMaterial.SetColor("_Color", val); } Color val2 = (enabled ? (GlowColor * 0.65f) : Color.black); if (runtimeMaterial.HasProperty("_EmissiveColor")) { runtimeMaterial.SetColor("_EmissiveColor", val2); } if (runtimeMaterial.HasProperty("_EmissiveColorLDR")) { runtimeMaterial.SetColor("_EmissiveColorLDR", val2); } if (runtimeMaterial.HasProperty("_EmissionColor")) { runtimeMaterial.SetColor("_EmissionColor", val2); if (enabled) { runtimeMaterial.EnableKeyword("_EMISSION"); } else { runtimeMaterial.DisableKeyword("_EMISSION"); } } } } internal static class BlumpkinSpawner { private static int lastAttemptFrame = int.MinValue; private static readonly BindingFlags InspectFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; internal static void TrySpawn() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0101: 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) if ((Object)(object)ItemFactory.BlumpkinItem == (Object)null || (Object)(object)ItemFactory.BlumpkinItem.spawnPrefab == (Object)null || (Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsListening || !NetworkManager.Singleton.IsServer || Time.frameCount == lastAttemptFrame) { return; } lastAttemptFrame = Time.frameCount; List list = FindPumpkinRoots(); if (list.Count == 0 && !CurrentLevelSupportsPumpkins()) { return; } float num = Mathf.Clamp(Plugin.ModConfig.BlumpkinChancePercent.Value, 0f, 100f); if (Random.Range(0f, 100f) >= num) { return; } Vector3 position; if (list.Count > 0) { position = PositionNear(list[Random.Range(0, list.Count)].position, 0.8f, 1.4f); } else if (!TryGetOutsideSpawnPosition(out position)) { Plugin.Log.LogWarning((object)"Blumpkin moon was pumpkin-eligible, but no safe outside spawn point was found."); return; } SnapToGround(ref position); GameObject val = Object.Instantiate(ItemFactory.BlumpkinItem.spawnPrefab, position, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); GrabbableObject component = val.GetComponent(); if ((Object)(object)component != (Object)null) { int val2 = Mathf.RoundToInt((float)ItemFactory.BlumpkinItem.minValue * 0.4f); int val3 = Mathf.RoundToInt((float)ItemFactory.BlumpkinItem.maxValue * 0.4f); int num2 = Random.Range(Math.Min(val2, val3), Math.Max(val2, val3) + 1); try { MethodInfo methodInfo = AccessTools.Method(typeof(GrabbableObject), "SetScrapValue", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(component, new object[1] { num2 }); } else { ReflectionUtil.SetMember(component, "scrapValue", num2); } } catch { ReflectionUtil.SetMember(component, "scrapValue", num2); } } NetworkObject component2 = val.GetComponent(); if ((Object)(object)component2 == (Object)null) { Object.Destroy((Object)(object)val); Plugin.Log.LogError((object)"Blumpkin prefab has no NetworkObject."); return; } try { if (!component2.IsSpawned) { component2.Spawn(false); } Plugin.Log.LogInfo((object)"A Blumpkin spawned outside on a pumpkin-eligible moon."); } catch (Exception ex) { Object.Destroy((Object)(object)val); Plugin.Log.LogDebug((object)("Blumpkin network spawn was skipped: " + ex.GetBaseException().Message)); } } private static Vector3 PositionNear(Vector3 origin, float minRadius, float maxRadius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0046: Unknown result type (might be due to invalid IL or missing references) //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) Vector2 val = Random.insideUnitCircle; if (((Vector2)(ref val)).sqrMagnitude < 0.01f) { val = Vector2.right; } ((Vector2)(ref val)).Normalize(); Vector2 val2 = val * Random.Range(minRadius, maxRadius); return origin + new Vector3(val2.x, 1.5f, val2.y); } private static void SnapToGround(ref Vector3 spawnPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) RaycastHit val = default(RaycastHit); if (Physics.Raycast(spawnPosition + Vector3.up * 3f, Vector3.down, ref val, 12f, -1, (QueryTriggerInteraction)1)) { spawnPosition = ((RaycastHit)(ref val)).point + Vector3.up * 0.15f; } } private static bool TryGetOutsideSpawnPosition(out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; try { GameObject[] array = GameObject.FindGameObjectsWithTag("OutsideAINode"); if (array != null && array.Length != 0) { GameObject val = array[Random.Range(0, array.Length)]; position = PositionNear(val.transform.position, 0.4f, 2f); return true; } } catch { } return false; } private static bool CurrentLevelSupportsPumpkins() { if ((Object)(object)StartOfRound.Instance == (Object)null) { return false; } object member = ReflectionUtil.GetMember(StartOfRound.Instance, "currentLevel"); if (member == null) { return false; } string[] array = new string[4] { "spawnableMapObjects", "spawnableOutsideObjects", "spawnableOutsideObjectsWithRarity", "randomMapObjects" }; foreach (string name in array) { if (ContainsPumpkinReference(ReflectionUtil.GetMember(member, name), 3, new HashSet())) { return true; } } return false; } private static bool ContainsPumpkinReference(object value, int depth, HashSet visited) { if (value == null || depth < 0) { return false; } if (value is string text) { return text.IndexOf("pumpkin", StringComparison.OrdinalIgnoreCase) >= 0; } Object val = (Object)((value is Object) ? value : null); if (val != (Object)null && !string.IsNullOrEmpty(val.name) && val.name.IndexOf("pumpkin", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } Type type = value.GetType(); if (type.IsPrimitive || type.IsEnum || type == typeof(decimal)) { return false; } if (!type.IsValueType) { if (visited.Contains(value)) { return false; } visited.Add(value); } if (value is IEnumerable enumerable && !(value is string)) { int num = 0; foreach (object item in enumerable) { if (ContainsPumpkinReference(item, depth - 1, visited)) { return true; } if (++num >= 256) { break; } } return false; } if (depth == 0) { return false; } FieldInfo[] fields = type.GetFields(InspectFlags); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.Name.IndexOf("pumpkin", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } object value2; try { value2 = fieldInfo.GetValue(value); } catch { continue; } if (ContainsPumpkinReference(value2, depth - 1, visited)) { return true; } } PropertyInfo[] properties = type.GetProperties(InspectFlags); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0) { if (propertyInfo.Name.IndexOf("pumpkin", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } object value3; try { value3 = propertyInfo.GetValue(value, null); } catch { continue; } if (ContainsPumpkinReference(value3, depth - 1, visited)) { return true; } } } return false; } private static List FindPumpkinRoots() { return Object.FindObjectsOfType(true).Where(delegate(Transform transform) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)transform != (Object)null) { Scene scene = ((Component)transform).gameObject.scene; if (((Scene)(ref scene)).IsValid() && ((Component)transform).gameObject.activeInHierarchy && ((Object)transform).name.IndexOf("pumpkin", StringComparison.OrdinalIgnoreCase) >= 0) { return !AncestorNameContainsPumpkin(transform.parent); } } return false; }).ToList(); } private static bool AncestorNameContainsPumpkin(Transform transform) { while ((Object)(object)transform != (Object)null) { if (((Object)transform).name.IndexOf("pumpkin", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } transform = transform.parent; } return false; } } internal static class ItemFactory { private static bool buildAttempted; private static int successfulBuilds; internal static Item BlumpkinItem { get; private set; } internal static Item ShumovkaItem { get; private set; } internal static Item BaconEggCheeseItem { get; private set; } internal static Item BalbalItem { get; private set; } internal static Item TvorogItem { get; private set; } internal static Item ZubrowkaItem { get; private set; } internal static Item MoutaiItem { get; private set; } internal static Item KyivCakeItem { get; private set; } internal static Item BimbkaItem { get; private set; } internal static Item HasbullahItem { get; private set; } internal static Item DoshirakItem { get; private set; } internal static Item MenorahItem { get; private set; } internal static void BuildAll() { if (buildAttempted) { return; } buildAttempted = true; ModConfig cfg = Plugin.ModConfig; Item shovel = FindTemplateWithComponent(new string[1] { "Shovel" }); if ((Object)(object)shovel == (Object)null) { shovel = FindAnyTemplateWithComponent(); } Item clownHorn = FindTemplateWithComponent(new string[6] { "Clown horn", "Clownhorn", "Clown Horn", "ClownHorn", "Airhorn", "Air horn" }); if ((Object)(object)clownHorn == (Object)null) { clownHorn = FindAnyTemplateWithComponent(); } Item neutralScrap = FindPlainScrapTemplate("Mug", "Toy cube", "ToyCube", "Metal sheet", "MetalSheet", "Large axle", "Big bolt", "BigBolt", "Cog1"); Item hive = FindTemplate("Hive", "RedLocustHive", "Red locust hive") ?? FindTemplateContains("hive"); Item bottleSoundDonor = FindTemplate("Flask", "BottleBin", "PerfumeBottle", "Molotov", "Molotov cocktail") ?? FindTemplateContains("bottle"); Item cakeSoundDonor = FindTemplate("Gift", "Gift box", "Gift Box", "GiftBox") ?? FindTemplateContains("gift"); LogTemplate("Shovel", shovel); LogTemplate("Noisemaker", clownHorn); LogTemplate("Neutral scrap", neutralScrap); LogTemplate("Hive sound donor", hive); float maxSeconds = Mathf.Max(0f, cfg.MusicExcerptSeconds.Value); AudioClip val = CreateSilentClip(); AudioClip baconClip = TryLoadWav("BaconEggCheese.wav", maxSeconds) ?? val; AudioClip tvorogClip = TryLoadWav("Tvorog.wav", maxSeconds) ?? val; AudioClip menorahSilence = TryLoadWav("MenorahSilence.wav") ?? val; AudioClip[] balbalClips = ((IEnumerable)(object)new AudioClip[4] { TryLoadWav("Balbal_01.wav"), TryLoadWav("Balbal_02.wav"), TryLoadWav("Balbal_03.wav"), TryLoadWav("Balbal_04.wav") }).Where((AudioClip clip) => (Object)(object)clip != (Object)null).ToArray(); if (balbalClips.Length == 0) { balbalClips = (AudioClip[])(object)new AudioClip[1] { val }; } ShumovkaItem = TryBuildScrap("Shumovka", cfg.ShumovkaRarity.Value, delegate { RequireTemplate(shovel, "a shovel-class donor"); Item obj = CreateItem(shovel, "Shumovka", "Shumovka", cfg.ShumovkaScale.Value, 19f, 95, 185, twoHanded: false, null, preserveTemplateHandling: true); Mark(obj, LoquatItemKind.Shumovka); return obj; }); BaconEggCheeseItem = TryBuildScrap("Bacon Egg and Cheese Sandwich", cfg.BaconEggCheeseRarity.Value, delegate { RequireTemplate(clownHorn, "a noisemaker donor"); Item val2 = CreateItem(clownHorn, "Bacon Egg and Cheese Sandwich", "BaconEggCheese", cfg.BaconEggCheeseScale.Value, 2f, 80, 160, twoHanded: false); ConfigureNoisemaker(val2, (AudioClip[])(object)new AudioClip[1] { baconClip }); ReflectionUtil.SetMember(val2, "useCooldown", Math.Max(0.5f, baconClip.length)); Mark(val2, LoquatItemKind.BaconEggCheese); return val2; }); BalbalItem = TryBuildScrap("Balbal", cfg.BalbalRarity.Value, delegate { RequireTemplate(clownHorn, "a noisemaker donor"); Item obj = CreateItem(clownHorn, "Balbal", "Balbal", cfg.BalbalScale.Value, 78f, 150, 290, twoHanded: true); ConfigureNoisemaker(obj, balbalClips); ReflectionUtil.SetMember(obj, "useCooldown", 1f); AddComponentIfMissing(obj.spawnPrefab); Mark(obj, LoquatItemKind.Balbal); return obj; }); TvorogItem = TryBuildScrap("Tvorog", cfg.TvorogRarity.Value, delegate { RequireTemplate(clownHorn, "a noisemaker donor"); Item val2 = CreateItem(clownHorn, "Tvorog", "Tvorog", cfg.TvorogScale.Value, 4f, 90, 175, twoHanded: false); ConfigureNoisemaker(val2, (AudioClip[])(object)new AudioClip[1] { tvorogClip }); ReflectionUtil.SetMember(val2, "useCooldown", Math.Max(0.5f, tvorogClip.length)); Mark(val2, LoquatItemKind.Tvorog); return val2; }); ZubrowkaItem = TryBuildScrap("Żubrówka", cfg.ZubrowkaRarity.Value, delegate { RequireTemplate(neutralScrap, "a plain scrap donor"); Item val2 = CreateItem(neutralScrap, "Żubrówka", "Zubrowka", cfg.ZubrowkaScale.Value, 3f, 90, 170, twoHanded: false); CopyVanillaHandlingSounds(bottleSoundDonor ?? neutralScrap, val2); Mark(val2, LoquatItemKind.Zubrowka); return val2; }); MoutaiItem = TryBuildScrap("Kweichow Moutai", cfg.MoutaiRarity.Value, delegate { RequireTemplate(neutralScrap, "a plain scrap donor"); Item val2 = CreateItem(neutralScrap, "Kweichow Moutai", "Moutai", cfg.MoutaiScale.Value, 4f, 180, 330, twoHanded: false); CopyVanillaHandlingSounds(bottleSoundDonor ?? neutralScrap, val2); Mark(val2, LoquatItemKind.Moutai); return val2; }); KyivCakeItem = TryBuildScrap("Roshen Київський", cfg.KyivCakeRarity.Value, delegate { RequireTemplate(neutralScrap, "a plain scrap donor"); Item val2 = CreateItem(neutralScrap, "Roshen Київський", "KyivCake", cfg.KyivCakeScale.Value, 10f, 105, 200, twoHanded: false, "Roshen Київський"); CopyVanillaHandlingSounds(cakeSoundDonor ?? neutralScrap, val2); Mark(val2, LoquatItemKind.KyivCake); return val2; }); BimbkaItem = TryBuildScrap("Bimbka", cfg.BimbkaRarity.Value, delegate { RequireTemplate(neutralScrap, "a plain scrap donor"); Item val2 = CreateItem(neutralScrap, "Bimbka", "Bimbka", cfg.BimbkaScale.Value, 72f, 175, 325, twoHanded: true); CopyVanillaHandlingSounds(neutralScrap, val2); Mark(val2, LoquatItemKind.Bimbka); return val2; }); HasbullahItem = TryBuildScrap("Hasbullah", cfg.HasbullahRarity.Value, delegate { RequireTemplate(neutralScrap, "a plain scrap donor"); Item val2 = CreateItem(neutralScrap, "Hasbullah", "Hasbullah", cfg.HasbullahScale.Value, 46f, 210, 390, twoHanded: true); CopyVanillaHandlingSounds(neutralScrap, val2); Mark(val2, LoquatItemKind.Hasbullah); return val2; }); DoshirakItem = TryBuildScrap("Doshirak", cfg.DoshirakRarity.Value, delegate { RequireTemplate(neutralScrap, "a plain scrap donor"); Item val2 = CreateItem(neutralScrap, "Doshirak", "Doshirak", cfg.DoshirakScale.Value, 2f, 80, 155, twoHanded: false); CopyVanillaHandlingSounds(neutralScrap, val2); Mark(val2, LoquatItemKind.Doshirak); return val2; }); MenorahItem = TryBuildScrap("Menorah", cfg.MenorahRarity.Value, delegate { RequireTemplate(clownHorn, "a noisemaker donor"); Item val2 = CreateItem(clownHorn, "Menorah", "Menorah", cfg.MenorahScale.Value, 18f, 145, 275, twoHanded: false); ConfigureNoisemaker(val2, (AudioClip[])(object)new AudioClip[1] { menorahSilence }); ReflectionUtil.SetMember(val2, "useCooldown", 0.75f); NoisemakerProp component = val2.spawnPrefab.GetComponent(); if ((Object)(object)component != (Object)null) { ReflectionUtil.SetMember(component, "noiseRange", 0f); ReflectionUtil.SetMember(component, "maxLoudness", 0f); ReflectionUtil.SetMember(component, "minLoudness", 0f); AddComponentIfMissing(val2.spawnPrefab); } CopyVanillaHandlingSounds(neutralScrap, val2); Mark(val2, LoquatItemKind.Menorah); return val2; }); BlumpkinItem = TryBuildItem("Blumpkin", delegate { RequireTemplate(neutralScrap, "a plain scrap donor"); Item val2 = CreateItem(neutralScrap, "Blumpkin", "Blumpkin", cfg.BlumpkinScale.Value, 12f, 230, 420, twoHanded: false, "Blumpkin (blue pumpkin)"); CopyVanillaHandlingSounds(hive ?? neutralScrap, val2); Mark(val2, LoquatItemKind.Blumpkin); return val2; }); ConfigureUprightRest(BaconEggCheeseItem, 0f); ConfigureUprightRest(BalbalItem, 0f); ConfigureUprightRest(TvorogItem, 0f); ConfigureUprightRest(ZubrowkaItem, 0f); ConfigureUprightRest(MoutaiItem, 0f); ConfigureUprightRest(KyivCakeItem, 0f); ConfigureUprightRest(BlumpkinItem, 0f); ConfigureUprightRest(BimbkaItem, 0f); ConfigureUprightRest(HasbullahItem, 0f); ConfigureUprightRest(DoshirakItem, 0f); ConfigureUprightRest(MenorahItem, 0f); float value = cfg.HeldFacingYawDegrees.Value; ConfigureHeldFacing(BaconEggCheeseItem, value); ConfigureHeldFacing(BalbalItem, value); ConfigureHeldFacing(TvorogItem, value); ConfigureHeldFacing(ZubrowkaItem, value); ConfigureHeldFacing(MoutaiItem, value); ConfigureHeldFacing(KyivCakeItem, value); ConfigureHeldFacing(BlumpkinItem, value); ConfigureHeldFacing(BimbkaItem, value); ConfigureHeldFacing(HasbullahItem, value); ConfigureHeldFacing(DoshirakItem, value); ConfigureHeldFacing(MenorahItem, value); Plugin.Log.LogInfo((object)$"Loquat initialization finished: {successfulBuilds}/12 items registered. Failed items were skipped without interrupting game startup."); } private static Item TryBuildScrap(string label, int rarity, Func factory) { Item val = TryCreate(label, factory); if ((Object)(object)val == (Object)null) { return null; } try { Items.RegisterScrap(val, Mathf.Max(0, rarity), (LevelTypes)(-1)); successfulBuilds++; return val; } catch (Exception ex) { Plugin.Log.LogError((object)(label + " was created but could not be added to the scrap table; it will be unavailable this session. " + ex.GetBaseException().Message)); return null; } } private static Item TryBuildItem(string label, Func factory) { Item val = TryCreate(label, factory); if ((Object)(object)val == (Object)null) { return null; } try { Items.RegisterItem(val); successfulBuilds++; return val; } catch (Exception ex) { Plugin.Log.LogError((object)(label + " was created but could not be registered; it will be unavailable this session. " + ex.GetBaseException().Message)); return null; } } private static Item TryCreate(string label, Func factory) { try { Item val = factory(); if ((Object)(object)val == (Object)null || !HasUsableSpawnPrefab(val)) { throw new InvalidOperationException("item creation returned an unusable prefab"); } return val; } catch (Exception ex) { Plugin.Log.LogError((object)("Skipping Loquat item '" + label + "': " + ex.GetBaseException().Message)); return null; } } private static void RequireTemplate(Item item, string description) { if (!HasUsableSpawnPrefab(item)) { throw new InvalidOperationException("Could not find " + description + " with a usable network prefab."); } } private static T AddComponentIfMissing(GameObject target) where T : Component { if ((Object)(object)target == (Object)null) { return default(T); } return target.GetComponent() ?? target.AddComponent(); } private static void Mark(Item item, LoquatItemKind kind) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item.spawnPrefab == (Object)null)) { LoquatItemMarker loquatItemMarker = AddComponentIfMissing(item.spawnPrefab); if ((Object)(object)loquatItemMarker != (Object)null) { loquatItemMarker.Kind = kind; } } } private static AudioClip TryLoadWav(string fileName, float maxSeconds = 0f) { try { return RuntimeAssets.LoadWav(fileName, maxSeconds); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Audio asset '" + fileName + "' could not be loaded; a silent fallback will be used. " + ex.GetBaseException().Message)); return null; } } private static AudioClip CreateSilentClip() { AudioClip obj = AudioClip.Create("LoquatSilentFallback", 2205, 1, 44100, false); obj.SetData(new float[2205], 0); return obj; } private static bool HasUsableSpawnPrefab(Item item) { if ((Object)(object)item == (Object)null || (Object)(object)item.spawnPrefab == (Object)null) { return false; } if ((Object)(object)item.spawnPrefab.GetComponent() != (Object)null) { return (Object)(object)item.spawnPrefab.GetComponent() != (Object)null; } return false; } private static bool IsLoquatGenerated(Item item) { if ((Object)(object)item == (Object)null) { return false; } if (string.IsNullOrEmpty(((Object)item).name) || !((Object)item).name.StartsWith("FGS_", StringComparison.Ordinal)) { if ((Object)(object)item.spawnPrefab != (Object)null && !string.IsNullOrEmpty(((Object)item.spawnPrefab).name)) { return ((Object)item.spawnPrefab).name.StartsWith("FGS_", StringComparison.Ordinal); } return false; } return true; } private static Item FindTemplate(params string[] names) { Item[] source = Resources.FindObjectsOfTypeAll(); foreach (string name in names) { Item val = ((IEnumerable)(from item in source.Where(HasUsableSpawnPrefab) where !IsLoquatGenerated(item) orderby MatchScore(item, name) descending select item)).FirstOrDefault((Func)((Item item) => MatchScore(item, name) > 0)); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static Item FindTemplateWithComponent(params string[] names) where T : Component { Item[] source = Resources.FindObjectsOfTypeAll(); foreach (string name in names) { Item val = ((IEnumerable)(from item in source.Where(HasUsableSpawnPrefab) where !IsLoquatGenerated(item) where (Object)(object)item.spawnPrefab.GetComponent() != (Object)null orderby MatchScore(item, name) descending select item)).FirstOrDefault((Func)((Item item) => MatchScore(item, name) > 0)); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static Item FindAnyTemplateWithComponent() where T : Component { return (from item in Resources.FindObjectsOfTypeAll().Where(HasUsableSpawnPrefab) where !IsLoquatGenerated(item) where (Object)(object)item.spawnPrefab.GetComponent() != (Object)null select item).OrderBy((Item item) => ((Object)item).name ?? string.Empty, StringComparer.OrdinalIgnoreCase).FirstOrDefault(); } private static Item FindPlainScrapTemplate(params string[] preferredNames) { Item val = FindTemplate(preferredNames); if ((Object)(object)val != (Object)null && IsPlainGrabbable(val)) { return val; } foreach (string name in preferredNames) { Item val2 = ((IEnumerable)(from item in (from item in Resources.FindObjectsOfTypeAll().Where(HasUsableSpawnPrefab) where !IsLoquatGenerated(item) select item).Where(IsPlainGrabbable) orderby MatchScore(item, name) descending select item)).FirstOrDefault((Func)((Item item) => MatchScore(item, name) > 0)); if ((Object)(object)val2 != (Object)null) { return val2; } } return (from item in (from item in Resources.FindObjectsOfTypeAll().Where(HasUsableSpawnPrefab) where !IsLoquatGenerated(item) select item).Where(IsPlainGrabbable) where item.isScrap select item).OrderBy((Item item) => ((Object)item).name ?? string.Empty, StringComparer.OrdinalIgnoreCase).FirstOrDefault(); } private static bool IsPlainGrabbable(Item item) { if (!HasUsableSpawnPrefab(item)) { return false; } GrabbableObject component = item.spawnPrefab.GetComponent(); if ((Object)(object)component != (Object)null) { return ((object)component).GetType() == typeof(GrabbableObject); } return false; } private static Item FindTemplateContains(string fragment) { string normalized = NormalizeName(fragment); return (from item in Resources.FindObjectsOfTypeAll().Where(HasUsableSpawnPrefab) where !IsLoquatGenerated(item) where ContainsNormalized(item.itemName, normalized) || ContainsNormalized(((Object)item).name, normalized) || ContainsNormalized(((Object)(object)item.spawnPrefab == (Object)null) ? null : ((Object)item.spawnPrefab).name, normalized) select item).OrderBy((Item item) => ((Object)item).name ?? string.Empty, StringComparer.OrdinalIgnoreCase).FirstOrDefault(); } private static int MatchScore(Item item, string requested) { string text = NormalizeName(requested); if (text.Length == 0 || (Object)(object)item == (Object)null) { return 0; } string text2 = NormalizeName(item.itemName); string text3 = NormalizeName(((Object)item).name); string text4 = NormalizeName(((Object)(object)item.spawnPrefab == (Object)null) ? null : ((Object)item.spawnPrefab).name); if (text3 == text) { return 50; } if (text4 == text) { return 45; } if (text2 == text) { return 30; } if (text3.EndsWith(text, StringComparison.Ordinal)) { return 20; } if (text4.EndsWith(text, StringComparison.Ordinal)) { return 15; } return 0; } private static bool ContainsNormalized(string value, string normalizedFragment) { return NormalizeName(value).IndexOf(normalizedFragment, StringComparison.Ordinal) >= 0; } private static string NormalizeName(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(value.Length); foreach (char c in value) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } private static void LogTemplate(string label, Item item) { if ((Object)(object)item == (Object)null) { Plugin.Log.LogWarning((object)(label + " donor: not found; dependent Loquat items will be skipped.")); return; } string text = (((Object)(object)item.spawnPrefab == (Object)null) ? "" : ((Object)item.spawnPrefab).name); string text2 = (((Object)(object)item.spawnPrefab == (Object)null) ? "" : (((object)item.spawnPrefab.GetComponent())?.GetType().Name ?? "")); Plugin.Log.LogInfo((object)(label + " donor: Item '" + item.itemName + "' / asset '" + ((Object)item).name + "' / prefab '" + text + "' / component '" + text2 + "'.")); } private static Item CreateItem(Item template, string displayName, string assetName, float visualScale, float pounds, int minInternalValue, int maxInternalValue, bool twoHanded, string scanHeader = null, bool preserveTemplateHandling = false) { RequireTemplate(template, "a donor for " + displayName); Item val = null; GameObject val2 = null; try { val = Object.Instantiate(template); ((Object)val).name = "FGS_" + assetName + "_Item"; val.itemName = displayName; val.isScrap = true; val.minValue = Math.Min(minInternalValue, maxInternalValue); val.maxValue = Math.Max(minInternalValue, maxInternalValue); val.weight = Mathf.Clamp(1f + pounds / 105f, 1f, 3.75f); if (!preserveTemplateHandling) { val.twoHanded = twoHanded; ReflectionUtil.SetMember(val, "twoHandedAnimation", twoHanded); if (twoHanded) { ReflectionUtil.SetMember(val, "grabAnim", "HoldLung"); } } val2 = PrefabUtils.ClonePrefab(template.spawnPrefab, "FGS_" + assetName + "_Prefab"); if ((Object)(object)val2 == (Object)null) { throw new InvalidOperationException("Could not clone the donor prefab for " + displayName + "."); } NetworkObject component = val2.GetComponent(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("Donor prefab for " + displayName + " has no root NetworkObject."); } GrabbableObject component2 = val2.GetComponent(); if ((Object)(object)component2 == (Object)null) { throw new InvalidOperationException("Donor prefab for " + displayName + " has no root GrabbableObject."); } val.spawnPrefab = val2; component2.itemProperties = val; ReplaceVisual(val2, component2, assetName, Mathf.Max(0.01f, visualScale), scanHeader ?? displayName); AssignDeterministicNetworkHash(component, ((Object)val2).name); NetworkPrefabs.RegisterNetworkPrefab(val2); return val; } catch { if ((Object)(object)val2 != (Object)null) { Object.DestroyImmediate((Object)(object)val2); } if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } throw; } } private static void AssignDeterministicNetworkHash(NetworkObject networkObject, string prefabName) { if ((Object)(object)networkObject == (Object)null) { throw new ArgumentNullException("networkObject"); } string name = typeof(Plugin).Assembly.GetName().Name; uint num; using (MD5 mD = MD5.Create()) { num = BitConverter.ToUInt32(mD.ComputeHash(Encoding.UTF8.GetBytes(name + prefabName)), 0); } if (!ReflectionUtil.SetMember(networkObject, "GlobalObjectIdHash", num) && !ReflectionUtil.SetMember(networkObject, "m_GlobalObjectIdHash", num) && !ReflectionUtil.SetMember(networkObject, "k__BackingField", num)) { throw new InvalidOperationException("Could not assign a deterministic NetworkObject hash to " + prefabName + "."); } } private static void ReplaceVisual(GameObject prefab, GrabbableObject grabbable, string assetName, float visualScale, string scanHeader) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: 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) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_0485: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_0494: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_04a4: Unknown result type (might be due to invalid IL or missing references) //IL_05c8: Unknown result type (might be due to invalid IL or missing references) //IL_05d6: Unknown result type (might be due to invalid IL or missing references) //IL_05e0: Unknown result type (might be due to invalid IL or missing references) //IL_05f4: Unknown result type (might be due to invalid IL or missing references) //IL_05f9: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = prefab.GetComponentsInChildren(true); Renderer val = (Renderer)(object)grabbable.mainObjectRenderer; if ((Object)(object)val == (Object)null) { val = ((IEnumerable)componentsInChildren).FirstOrDefault((Func)((Renderer renderer) => renderer is MeshRenderer && (Object)(object)((Component)renderer).GetComponent() != (Object)null)); } if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("Could not find a mesh anchor renderer for " + assetName + "."); } GameObject gameObject = ((Component)val).gameObject; int layer = gameObject.layer; MeshRenderer val2 = (MeshRenderer)(object)((val is MeshRenderer) ? val : null); MeshFilter val3 = gameObject.GetComponent(); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { val.enabled = false; val3 = gameObject.GetComponent() ?? gameObject.AddComponent(); val2 = gameObject.GetComponent() ?? gameObject.AddComponent(); } Quaternion localRotation = gameObject.transform.localRotation; Vector3 localPosition = gameObject.transform.localPosition; gameObject.layer = layer; for (int num = gameObject.transform.childCount - 1; num >= 0; num--) { Transform child = gameObject.transform.GetChild(num); if ((Object)(object)child != (Object)null && (((Object)child).name.StartsWith("FGS_Part_", StringComparison.Ordinal) || ((Object)child).name == "FGS_ShumovkaVisual")) { Object.DestroyImmediate((Object)(object)((Component)child).gameObject); } } MeshFilter val4 = val3; MeshRenderer val5 = val2; if (assetName == "Shumovka") { GameObject val6 = new GameObject("FGS_ShumovkaVisual") { layer = layer }; val6.transform.SetParent(gameObject.transform, false); val6.transform.localPosition = Vector3.zero; val6.transform.localRotation = Quaternion.identity; val6.transform.localScale = Vector3.one; val4 = val6.AddComponent(); val5 = val6.AddComponent(); } Bounds val7 = default(Bounds); bool flag = false; if (RuntimeAssets.HasVisualParts(assetName)) { List list = RuntimeAssets.LoadVisualParts(assetName); if (list.Count == 0) { throw new InvalidOperationException("Visual-parts manifest for " + assetName + " contained no parts."); } RuntimeAssets.VisualPart visualPart = list[0]; val4.sharedMesh = visualPart.Mesh; ((Renderer)val5).sharedMaterial = visualPart.Material; ((Renderer)val5).enabled = true; val7 = visualPart.Mesh.bounds; flag = true; for (int num2 = 1; num2 < list.Count; num2++) { RuntimeAssets.VisualPart visualPart2 = list[num2]; GameObject val8 = new GameObject("FGS_Part_" + visualPart2.Name) { layer = layer }; val8.transform.SetParent(((Component)val5).transform, false); val8.transform.localPosition = Vector3.zero; val8.transform.localRotation = Quaternion.identity; val8.transform.localScale = Vector3.one; val8.AddComponent().sharedMesh = visualPart2.Mesh; ((Renderer)val8.AddComponent()).sharedMaterial = visualPart2.Material; Bounds bounds = visualPart2.Mesh.bounds; ((Bounds)(ref val7)).Encapsulate(((Bounds)(ref bounds)).min); bounds = visualPart2.Mesh.bounds; ((Bounds)(ref val7)).Encapsulate(((Bounds)(ref bounds)).max); } } else { Mesh val9 = (val4.sharedMesh = RuntimeAssets.LoadMesh(assetName)); ((Renderer)val5).sharedMaterial = RuntimeAssets.CreateMaterial(assetName); ((Renderer)val5).enabled = true; val7 = val9.bounds; flag = true; } float targetLongestDimensionMetres = GetTargetLongestDimensionMetres(assetName); float num3 = Mathf.Max(((Bounds)(ref val7)).size.x, Mathf.Max(((Bounds)(ref val7)).size.y, ((Bounds)(ref val7)).size.z)); float num4 = ((num3 > 0.0001f) ? (targetLongestDimensionMetres / num3 * Mathf.Max(0.05f, visualScale)) : 1f); Transform parent = gameObject.transform.parent; float num5 = 1f; if ((Object)(object)parent != (Object)null) { Vector3 lossyScale = parent.lossyScale; num5 = Mathf.Max(0.0001f, Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Max(Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z)))); } float num6 = num4 / num5; gameObject.transform.localScale = Vector3.one * num6; float value = Plugin.ModConfig.ModelRotationZDegrees.Value; Quaternion modelSpaceCorrection = GetModelSpaceCorrection(assetName, value); gameObject.transform.localPosition = localPosition; if (assetName == "Shumovka") { gameObject.transform.localRotation = localRotation * modelSpaceCorrection; Vector3 val11 = default(Vector3); ((Vector3)(ref val11))..ctor(0f, 0.16f, 0.31f); Vector3 val12 = modelSpaceCorrection * val11; gameObject.transform.localPosition = localPosition - localRotation * val12 * num6; } else { gameObject.transform.localRotation = modelSpaceCorrection; } Renderer[] array = componentsInChildren; foreach (Renderer val13 in array) { if ((Object)(object)val13 == (Object)null || (Object)(object)val13 == (Object)(object)val5) { continue; } val13.enabled = false; MeshRenderer val14 = (MeshRenderer)(object)((val13 is MeshRenderer) ? val13 : null); if ((Object)(object)val14 != (Object)null) { MeshFilter component = ((Component)val14).GetComponent(); if ((Object)(object)component != (Object)null) { component.sharedMesh = null; } ((Renderer)val14).sharedMaterial = null; } else { SkinnedMeshRenderer val15 = (SkinnedMeshRenderer)(object)((val13 is SkinnedMeshRenderer) ? val13 : null); if ((Object)(object)val15 != (Object)null) { val15.sharedMesh = null; ((Renderer)val15).sharedMaterial = null; } } } grabbable.mainObjectRenderer = val5; Collider[] componentsInChildren2 = prefab.GetComponentsInChildren(true); foreach (Collider val16 in componentsInChildren2) { if ((Object)(object)val16 != (Object)null && !val16.isTrigger) { val16.enabled = false; } } BoxCollider val17 = gameObject.GetComponent() ?? gameObject.AddComponent(); ((Collider)val17).enabled = true; ((Collider)val17).isTrigger = false; if (flag) { val17.center = ((Bounds)(ref val7)).center; val17.size = Vector3.Max(((Bounds)(ref val7)).size * 0.9f, new Vector3(0.08f, 0.08f, 0.08f)); } UpdateScanNode(prefab, scanHeader); Plugin.Log.LogInfo((object)$"Bound {assetName} to '{((Object)gameObject).name}': target longest dimension {targetLongestDimensionMetres:0.00} m, size multiplier {visualScale:0.##}, extra local Z rotation {value:0.#} deg. Donor anchor preserved; per-model correction applied where required."); } private static Quaternion GetModelSpaceCorrection(string assetName, float extraZDegrees) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) Quaternion val = Quaternion.identity; if (assetName == "Shumovka") { Quaternion val2 = Quaternion.AngleAxis(-124.5f, Vector3.right); val = Quaternion.AngleAxis(Plugin.ModConfig.ShumovkaRollDegrees.Value, Vector3.up) * val2; } if (Mathf.Abs(extraZDegrees) > 0.001f) { val *= Quaternion.Euler(0f, 0f, extraZDegrees); } return val; } private static void ConfigureHeldFacing(Item item, float yawDegrees) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)item == (Object)null) && !(Mathf.Abs(yawDegrees) < 0.001f)) { object member = ReflectionUtil.GetMember(item, "rotationOffset"); Vector3 val = (Vector3)((member is Vector3) ? ((Vector3)member) : Vector3.zero); val.y = NormalizeDegrees(val.y + yawDegrees); ReflectionUtil.SetMember(item, "rotationOffset", val); Plugin.Log.LogInfo((object)$"Held-facing correction for {item.itemName}: +{yawDegrees:0.#}° yaw -> rotationOffset {val}."); } } private static float NormalizeDegrees(float degrees) { degrees %= 360f; if (degrees > 180f) { degrees -= 360f; } if (degrees < -180f) { degrees += 360f; } return degrees; } private static void ConfigureUprightRest(Item item, float zDegrees) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)item == (Object)null)) { ReflectionUtil.SetMember(item, "restingRotation", (object)new Vector3(0f, 0f, zDegrees)); ReflectionUtil.SetMember(item, "verticalOffset", 0f); } } private static float GetTargetLongestDimensionMetres(string assetName) { return assetName switch { "Shumovka" => 1.1f, "BaconEggCheese" => 0.2f, "Balbal" => 1.2f, "Blumpkin" => 0.42f, "Tvorog" => 0.24f, "Zubrowka" => 0.33f, "Moutai" => 0.25f, "KyivCake" => 0.3f, "Bimbka" => 0.85f, "Hasbullah" => 0.75f, "Doshirak" => 0.24f, "Menorah" => 0.55f, _ => 0.35f, }; } private static void UpdateScanNode(GameObject prefab, string headerText) { MonoBehaviour[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (MonoBehaviour val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(((object)val).GetType().Name != "ScanNodeProperties")) { ReflectionUtil.SetMember(val, "headerText", headerText); break; } } } private static void ConfigureNoisemaker(Item item, AudioClip[] clips) { NoisemakerProp component = item.spawnPrefab.GetComponent(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException(item.itemName + " was cloned from a noisemaker but has no NoisemakerProp."); } ReflectionUtil.SetMember(component, "noiseSFX", clips); ReflectionUtil.SetMember(component, "noiseSFXFar", clips); ReflectionUtil.SetMember(component, "minPitch", 1f); ReflectionUtil.SetMember(component, "maxPitch", 1f); ReflectionUtil.SetMember(item, "syncUseFunction", true); } private static void CopyVanillaHandlingSounds(Item source, Item destination) { if ((Object)(object)source == (Object)null || (Object)(object)destination == (Object)null) { return; } string[] array = new string[4] { "grabSFX", "dropSFX", "pocketSFX", "throwSFX" }; foreach (string name in array) { object member = ReflectionUtil.GetMember(source, name); if (member != null) { ReflectionUtil.SetMember(destination, name, member); } } } } internal enum LoquatItemKind { Unknown, Shumovka, BaconEggCheese, Balbal, Tvorog, Zubrowka, Moutai, KyivCake, Bimbka, Hasbullah, Doshirak, Menorah, Blumpkin } internal sealed class LoquatItemMarker : MonoBehaviour { [SerializeField] private LoquatItemKind kind; internal LoquatItemKind Kind { get { return kind; } set { kind = value; } } } internal sealed class MenorahLightMarker : MonoBehaviour { private GameObject flamesRoot; private Light warmLight; private float lastToggleTime = -10f; private bool isLit = true; internal bool IsLit => isLit; private void Start() { try { BuildFlames(); SetLit(value: true); } catch (Exception ex) { Plugin.Log.LogDebug((object)("Menorah visual setup was disabled: " + ex.GetBaseException().Message)); ((Behaviour)this).enabled = false; } } private void BuildFlames() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Expected O, but got Unknown //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)flamesRoot != (Object)null) { return; } GrabbableObject component = ((Component)this).GetComponent(); Renderer val = (Renderer)(((Object)(object)component != (Object)null) ? ((object)component.mainObjectRenderer) : ((object)((Component)this).GetComponentInChildren(true))); Transform val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : ((Component)this).transform); MeshFilter component2 = ((Component)val2).GetComponent(); Bounds val3 = (Bounds)(((Object)(object)component2 != (Object)null && (Object)(object)component2.sharedMesh != (Object)null) ? component2.sharedMesh.bounds : new Bounds(new Vector3(0f, 0.5f, 0f), new Vector3(0.8f, 1f, 0.35f))); flamesRoot = new GameObject("FGS_MenorahFlames"); flamesRoot.transform.SetParent(val2, false); Material sharedMaterial = CreateFlameMaterial(); float num = ((Bounds)(ref val3)).extents.x * 0.86f; float num2 = ((Bounds)(ref val3)).max.y - ((Bounds)(ref val3)).size.y * 0.05f; float num3 = ((Bounds)(ref val3)).max.y + ((Bounds)(ref val3)).size.y * 0.005f; float z = ((Bounds)(ref val3)).center.z; for (int i = 0; i < 9; i++) { float num4 = (float)(i - 4) / 4f * num; float num5 = ((i == 4) ? num3 : num2); GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)obj).name = "FGS_MenorahFlame_" + i; obj.transform.SetParent(flamesRoot.transform, false); obj.transform.localPosition = new Vector3(num4, num5, z); float num6 = ((Bounds)(ref val3)).size.y * 0.019f; obj.transform.localScale = new Vector3(num6 * 0.75f, num6 * 1.55f, num6 * 0.75f); Collider component3 = obj.GetComponent(); if ((Object)(object)component3 != (Object)null) { Object.Destroy((Object)(object)component3); } Renderer component4 = obj.GetComponent(); if ((Object)(object)component4 != (Object)null) { component4.sharedMaterial = sharedMaterial; } } GameObject val4 = new GameObject("FGS_MenorahWarmLight"); val4.transform.SetParent(val2, false); val4.transform.localPosition = new Vector3(0f, ((Bounds)(ref val3)).max.y, z); warmLight = val4.AddComponent(); warmLight.type = (LightType)2; warmLight.color = new Color(1f, 0.48f, 0.16f, 1f); warmLight.range = 2.4f; warmLight.intensity = 6f; warmLight.shadows = (LightShadows)0; } private static Material CreateFlameMaterial() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("HDRP/Unlit") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Standard"); if ((Object)(object)val == (Object)null) { return null; } Material val2 = new Material(val) { name = "FGS_MenorahFlameMaterial" }; Color val3 = default(Color); ((Color)(ref val3))..ctor(1f, 0.34f, 0.06f, 1f); if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", val3); } if (val2.HasProperty("_Color")) { val2.SetColor("_Color", val3); } if (val2.HasProperty("_EmissiveColor")) { val2.SetColor("_EmissiveColor", val3 * 4f); } if (val2.HasProperty("_EmissionColor")) { val2.SetColor("_EmissionColor", val3 * 4f); val2.EnableKeyword("_EMISSION"); } return val2; } internal void ToggleFromActivation() { if (!(Time.unscaledTime - lastToggleTime < 0.65f)) { lastToggleTime = Time.unscaledTime; SetLit(!isLit); } } private void SetLit(bool value) { isLit = value; if ((Object)(object)flamesRoot != (Object)null) { flamesRoot.SetActive(value); } if ((Object)(object)warmLight != (Object)null) { ((Behaviour)warmLight).enabled = value; } } internal bool CanRelightNearFire() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) if (isLit) { return true; } Vector3 position = ((Component)this).transform.position; MenorahLightMarker[] array = Object.FindObjectsOfType(); foreach (MenorahLightMarker menorahLightMarker in array) { if ((Object)(object)menorahLightMarker != (Object)null && (Object)(object)menorahLightMarker != (Object)(object)this && menorahLightMarker.IsLit && Vector3.Distance(position, ((Component)menorahLightMarker).transform.position) <= 2.25f) { return true; } } Collider[] array2 = Physics.OverlapSphere(position, 2.25f, -1, (QueryTriggerInteraction)2); foreach (Collider val in array2) { if (!((Object)(object)val == (Object)null) && LooksLikeFire(((Component)val).transform)) { return true; } } ParticleSystem[] array3 = Object.FindObjectsOfType(); foreach (ParticleSystem val2 in array3) { if ((Object)(object)val2 != (Object)null && val2.isPlaying && Vector3.Distance(position, ((Component)val2).transform.position) <= 2.25f && LooksLikeFire(((Component)val2).transform)) { return true; } } MonoBehaviour[] array4 = Object.FindObjectsOfType(); foreach (MonoBehaviour val3 in array4) { if (!((Object)(object)val3 == (Object)null) && !(Vector3.Distance(position, ((Component)val3).transform.position) > 2.25f)) { string text = ((object)val3).GetType().Name.ToLowerInvariant(); if (!text.Contains("fireexit") && (text.Contains("flame") || text.Contains("campfire") || text.Contains("bonfire") || text.Contains("fireplace") || text.Contains("lighter") || text.Contains("torch"))) { return true; } } } return false; } private static bool LooksLikeFire(Transform transform) { Transform val = transform; while ((Object)(object)val != (Object)null) { string text = ((Object)val).name.ToLowerInvariant(); if (!text.Contains("fireexit") && !text.Contains("fire exit") && (text.Contains("flame") || text.Contains("campfire") || text.Contains("bonfire") || text.Contains("fireplace") || text.Contains("lighter") || text.Contains("torch") || text.Contains("candle"))) { return true; } val = val.parent; } return false; } internal void PlayFailedRelightFeedback() { Plugin.Log.LogInfo((object)"Menorah is extinguished; bring it near an active flame/fire source to relight it."); } } internal sealed class ModConfig { internal readonly ConfigEntry ShumovkaRarity; internal readonly ConfigEntry BaconEggCheeseRarity; internal readonly ConfigEntry BalbalRarity; internal readonly ConfigEntry TvorogRarity; internal readonly ConfigEntry ZubrowkaRarity; internal readonly ConfigEntry MoutaiRarity; internal readonly ConfigEntry KyivCakeRarity; internal readonly ConfigEntry BimbkaRarity; internal readonly ConfigEntry HasbullahRarity; internal readonly ConfigEntry DoshirakRarity; internal readonly ConfigEntry MenorahRarity; internal readonly ConfigEntry BlumpkinChancePercent; internal readonly ConfigEntry MusicExcerptSeconds; internal readonly ConfigEntry BaconEggCheeseEmoteName; internal readonly ConfigEntry TvorogEmoteName; internal readonly ConfigEntry ShumovkaScale; internal readonly ConfigEntry BaconEggCheeseScale; internal readonly ConfigEntry BalbalScale; internal readonly ConfigEntry BlumpkinScale; internal readonly ConfigEntry TvorogScale; internal readonly ConfigEntry ZubrowkaScale; internal readonly ConfigEntry MoutaiScale; internal readonly ConfigEntry KyivCakeScale; internal readonly ConfigEntry BimbkaScale; internal readonly ConfigEntry HasbullahScale; internal readonly ConfigEntry DoshirakScale; internal readonly ConfigEntry MenorahScale; internal readonly ConfigEntry ShumovkaRollDegrees; internal readonly ConfigEntry ModelRotationZDegrees; internal readonly ConfigEntry HeldFacingYawDegrees; internal ModConfig(ConfigFile config) { ShumovkaRarity = config.Bind("Spawn", "ShumovkaRarity", 6, "Relative scrap rarity on all moons. Intentionally rare by default."); BaconEggCheeseRarity = config.Bind("Spawn", "BaconEggCheeseRarity", 5, "Relative scrap rarity on all moons. Intentionally rare by default."); BalbalRarity = config.Bind("Spawn", "BalbalRarity", 3, "Relative scrap rarity on all moons. Very rare by default."); TvorogRarity = config.Bind("Spawn", "TvorogRarity", 5, "Relative scrap rarity on all moons. Intentionally rare by default."); ZubrowkaRarity = config.Bind("Spawn", "ZubrowkaRarity", 5, "Relative scrap rarity on all moons. Intentionally rare by default."); MoutaiRarity = config.Bind("Spawn", "MoutaiRarity", 2, "Relative scrap rarity on all moons. Very rare premium bottle."); KyivCakeRarity = config.Bind("Spawn", "KyivCakeRarity", 4, "Relative scrap rarity on all moons. Intentionally rare by default."); BimbkaRarity = config.Bind("Spawn", "BimbkaRarity", 3, "Relative scrap rarity on all moons. Heavy and very rare, like Balbal."); HasbullahRarity = config.Bind("Spawn", "HasbullahRarity", 1, "Extremely rare two-handed inert scrap."); DoshirakRarity = config.Bind("Spawn", "DoshirakRarity", 4, "Rare inert instant-noodle tray scrap."); MenorahRarity = config.Bind("Spawn", "MenorahRarity", 3, "Very rare interactive menorah scrap."); BlumpkinChancePercent = config.Bind("Spawn", "BlumpkinChancePercent", 1.5f, "Chance per landing to spawn one Blumpkin on pumpkin-eligible moons. It is deliberately rarer than normal custom scrap."); MusicExcerptSeconds = config.Bind("Audio", "MusicExcerptSeconds", 0f, "Length of Bacon Egg and Cheese / Tvorog audio used by the item. Set to 0 to play the full source clip (default)."); BaconEggCheeseEmoteName = config.Bind("TooManyEmotes v2", "BaconEggCheeseEmoteName", "feelin'_jaunty", "One exact TooManyEmotes emote identifier requested by Bacon Egg and Cheese. Upbeat/pop-dance default; no random fallback."); TvorogEmoteName = config.Bind("TooManyEmotes v2", "TvorogEmoteName", "smug_dance", "One exact TooManyEmotes emote identifier requested by Tvorog. Smooth/swaying default; no random fallback."); ShumovkaScale = config.Bind("Visuals v5", "ShumovkaSizeMultiplier", 1.2f, "Multiplier on the enlarged shovel-class Shumovka target size."); BaconEggCheeseScale = config.Bind("Visuals v5", "BaconEggCheeseSizeMultiplier", 1.2f, "Multiplier on the ~0.20 m sandwich target size."); BalbalScale = config.Bind("Visuals v5", "BalbalSizeMultiplier", 1.2f, "Multiplier on the ~1.20 m Balbal target size. 1.20 default makes the statue ~1.44 m tall/longest-axis target."); BlumpkinScale = config.Bind("Visuals v5", "BlumpkinSizeMultiplier", 1.2f, "Multiplier on the ~0.42 m pumpkin target size."); TvorogScale = config.Bind("Visuals v5", "TvorogSizeMultiplier", 1.2f, "Multiplier on the ~0.24 m bowl target size."); ZubrowkaScale = config.Bind("Visuals v5", "ZubrowkaSizeMultiplier", 1.2f, "Multiplier on the ~0.33 m bottle target size."); MoutaiScale = config.Bind("Visuals v5", "MoutaiSizeMultiplier", 1.2f, "Multiplier on the ~0.25 m bottle target size."); KyivCakeScale = config.Bind("Visuals v5", "KyivCakeSizeMultiplier", 1.2f, "Multiplier on the ~0.30 m cake-box target diameter."); BimbkaScale = config.Bind("Visuals v5", "BimbkaSizeMultiplier", 1.2f, "Multiplier on the ~0.85 m heavy Bimbka target size."); HasbullahScale = config.Bind("Visuals v5", "HasbullahSizeMultiplier", 1.2f, "Multiplier on the ~0.75 m Hasbullah target size."); DoshirakScale = config.Bind("Visuals v5", "DoshirakSizeMultiplier", 1.2f, "Multiplier on the ~0.24 m Doshirak tray target size."); MenorahScale = config.Bind("Visuals v5", "MenorahSizeMultiplier", 1.2f, "Multiplier on the ~0.55 m menorah target size."); ShumovkaRollDegrees = config.Bind("Visuals v5", "ShumovkaRollDegrees", 45f, "Roll around Shumovka's long handle axis. 45 degrees makes the spoon/skimmer bowl perpendicular to the player's torso."); ModelRotationZDegrees = config.Bind("Visuals v5", "ModelRotationZDegrees", 0f, "Advanced global model-space Z correction. Leave at 0; floor orientation is now fixed using each Item's resting rotation instead."); HeldFacingYawDegrees = config.Bind("Held Poses v1", "HeldFacingYawDegrees", 180f, "Held-only yaw correction for Loquat Scrap Pack items except Shumovka. 180 makes front-facing props face the player while carried; dropped orientation is unaffected."); } } internal static class ModPatches { internal static bool BeforeNoisemakerActivate(NoisemakerProp __instance, object[] __args) { try { if (GetKind((Component)(object)__instance) != LoquatItemKind.Menorah) { return true; } if (IsReleaseCallback(__args)) { return true; } MenorahLightMarker component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } if (component.IsLit || component.CanRelightNearFire()) { return true; } component.PlayFailedRelightFeedback(); return false; } catch (Exception ex) { Plugin.Log.LogDebug((object)("Menorah activation compatibility fallback: " + ex.GetBaseException().Message)); return true; } } internal static void BeforeGameNetworkManagerStart() { try { ItemFactory.BuildAll(); } catch (Exception ex) { Plugin.Log.LogError((object)("Loquat item initialization stopped unexpectedly. The game will continue without any remaining Loquat items. " + ex)); } } internal static void AfterNoisemakerActivate(NoisemakerProp __instance, object[] __args) { try { LoquatItemKind kind = GetKind((Component)(object)__instance); switch (kind) { case LoquatItemKind.Unknown: return; case LoquatItemKind.Balbal: PulseBalbal(__instance); break; } if (kind == LoquatItemKind.Menorah) { MenorahLightMarker component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { component.ToggleFromActivation(); } } if (!IsReleaseCallback(__args) && (kind == LoquatItemKind.BaconEggCheese || kind == LoquatItemKind.Tvorog)) { object member = ReflectionUtil.GetMember(__instance, "playerHeldBy"); if ((Object)(object)StartOfRound.Instance != (Object)null && member == StartOfRound.Instance.localPlayerController) { TooManyEmotesCompat.TryDance((kind == LoquatItemKind.BaconEggCheese) ? Plugin.ModConfig.BaconEggCheeseEmoteName.Value : Plugin.ModConfig.TvorogEmoteName.Value); } } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Loquat noisemaker post-activation hook was skipped: " + ex.GetBaseException().Message)); } } internal static void AfterNoisemakerNetworkPlayback(NoisemakerProp __instance) { try { switch (GetKind((Component)(object)__instance)) { case LoquatItemKind.Balbal: PulseBalbal(__instance); break; case LoquatItemKind.Menorah: { MenorahLightMarker component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { component.ToggleFromActivation(); } break; } } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Remote Loquat noisemaker feedback was skipped: " + ex.GetBaseException().Message)); } } internal static void AfterShovelActivate(Shovel __instance) { try { if (IsShumovka(__instance)) { object member = ReflectionUtil.GetMember(ReflectionUtil.GetMember(__instance, "playerHeldBy"), "playerBodyAnimator"); Animator val = (Animator)((member is Animator) ? member : null); if (!((Object)(object)val == (Object)null) && ReflectionUtil.GetMember(__instance, "reelingUp") is int num && num != 0) { val.ResetTrigger("shovelHit"); val.SetBool("reelingUp", true); } } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Shumovka reel animation compatibility fallback: " + ex.GetBaseException().Message)); } } internal static void AfterShovelSwing(Shovel __instance) { try { if (IsShumovka(__instance)) { object member = ReflectionUtil.GetMember(ReflectionUtil.GetMember(__instance, "playerHeldBy"), "playerBodyAnimator"); Animator val = (Animator)((member is Animator) ? member : null); if ((Object)(object)val != (Object)null) { val.SetBool("reelingUp", false); val.ResetTrigger("shovelHit"); val.SetTrigger("shovelHit"); } } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Shumovka swing animation compatibility fallback: " + ex.GetBaseException().Message)); } } private static bool IsShumovka(Shovel shovel) { return GetKind((Component)(object)shovel) == LoquatItemKind.Shumovka; } private static LoquatItemKind GetKind(Component component) { if ((Object)(object)component == (Object)null) { return LoquatItemKind.Unknown; } LoquatItemMarker component2 = component.GetComponent(); if (!((Object)(object)component2 == (Object)null)) { return component2.Kind; } return LoquatItemKind.Unknown; } private static bool IsReleaseCallback(object[] args) { if (args != null && args.Length != 0 && args[0] is bool && !(bool)args[0]) { return true; } if (args != null && args.Length > 1 && args[1] is bool && !(bool)args[1]) { return true; } return false; } private static void PulseBalbal(NoisemakerProp prop) { BalbalGlowMarker balbalGlowMarker = (((Object)(object)prop == (Object)null) ? null : ((Component)prop).GetComponent()); if ((Object)(object)balbalGlowMarker != (Object)null) { balbalGlowMarker.PulseForCurrentPlayback(); } } internal static void AfterSpawnMapObjects() { try { BlumpkinSpawner.TrySpawn(); } catch (Exception ex) { Plugin.Log.LogDebug((object)("Blumpkin spawn attempt skipped: " + ex.GetBaseException().Message)); } } } [BepInPlugin("sosigelite.loquatscrappack", "Loquat Scrap Pack", "0.3.4")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "sosigelite.loquatscrappack"; public const string PluginName = "Loquat Scrap Pack"; public const string PluginVersion = "0.3.4"; private Harmony harmony; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ModConfig ModConfig { get; private set; } internal static string ModDirectory { get; private set; } private void Awake() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ModDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); ModConfig = new ModConfig(((BaseUnityPlugin)this).Config); harmony = new Harmony("sosigelite.loquatscrappack"); if (!TryPatch(typeof(GameNetworkManager), "Start", typeof(ModPatches), "BeforeGameNetworkManagerStart", prefix: true, 800, quietIfMissing: false)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not install the Loquat item-registration hook. The pack will stay disabled for this session, but the game will continue normally."); } TryPatch(typeof(NoisemakerProp), "ItemActivate", typeof(ModPatches), "BeforeNoisemakerActivate", prefix: true, 200, quietIfMissing: false); TryPatch(typeof(NoisemakerProp), "ItemActivate", typeof(ModPatches), "AfterNoisemakerActivate", prefix: false, 200, quietIfMissing: false); TryPatchNoisemakerPlaybackRpc(); TryPatch(typeof(Shovel), "ItemActivate", typeof(ModPatches), "AfterShovelActivate", prefix: false, 200, quietIfMissing: true); TryPatch(typeof(Shovel), "SwingShovel", typeof(ModPatches), "AfterShovelSwing", prefix: false, 200, quietIfMissing: true); TryPatch(typeof(RoundManager), "SpawnMapObjects", typeof(ModPatches), "AfterSpawnMapObjects", prefix: false, 200, quietIfMissing: true); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loquat Scrap Pack 0.3.4 loaded."); } private bool TryPatch(Type targetType, string methodName, Type patchType, string patchName, bool prefix, int priority, bool quietIfMissing) { //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(targetType, methodName, (Type[])null, (Type[])null); if (methodInfo == null) { if (!quietIfMissing) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Patch target " + targetType.Name + "." + methodName + " was not found. Related Loquat functionality will be disabled.")); } else { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Optional patch target " + targetType.Name + "." + methodName + " was not found.")); } return false; } MethodInfo methodInfo2 = AccessTools.Method(patchType, patchName, (Type[])null, (Type[])null); if (methodInfo2 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Internal patch method " + patchType.Name + "." + patchName + " was not found.")); return false; } HarmonyMethod val = new HarmonyMethod(methodInfo2) { priority = priority }; harmony.Patch((MethodBase)methodInfo, prefix ? val : null, prefix ? null : val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not patch " + targetType.Name + "." + methodName + "; related Loquat functionality will be disabled. " + ex.GetBaseException().Message)); return false; } } private void TryPatchNoisemakerPlaybackRpc() { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown try { MethodInfo methodInfo = (from method in typeof(NoisemakerProp).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where method.Name.IndexOf("ClientRpc", StringComparison.OrdinalIgnoreCase) >= 0 where method.Name.IndexOf("Noise", StringComparison.OrdinalIgnoreCase) >= 0 || method.Name.IndexOf("Sound", StringComparison.OrdinalIgnoreCase) >= 0 orderby string.Equals(method.Name, "PlayNoiseClientRpc", StringComparison.Ordinal) descending select method).FirstOrDefault(); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogDebug((object)"No compatible NoisemakerProp playback ClientRpc was found; remote Loquat noisemaker visual feedback is disabled."); return; } HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(ModPatches), "AfterNoisemakerNetworkPlayback", (Type[])null, (Type[])null)) { priority = 200 }; harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogDebug((object)("Remote noisemaker feedback attached to " + methodInfo.Name + ".")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Remote noisemaker feedback could not be patched and was disabled: " + ex.GetBaseException().Message)); } } } internal static class ReflectionUtil { private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; internal static bool SetMember(object target, string name, object value) { if (target == null || string.IsNullOrEmpty(name)) { return false; } try { Type type = ((target is Type) ? ((Type)target) : target.GetType()); object obj = ((target is Type) ? null : target); FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(obj, value); return true; } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { property.SetValue(obj, value, null); return true; } } catch { } return false; } internal static object GetMember(object target, string name) { if (target == null || string.IsNullOrEmpty(name)) { return null; } try { Type type = ((target is Type) ? ((Type)target) : target.GetType()); object obj = ((target is Type) ? null : target); FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(obj); } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { return property.GetValue(obj, null); } } catch { } return null; } internal static T GetMember(object target, string name) where T : class { return GetMember(target, name) as T; } } internal static class RuntimeAssets { internal sealed class VisualPart { internal string Name; internal Mesh Mesh; internal Material Material; internal bool Transparent; } private static string AssetRoot => Path.Combine(Plugin.ModDirectory, "AssetsData"); internal static Mesh LoadMesh(string assetName) { return LoadMeshFile(Path.Combine(AssetRoot, "Meshes", assetName + ".meshbin"), "FGS_" + assetName); } private static Mesh LoadMeshFile(string path, string meshName) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown using FileStream input = File.OpenRead(path); using BinaryReader binaryReader = new BinaryReader(input); if (Encoding.ASCII.GetString(binaryReader.ReadBytes(4)) != "FGSM") { throw new InvalidDataException("Invalid mesh file: " + path); } uint num = binaryReader.ReadUInt32(); if (num != 1) { throw new InvalidDataException($"Unsupported FGSM mesh version {num}: {path}"); } int num2; int num3; Vector3[] array; Vector3[] array2; Vector2[] array3; int[] array4; checked { num2 = (int)binaryReader.ReadUInt32(); num3 = (int)binaryReader.ReadUInt32(); array = (Vector3[])(object)new Vector3[num2]; array2 = (Vector3[])(object)new Vector3[num2]; array3 = (Vector2[])(object)new Vector2[num2]; array4 = new int[num3]; } for (int i = 0; i < num2; i++) { array[i] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()); } for (int j = 0; j < num2; j++) { array2[j] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()); } for (int k = 0; k < num2; k++) { array3[k] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle()); } for (int l = 0; l < num3; l++) { array4[l] = checked((int)binaryReader.ReadUInt32()); } Mesh val = new Mesh { name = meshName, indexFormat = (IndexFormat)(num2 > 65535) }; val.vertices = array; val.normals = array2; val.uv = array3; val.triangles = array4; val.RecalculateBounds(); try { val.RecalculateTangents(); } catch { } return val; } internal static bool HasVisualParts(string assetName) { return File.Exists(Path.Combine(AssetRoot, "Parts", assetName, "parts.tsv")); } internal static List LoadVisualParts(string assetName) { string path = Path.Combine(AssetRoot, "Parts", assetName); string path2 = Path.Combine(path, "parts.tsv"); if (!File.Exists(path2)) { return new List(); } List list = new List(); string[] array = File.ReadAllLines(path2); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0 && !text.StartsWith("#")) { string[] array2 = text.Split('|'); if (array2.Length < 6) { throw new InvalidDataException("Invalid visual-part line for " + assetName + ": " + text); } string text2 = array2[0]; string path3 = Path.Combine(path, array2[1]); string texturePath = Path.Combine(path, array2[2]); bool transparent = array2[3] == "1"; if (!float.TryParse(array2[4], NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { result = 0.35f; } bool doubleSided = array2[5] == "1"; list.Add(new VisualPart { Name = text2, Mesh = LoadMeshFile(path3, "FGS_" + assetName + "_" + text2), Material = CreatePartMaterial(assetName, text2, texturePath, transparent, result, doubleSided), Transparent = transparent }); } } return list; } internal static Texture2D LoadTexture(string assetName, string suffix, bool linear) { //IL_0030: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0068: Expected O, but got Unknown string path = Path.Combine(AssetRoot, "Textures", assetName + "_" + suffix + ".png"); if (!File.Exists(path)) { return null; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear) { name = "FGS_" + assetName + "_" + suffix, wrapMode = (TextureWrapMode)0, filterMode = (FilterMode)1 }; ImageConversion.LoadImage(val, File.ReadAllBytes(path)); return val; } private static Texture2D LoadTextureFile(string path, string textureName) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_002d: Expected O, but got Unknown Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, false) { name = textureName, wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; ImageConversion.LoadImage(val, File.ReadAllBytes(path)); return val; } private static Material CreatePartMaterial(string assetName, string partName, string texturePath, bool transparent, float smoothness, bool doubleSided) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) Shader obj = Shader.Find("HDRP/Lit") ?? Shader.Find("Standard"); if ((Object)(object)obj == (Object)null) { throw new InvalidOperationException("Could not find HDRP/Lit or Standard shader."); } Material val = new Material(obj); ((Object)val).name = "FGS_" + assetName + "_" + partName + "_Material"; Material val2 = val; Texture2D val3 = LoadTextureFile(texturePath, "FGS_" + assetName + "_" + partName + "_Base"); if (val2.HasProperty("_BaseColorMap")) { val2.SetTexture("_BaseColorMap", (Texture)(object)val3); } if (val2.HasProperty("_MainTex")) { val2.SetTexture("_MainTex", (Texture)(object)val3); } if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", Color.white); } if (val2.HasProperty("_Color")) { val2.SetColor("_Color", Color.white); } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", smoothness); } if (val2.HasProperty("_Glossiness")) { val2.SetFloat("_Glossiness", smoothness); } if (doubleSided) { val2.doubleSidedGI = true; if (val2.HasProperty("_DoubleSidedEnable")) { val2.SetFloat("_DoubleSidedEnable", 1f); } if (val2.HasProperty("_CullMode")) { val2.SetFloat("_CullMode", 0f); } if (val2.HasProperty("_Cull")) { val2.SetFloat("_Cull", 0f); } val2.EnableKeyword("_DOUBLESIDED_ON"); } if (transparent) { ConfigureTransparentMaterial(val2); } return val2; } private static void ConfigureTransparentMaterial(Material material) { material.SetOverrideTag("RenderType", "Transparent"); material.renderQueue = 3000; if (material.HasProperty("_SurfaceType")) { material.SetFloat("_SurfaceType", 1f); } if (material.HasProperty("_BlendMode")) { material.SetFloat("_BlendMode", 0f); } if (material.HasProperty("_SrcBlend")) { material.SetFloat("_SrcBlend", 5f); } if (material.HasProperty("_DstBlend")) { material.SetFloat("_DstBlend", 10f); } if (material.HasProperty("_ZWrite")) { material.SetFloat("_ZWrite", 0f); } if (material.HasProperty("_AlphaDstBlend")) { material.SetFloat("_AlphaDstBlend", 10f); } material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); material.EnableKeyword("_BLENDMODE_ALPHA"); material.EnableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); } internal static Material CreateMaterial(string assetName) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) Shader obj = Shader.Find("HDRP/Lit") ?? Shader.Find("Standard"); if ((Object)(object)obj == (Object)null) { throw new InvalidOperationException("Could not find HDRP/Lit or Standard shader."); } Material val = new Material(obj) { name = "FGS_" + assetName + "_Material" }; Texture2D val2 = LoadTexture(assetName, "Base", linear: false); Texture2D val3 = LoadTexture(assetName, "Normal", linear: true); Texture2D val4 = LoadTexture(assetName, "Mask", linear: true); if ((Object)(object)val2 != (Object)null) { if (val.HasProperty("_BaseColorMap")) { val.SetTexture("_BaseColorMap", (Texture)(object)val2); } if (val.HasProperty("_MainTex")) { val.SetTexture("_MainTex", (Texture)(object)val2); } } if (val.HasProperty("_BaseColor")) { val.SetColor("_BaseColor", Color.white); } if (val.HasProperty("_Color")) { val.SetColor("_Color", Color.white); } float num = 0.35f; switch (assetName) { case "Zubrowka": num = 0.72f; break; case "Moutai": num = 0.48f; break; case "KyivCake": num = 0.18f; break; case "Hasbullah": num = 0.3f; break; case "Doshirak": num = 0.22f; break; case "Menorah": num = 0.68f; break; case "Shumovka": num = 0.38f; break; } if (val.HasProperty("_Smoothness")) { val.SetFloat("_Smoothness", num); } if (val.HasProperty("_Glossiness")) { val.SetFloat("_Glossiness", num); } if ((Object)(object)val3 != (Object)null) { if (val.HasProperty("_NormalMap")) { val.SetTexture("_NormalMap", (Texture)(object)val3); val.SetFloat("_NormalScale", 1f); val.EnableKeyword("_NORMALMAP_TANGENT_SPACE"); } if (val.HasProperty("_BumpMap")) { val.SetTexture("_BumpMap", (Texture)(object)val3); val.SetFloat("_BumpScale", 1f); val.EnableKeyword("_NORMALMAP"); } } if ((Object)(object)val4 != (Object)null && val.HasProperty("_MaskMap")) { val.SetTexture("_MaskMap", (Texture)(object)val4); } return val; } internal static AudioClip LoadWav(string fileName, float maxSeconds = 0f) { byte[] array = File.ReadAllBytes(Path.Combine(AssetRoot, "Audio", fileName)); int num = 12; short num2 = 0; short num3 = 0; int num4 = 0; short num5 = 0; int num6 = -1; int num7 = 0; if (Encoding.ASCII.GetString(array, 0, 4) != "RIFF" || Encoding.ASCII.GetString(array, 8, 4) != "WAVE") { throw new InvalidDataException(fileName + " is not a RIFF/WAVE file."); } while (num + 8 <= array.Length) { string text = Encoding.ASCII.GetString(array, num, 4); int num8 = BitConverter.ToInt32(array, num + 4); int num9 = num + 8; if (text == "fmt ") { num2 = BitConverter.ToInt16(array, num9); num3 = BitConverter.ToInt16(array, num9 + 2); num4 = BitConverter.ToInt32(array, num9 + 4); num5 = BitConverter.ToInt16(array, num9 + 14); } else if (text == "data") { num6 = num9; num7 = Math.Min(num8, array.Length - num9); break; } num = num9 + num8 + (num8 & 1); } if (num6 < 0 || num3 <= 0 || num4 <= 0) { throw new InvalidDataException("Missing WAV format/data chunk in " + fileName); } if (num2 != 1 || num5 != 16) { throw new NotSupportedException(fileName + ": only PCM 16-bit WAV is supported by this build."); } int num10 = num7 / 2 / num3; if (maxSeconds > 0f) { num10 = Math.Min(num10, Math.Max(1, Mathf.RoundToInt(maxSeconds * (float)num4))); } float[] array2 = new float[num10 * num3]; for (int i = 0; i < array2.Length; i++) { short num11 = BitConverter.ToInt16(array, num6 + i * 2); array2[i] = (float)num11 / 32768f; } AudioClip obj = AudioClip.Create(Path.GetFileNameWithoutExtension(fileName), num10, (int)num3, num4, false); obj.SetData(array2, 0); return obj; } } internal static class TooManyEmotesCompat { private static bool initialized; private static bool available; private static Type controllerType; private static Type managerType; private static PropertyInfo localControllerProperty; private static FieldInfo allEmotesDictionaryField; private static MethodInfo tryPerformEmoteMethod; private static FieldInfo emoteNameField; private static FieldInfo displayNameField; private static readonly HashSet missingEmoteWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); internal static void TryDance(string requestedEmoteName) { EnsureInitialized(); if (!available || string.IsNullOrWhiteSpace(requestedEmoteName)) { return; } try { object value = localControllerProperty.GetValue(null, null); if (value == null || !(allEmotesDictionaryField.GetValue(null) is IDictionary { Count: not 0 } dictionary)) { return; } object obj = FindNamedEmote(dictionary, requestedEmoteName); if (obj == null) { if (missingEmoteWarnings.Add(requestedEmoteName)) { Plugin.Log.LogWarning((object)("TooManyEmotes: requested emote '" + requestedEmoteName + "' was not found. No random fallback will be used; change the LoquatScrapPack emote name in config if desired.")); } return; } object obj2 = tryPerformEmoteMethod.Invoke(value, new object[3] { obj, -1, null }); if (obj2 is bool && !(bool)obj2) { Plugin.Log.LogWarning((object)("TooManyEmotes found '" + requestedEmoteName + "', but TryPerformingEmoteLocal returned false (player/emote conditions prevented the dance).")); } else { Plugin.Log.LogInfo((object)("TooManyEmotes triggered configured emote '" + requestedEmoteName + "'.")); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("TooManyEmotes named dance hook failed: " + ex.GetBaseException().Message)); } } private static object FindNamedEmote(IDictionary dictionary, string requestedName) { string text = Normalize(requestedName); foreach (DictionaryEntry item in dictionary) { if (item.Value != null && Normalize(Convert.ToString(item.Key)) == text) { return item.Value; } } foreach (DictionaryEntry item2 in dictionary) { object value = item2.Value; if (value != null) { string? value2 = ((emoteNameField == null) ? null : Convert.ToString(emoteNameField.GetValue(value))); string value3 = ((displayNameField == null) ? null : Convert.ToString(displayNameField.GetValue(value))); if (Normalize(value2) == text || Normalize(value3) == text) { return value; } } } return null; } private static string Normalize(string value) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } return new string((from c in value.Trim().ToLowerInvariant() select (c != '_' && c != '-') ? c : ' ' into c where !char.IsWhiteSpace(c) || c == ' ' select c).ToArray()).Replace(" ", " "); } private static void EnsureInitialized() { if (initialized) { return; } initialized = true; Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => string.Equals(a.GetName().Name, "TooManyEmotes", StringComparison.OrdinalIgnoreCase)); if (assembly == null) { return; } controllerType = assembly.GetType("TooManyEmotes.EmoteControllerPlayer", throwOnError: false); managerType = assembly.GetType("TooManyEmotes.EmotesManager", throwOnError: false); Type type = assembly.GetType("TooManyEmotes.UnlockableEmote", throwOnError: false); if (controllerType == null || managerType == null || type == null) { return; } localControllerProperty = controllerType.GetProperty("emoteControllerLocal", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); allEmotesDictionaryField = managerType.GetField("allUnlockableEmotesDict", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); emoteNameField = type.GetField("emoteName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); displayNameField = type.GetField("displayName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); tryPerformEmoteMethod = controllerType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo method) { if (method.Name != "TryPerformingEmoteLocal") { return false; } ParameterInfo[] parameters = method.GetParameters(); return parameters.Length == 3 && parameters[0].ParameterType.Name == "UnlockableEmote" && parameters[1].ParameterType == typeof(int); }); available = localControllerProperty != null && allEmotesDictionaryField != null && tryPerformEmoteMethod != null; Plugin.Log.LogInfo((object)(available ? "TooManyEmotes detected; LoquatScrapPack will request one configured named emote per music item (never a random emote)." : "TooManyEmotes assembly detected, but compatible API members were not found. Dance integration disabled.")); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }