using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FishNet.Object; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.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 SeagullDigestion { internal class DigestionRunner : MonoBehaviour { private struct Meal { public Item Item; public float DueAt; } private static readonly Dictionary Meals = new Dictionary(); private static readonly Dictionary FullUntil = new Dictionary(); private static readonly List Finished = new List(); internal static bool IsFull(Bird bird) { if ((Object)(object)bird == (Object)null) { return false; } if (FullUntil.TryGetValue(bird, out var value)) { return Time.time < value; } return false; } internal static void Register(Bird bird, Item item) { if (!((Object)(object)bird == (Object)null) && !((Object)(object)item == (Object)null)) { float num = Mathf.Min(Plugin.CfgMinSeconds.Value, Plugin.CfgMaxSeconds.Value); float num2 = Mathf.Max(Plugin.CfgMinSeconds.Value, Plugin.CfgMaxSeconds.Value); float num3 = Random.Range(num, num2); Meals[bird] = new Meal { Item = item, DueAt = Time.time + num3 }; Plugin.Log.LogInfo((object)$"Seagull grabbed '{SafeName(item)}' - digesting in {num3:0.0}s"); } } internal static void Forget(Bird bird) { if ((Object)(object)bird != (Object)null) { Meals.Remove(bird); } } private void Update() { if (Meals.Count == 0) { return; } Finished.Clear(); float time = Time.time; foreach (KeyValuePair meal in Meals) { Bird key = meal.Key; Meal value = meal.Value; if ((Object)(object)key == (Object)null || (Object)(object)value.Item == (Object)null || (Object)(object)key.CaughtItem != (Object)(object)value.Item || ((Creature)key).IsDead || !((NetworkBehaviour)key).IsServerInitialized) { Finished.Add(key); } else if (!(time < value.DueAt)) { Finished.Add(key); try { Digest(key, value.Item); } catch (Exception ex) { Plugin.Log.LogError((object)("Digestion failed: " + ex)); } } } foreach (Bird item in Finished) { if ((Object)(object)item != (Object)null) { Meals.Remove(item); } } if (Meals.ContainsKey(null)) { Meals.Remove(null); } } private static void Digest(Bird bird, Item item) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)item).transform.position; int num = Mathf.Min(Plugin.CfgMinWorth.Value, Plugin.CfgMaxWorth.Value); int num2 = Mathf.Max(Plugin.CfgMinWorth.Value, Plugin.CfgMaxWorth.Value); int num3 = Random.Range(num, num2 + 1); item._bettingMultiplier.Value = PoopMarker.Encode(num3); (((Component)item).GetComponent() ?? ((Component)item).gameObject.AddComponent()).Apply(); item.ReleasedByBird(); float value = Plugin.CfgCooldown.Value; if (value > 0f) { FullUntil[bird] = Time.time + value; } if (Plugin.CfgSound.Value) { try { AudioManager.PlayRandomClipAt("Seagull_V", 1, 9, position, false, (AudioDistance)2, 0.5f, 0.1f); } catch { } } Plugin.Log.LogInfo((object)$"Seagull digested '{SafeName(item)}' -> {Plugin.CfgPoopName.Value} worth {num3}"); } private static string SafeName(Item item) { try { return item.GetName(); } catch { return ((Object)(object)item != (Object)null) ? ((Object)item).name : "null"; } } } internal static class Eating { internal static bool SwallowedPoop; private static int _fullnessBefore; [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyPatch(typeof(Server), "RpcLogic___FinishEatingCreature___1039939981")] private static void BeforeSwallow(Creature __0, Player __1) { SwallowedPoop = Plugin.CfgEnabled.Value && PoopMarker.IsPoop((Item)(object)__0) && (Object)(object)__1 != (Object)null; _fullnessBefore = (SwallowedPoop ? __1.Vitals.Fullness : 0); } [HarmonyPostfix] [HarmonyPatch(typeof(Server), "RpcLogic___FinishEatingCreature___1039939981")] private static void AfterSwallow(Player __1) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (!SwallowedPoop || (Object)(object)__1 == (Object)null) { return; } try { PlayerVitals vitals = __1.Vitals; if (!((Object)(object)vitals == (Object)null)) { int num = Mathf.Max(0, Plugin.CfgHungerCost.Value); int num2 = Mathf.Min(_fullnessBefore, num); int num3 = num - num2; int num4 = _fullnessBefore - num2; int num5 = num4 - vitals.Fullness; if (num5 != 0) { vitals.RestoreFullness(num5); } if (num3 > 0 && Plugin.CfgDamageOnEmptyStomach.Value) { vitals.TakeDamage(num3, default(Vector3), default(Vector3), false); } if (Plugin.CfgPoison.Value) { vitals.ApplyNewPoison(); } Plugin.Log.LogInfo((object)($"{SafeName(__1)} swallowed poop: fullness {_fullnessBefore} -> {num4}" + ((num3 > 0) ? $", {num3} damage" : "") + (Plugin.CfgPoison.Value ? ", poisoned" : ""))); } } catch (Exception ex) { Plugin.Log.LogError((object)("Poop swallow effects failed: " + ex)); } } private static string SafeName(Player p) { try { return p.SteamName; } catch { return "player"; } } } internal static class ForeignEffects { private const string EffectPatch = "FishEffects.Plugin+FinishEatingCreaturePatch"; private const string InspectPatch = "FishEffects.Plugin+UpdateInspectedItemTextPatch"; internal static void Apply(Harmony harmony) { if (Plugin.CfgBlockOtherFoodEffects.Value) { Hook(harmony, "FishEffects.Plugin+FinishEatingCreaturePatch", "Postfix", "SkipIfPoopWasSwallowed"); Hook(harmony, "FishEffects.Plugin+UpdateInspectedItemTextPatch", "Prefix", "SkipIfInspectingPoop"); } } private static void Hook(Harmony harmony, string typeName, string methodName, string ownPrefix) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown try { Type type = AccessTools.TypeByName(typeName); if (type == null) { Plugin.Log.LogInfo((object)(typeName + " not present - nothing to suppress.")); return; } MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null); if (methodInfo == null) { Plugin.Log.LogWarning((object)(typeName + "." + methodName + " not found; its layout changed. Poop may grant a food effect.")); return; } MethodInfo method = typeof(ForeignEffects).GetMethod(ownPrefix, BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)("Suppressing " + typeName + "." + methodName + " for poop.")); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not hook " + typeName + "." + methodName + ": " + ex.Message)); } } private static bool SkipIfPoopWasSwallowed() { return !Eating.SwallowedPoop; } private static bool SkipIfInspectingPoop(object __0) { return !PoopMarker.IsPoop((Item)((__0 is Item) ? __0 : null)); } } internal static class MoneyGuard { internal struct Pending { public bool Active; public long Before; public long Delta; } private static bool Ready(out MoneyManager manager) { manager = MoneyManager.Instance; if ((Object)(object)manager != (Object)null && ((NetworkBehaviour)manager).IsServerInitialized) { return manager._money != null; } return false; } private static Pending Capture(long delta) { if (!Plugin.CfgClampBalance.Value || !Ready(out var manager)) { return default(Pending); } return new Pending { Active = true, Before = manager._money.Value, Delta = delta }; } private static void Settle(Pending state) { if (state.Active && Ready(out var manager)) { long num = state.Before + state.Delta; int num2 = (int)((num >= 0) ? ((num > int.MaxValue) ? int.MaxValue : num) : 0); if (manager._money.Value != num2) { Plugin.Log.LogWarning((object)(string.Format("Balance ${0} {1} ${2} ", state.Before, (state.Delta < 0) ? "-" : "+", Math.Abs(state.Delta)) + $"= ${num}, outside the money range, and the game does not clamp. " + $"Held at ${num2} instead of letting it land on ${manager._money.Value}.")); manager._money.Value = num2; } } } [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyPatch(typeof(MoneyManager), "SellItem")] private static void SellItem_Pre(Item item, out Pending __state) { __state = (((Object)(object)item == (Object)null) ? default(Pending) : Capture(item.TotalWorth)); } [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyPatch(typeof(MoneyManager), "SellItem")] private static void SellItem_Post(Pending __state) { Settle(__state); } [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyPatch(typeof(MoneyManager), "AddMoney")] private static void AddMoney_Pre(int amount, out Pending __state) { __state = Capture(Math.Abs((long)amount)); } [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyPatch(typeof(MoneyManager), "AddMoney")] private static void AddMoney_Post(Pending __state) { Settle(__state); } } internal static class Patches { [HarmonyPostfix] [HarmonyPatch(typeof(Bird), "SetCaughtFood")] private static void Bird_SetCaughtFood(Bird __instance) { if (Plugin.CfgEnabled.Value && !((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsServerInitialized) { Item caughtItem = __instance.CaughtItem; if (!((Object)(object)caughtItem == (Object)null) && !PoopMarker.IsPoop(caughtItem) && (!Plugin.CfgOnlyFish.Value || !((Object)(object)caughtItem.Fish == (Object)null))) { DigestionRunner.Register(__instance, caughtItem); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Bird), "RemoveFood")] private static void Bird_RemoveFood(Bird __instance) { DigestionRunner.Forget(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(Bird), "SetAttackingFood")] private static void Bird_SetAttackingFood(Bird __instance, ref Item item) { if (!((Object)(object)item == (Object)null) && (PoopMarker.IsPoop(item) || DigestionRunner.IsFull(__instance))) { item = null; } } [HarmonyPostfix] [HarmonyPatch(typeof(Item), "OnStartClient")] private static void Item_OnStartClient(Item __instance) { if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } [HarmonyPostfix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static void Item_TotalWorth(Item __instance, ref int __result) { if (PoopMarker.IsPoop(__instance)) { __result = PoopMarker.WorthOf(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(Item), "GetName")] private static void Item_GetName(Item __instance, ref string __result) { if (PoopMarker.IsPoop(__instance)) { __result = Plugin.CfgPoopName.Value; } } [HarmonyPostfix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static void Item_Mesh(Item __instance, ref Mesh __result) { UsePoopMesh(__instance, ref __result); } [HarmonyPostfix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static void Creature_Mesh(Creature __instance, ref Mesh __result) { UsePoopMesh((Item)(object)__instance, ref __result); } [HarmonyPostfix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static void Creature_DripMesh(Creature __instance, ref Mesh __result) { UsePoopMesh((Item)(object)__instance, ref __result); } private static void UsePoopMesh(Item item, ref Mesh result) { if (Plugin.CfgReplaceModel.Value && PoopMarker.IsPoop(item)) { PoopVisual component = ((Component)item).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.IconMesh != (Object)null) { result = component.IconMesh; } } } [HarmonyPrefix] [HarmonyPatch(typeof(Item), "AddBetMultiplier")] private static bool Item_AddBetMultiplier(Item __instance) { return !PoopMarker.IsPoop(__instance); } } [BepInPlugin("erwins.seagulldigestion", "Seagull Digestion", "1.5.2")] public class Plugin : BaseUnityPlugin { public const string Guid = "erwins.seagulldigestion"; internal static ManualLogSource Log; internal static ConfigEntry CfgEnabled; internal static ConfigEntry CfgOnlyFish; internal static ConfigEntry CfgMinSeconds; internal static ConfigEntry CfgMaxSeconds; internal static ConfigEntry CfgCooldown; internal static ConfigEntry CfgMinWorth; internal static ConfigEntry CfgMaxWorth; internal static ConfigEntry CfgClampBalance; internal static ConfigEntry CfgPoopName; internal static ConfigEntry CfgReplaceModel; internal static ConfigEntry CfgPoopScale; internal static ConfigEntry CfgPoopColor; internal static ConfigEntry CfgPoopCookness; internal static ConfigEntry CfgSound; internal static ConfigEntry CfgHungerCost; internal static ConfigEntry CfgDamageOnEmptyStomach; internal static ConfigEntry CfgPoison; internal static ConfigEntry CfgBlockOtherFoodEffects; private Harmony _harmony; private void Awake() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Expected O, but got Unknown //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Expected O, but got Unknown //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Expected O, but got Unknown //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; CfgEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Master switch. Seagulls digest the food they steal."); CfgOnlyFish = ((BaseUnityPlugin)this).Config.Bind("General", "OnlyFish", false, "Only digest fish. When false, anything a seagull steals can be digested."); CfgMinSeconds = ((BaseUnityPlugin)this).Config.Bind("Timing", "MinSeconds", 8f, new ConfigDescription("Shortest time a seagull holds stolen food before eating it.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 600f), Array.Empty())); CfgMaxSeconds = ((BaseUnityPlugin)this).Config.Bind("Timing", "MaxSeconds", 25f, new ConfigDescription("Longest time a seagull holds stolen food before eating it.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 600f), Array.Empty())); CfgCooldown = ((BaseUnityPlugin)this).Config.Bind("Timing", "CooldownAfterEating", 30f, new ConfigDescription("Seconds a seagull refuses to hunt after a meal. 0 disables the cooldown; a huge value means it never steals again.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100000f), Array.Empty())); CfgMinWorth = ((BaseUnityPlugin)this).Config.Bind("Worth", "MinWorth", -60, new ConfigDescription("Low end of the random sell price. Negative costs you money.", (AcceptableValueBase)(object)new AcceptableValueRange(-50000, 50000), Array.Empty())); CfgMaxWorth = ((BaseUnityPlugin)this).Config.Bind("Worth", "MaxWorth", 20, new ConfigDescription("High end of the random sell price. Set both to the same number for a fixed price.", (AcceptableValueBase)(object)new AcceptableValueRange(-50000, 50000), Array.Empty())); CfgClampBalance = ((BaseUnityPlugin)this).Config.Bind("Worth", "ClampBalance", true, "Keep the balance between $0 and the $2,147,483,647 limit. Leave this on: a negative balance makes How To Fish - Extended reset you to the limit, and the next sale then overflows to -$2,147,483,648."); CfgPoopName = ((BaseUnityPlugin)this).Config.Bind("Poop", "Name", "Seagull Poop", "Display name of the resulting item."); CfgReplaceModel = ((BaseUnityPlugin)this).Config.Bind("Poop", "ReplaceModel", true, "Swap the item's model for a procedurally generated poop. Off = the original model, recoloured."); CfgPoopScale = ((BaseUnityPlugin)this).Config.Bind("Poop", "Scale", 1f, new ConfigDescription("Size multiplier. The poop is sized from the item it replaced, so 1 keeps it in proportion to that fish. Capped so it cannot fill the screen when held.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 3f), Array.Empty())); CfgPoopColor = ((BaseUnityPlugin)this).Config.Bind("Poop", "Colour", "4A2E17", "Poop colour as an RRGGBB hex string."); CfgPoopCookness = ((BaseUnityPlugin)this).Config.Bind("Poop", "Cookness", 0.85f, new ConfigDescription("Feeds the game's own cookness shader input, which darkens the surface.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); CfgSound = ((BaseUnityPlugin)this).Config.Bind("Poop", "PlaySound", true, "Play a seagull squawk at the moment of digestion."); CfgHungerCost = ((BaseUnityPlugin)this).Config.Bind("Eating", "HungerCost", 25, new ConfigDescription("Fullness a mouthful of poop costs. Paid out of your stomach first.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); CfgDamageOnEmptyStomach = ((BaseUnityPlugin)this).Config.Bind("Eating", "DamageOnEmptyStomach", true, "Whatever fullness you did not have to pay with is dealt as direct damage instead."); CfgPoison = ((BaseUnityPlugin)this).Config.Bind("Eating", "Poison", true, "Apply the game's own poison, exactly like raw pufferfish. Happens regardless of fullness."); CfgBlockOtherFoodEffects = ((BaseUnityPlugin)this).Config.Bind("Eating", "BlockOtherFoodEffects", true, "Stop other food-effect mods (Fish Effects) from granting poop a positive effect."); _harmony = new Harmony("erwins.seagulldigestion"); _harmony.PatchAll(typeof(Patches)); _harmony.PatchAll(typeof(Eating)); _harmony.PatchAll(typeof(MoneyGuard)); ForeignEffects.Apply(_harmony); ((Component)this).gameObject.AddComponent(); Log.LogInfo((object)"Seagull Digestion loaded. Seagulls now finish what they start."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class PoopMarker { private const float Base = 100000f; private const float Threshold = -1000f; internal const int MinWorth = -50000; internal const int MaxWorth = 50000; internal static float Encode(int worth) { return 0f - (100000f + (float)Mathf.Clamp(worth, -50000, 50000)); } internal static bool IsPoop(Item item) { if ((Object)(object)item == (Object)null) { return false; } try { return item._bettingMultiplier != null && item._bettingMultiplier.Value < -1000f; } catch { return false; } } internal static int WorthOf(Item item) { try { return Mathf.RoundToInt(0f - item._bettingMultiplier.Value - 100000f); } catch { return 0; } } } internal static class PoopMesh { internal const float UnitHeight = 1.2f; private static readonly Dictionary Cache = new Dictionary(); internal static Mesh Get(float scale) { scale = Mathf.Clamp(scale, 0.005f, 5f); int num = Mathf.RoundToInt(scale * 1000f); if (Cache.TryGetValue(num, out var value) && (Object)(object)value != (Object)null) { return value; } Mesh val = Build((float)num / 1000f); Cache[num] = val; return val; } private static Mesh Build(float scale) { //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_0050: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_008f: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00c8: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: 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_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: 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_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Expected O, but got Unknown List list = new List(976); List list2 = new List(list.Capacity); List list3 = new List(5418); for (int i = 0; i <= 64; i++) { float num = (float)i / 64f; Vector3 val = PathAt(num); Vector3 val2 = PathAt(Mathf.Min(1f, num + 0.008f)) - PathAt(Mathf.Max(0f, num - 0.008f)); Vector3 val3 = ((Vector3)(ref val2)).normalized; if (((Vector3)(ref val3)).sqrMagnitude < 1E-06f) { val3 = Vector3.up; } Vector3 val4 = Vector3.Cross(val3, Vector3.up); if (((Vector3)(ref val4)).sqrMagnitude < 1E-06f) { val4 = Vector3.right; } ((Vector3)(ref val4)).Normalize(); val2 = Vector3.Cross(val4, val3); Vector3 normalized = ((Vector3)(ref val2)).normalized; float num2 = 0.2f * Mathf.Pow(1f - num, 0.5f); for (int j = 0; j <= 14; j++) { float num3 = (float)j / 14f * MathF.PI * 2f; Vector3 val5 = val4 * Mathf.Cos(num3) + normalized * Mathf.Sin(num3); list.Add((val + new Vector3(val5.x * num2, val5.y * num2 * 0.85f, val5.z * num2)) * scale); list2.Add(new Vector2((float)j / 14f, num)); } } int num4 = 15; for (int k = 0; k < 64; k++) { for (int l = 0; l < 14; l++) { int num5 = k * num4 + l; int item = num5 + 1; int num6 = num5 + num4; int item2 = num6 + 1; list3.Add(num5); list3.Add(num6); list3.Add(item); list3.Add(item); list3.Add(num6); list3.Add(item2); } } int count = list.Count; list.Add(PathAt(0f) * scale); list2.Add(new Vector2(0.5f, 0f)); for (int m = 0; m < 14; m++) { list3.Add(count); list3.Add(m); list3.Add(m + 1); } Mesh val6 = new Mesh { name = "SeagullPoop" }; val6.SetVertices(list); val6.SetUVs(0, list2); val6.SetTriangles(list3, 0); val6.RecalculateNormals(); val6.RecalculateBounds(); return val6; static Vector3 PathAt(float t) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) float num7 = t * 3f * MathF.PI * 2f; float num8 = 0.38f * (1f - t * 0.85f); return new Vector3(Mathf.Cos(num7) * num8, 1.2f * t, Mathf.Sin(num7) * num8); } } } internal class PoopVisual : MonoBehaviour { private static readonly int[] ColorIds = new int[2] { Shader.PropertyToID("_BaseColor"), Shader.PropertyToID("_Color") }; private static readonly int[] AlbedoMapIds = new int[2] { Shader.PropertyToID("_BaseMap"), Shader.PropertyToID("_MainTex") }; private static readonly int CooknessId = Shader.PropertyToID("_Cookness"); private static readonly int UseSkinId = Shader.PropertyToID("_Use_Skin"); private static readonly int RainbowSkinId = Shader.PropertyToID("_Rainbow_Skin"); private static Texture2D _flat; private static Color _flatColor; private const float FallbackLongestSide = 0.5f; private const float MinPoopHeight = 0.04f; private const float MaxPoopHeight = 0.6f; private Item _item; private bool _applied; private bool _subscribed; private readonly List _hidden = new List(); internal Mesh IconMesh { get; private set; } private void Awake() { _item = ((Component)this).GetComponent(); if ((Object)(object)_item == (Object)null) { ((Behaviour)this).enabled = false; return; } try { if (_item._bettingMultiplier != null) { _item._bettingMultiplier.OnChange += OnMultiplierChanged; _subscribed = true; if (PoopMarker.IsPoop(_item)) { Apply(); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("PoopVisual subscribe failed: " + ex.Message)); } } private void OnDestroy() { if (!_subscribed || (Object)(object)_item == (Object)null) { return; } try { _item._bettingMultiplier.OnChange -= OnMultiplierChanged; } catch { } } private void OnMultiplierChanged(float prev, float next, bool asServer) { if (next < -1000f) { Apply(); } } internal void Apply() { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) if (_applied) { return; } _applied = true; BirdFood.Forget(_item); try { Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && val.enabled && !(val is ParticleSystemRenderer) && !(val is TrailRenderer) && !(val is LineRenderer) && !((Object)(object)((Component)val).GetComponentInParent() != (Object)null)) { _hidden.Add(val); } } if (!Plugin.CfgReplaceModel.Value) { Recolour(); return; } MeasureOriginal(out var localCentre, out var longestSide); foreach (Renderer item in _hidden) { item.enabled = false; } IconMesh = PoopMesh.Get(FitScale(longestSide)); GameObject val2 = new GameObject("SeagullPoopModel"); val2.transform.SetParent(((Component)this).transform, false); val2.transform.localPosition = localCentre; val2.layer = ((Component)this).gameObject.layer; val2.AddComponent().sharedMesh = IconMesh; ((Renderer)val2.AddComponent()).sharedMaterial = MakeMaterial(); } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to apply poop visuals: " + ex)); } } internal static Color PoopColor() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) string text = (Plugin.CfgPoopColor.Value ?? "").Trim().TrimStart('#'); Color result = default(Color); if (ColorUtility.TryParseHtmlString("#" + text, ref result)) { return result; } return new Color(0.29f, 0.18f, 0.09f); } private static Texture2D FlatTexture(Color c) { //IL_0024: 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_0039: Expected O, but got Unknown //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_flat != (Object)null && _flatColor == c) { return _flat; } _flat = new Texture2D(4, 4, (TextureFormat)4, false) { name = "SeagullPoopTex" }; Color[] array = (Color[])(object)new Color[16]; for (int i = 0; i < array.Length; i++) { array[i] = c; } _flat.SetPixels(array); _flat.Apply(); _flatColor = c; return _flat; } private Material MakeMaterial() { //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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) Color color = PoopColor(); Material val = null; foreach (Renderer item in _hidden) { if ((Object)(object)item != (Object)null && (Object)(object)item.sharedMaterial != (Object)null) { val = item.sharedMaterial; break; } } Material val2; if ((Object)(object)val != (Object)null) { val2 = new Material(val); Plugin.Log.LogInfo((object)("Poop material cloned from shader: " + ((Object)val.shader).name)); } else { Shader val3 = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"); val2 = new Material(val3); Plugin.Log.LogWarning((object)("No source material on item; fell back to " + (((Object)(object)val3 != (Object)null) ? ((Object)val3).name : "none"))); } ((Object)val2).name = "SeagullPoopMat"; Paint(val2, color); return val2; } private static void Paint(Material mat, Color color) { //IL_0000: 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) Texture2D val = FlatTexture(color); int[] albedoMapIds = AlbedoMapIds; foreach (int num in albedoMapIds) { if (mat.HasProperty(num)) { mat.SetTexture(num, (Texture)(object)val); } } albedoMapIds = ColorIds; foreach (int num2 in albedoMapIds) { if (mat.HasProperty(num2)) { mat.SetColor(num2, color); } } if (mat.HasProperty(UseSkinId)) { mat.SetFloat(UseSkinId, 0f); } if (mat.HasProperty(RainbowSkinId)) { mat.SetFloat(RainbowSkinId, 0f); } if (mat.HasProperty(CooknessId)) { mat.SetFloat(CooknessId, Plugin.CfgPoopCookness.Value); } } private void MeasureOriginal(out Vector3 localCentre, out float longestSide) { //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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: 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_0119: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) localCentre = Vector3.zero; longestSide = 0.5f; Bounds? val = null; foreach (Renderer item in _hidden) { if (!((Object)(object)item == (Object)null)) { if (val.HasValue) { Bounds value = val.Value; ((Bounds)(ref value)).Encapsulate(item.bounds); val = value; } else { val = item.bounds; } } } if (val.HasValue) { Bounds value2 = val.Value; localCentre = ((Component)this).transform.InverseTransformPoint(((Bounds)(ref value2)).center); Vector3 lossyScale = ((Component)this).transform.lossyScale; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(((Bounds)(ref value2)).size.x / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.x)), ((Bounds)(ref value2)).size.y / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.y)), ((Bounds)(ref value2)).size.z / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.z))); float num = Mathf.Max(val2.x, Mathf.Max(val2.y, val2.z)); if (num > 0.0001f && !float.IsNaN(num) && !float.IsInfinity(num)) { longestSide = num; } } } private static float FitScale(float longestSide) { return Mathf.Clamp(longestSide * 0.5f * Mathf.Max(0.01f, Plugin.CfgPoopScale.Value), 0.04f, 0.6f) / 1.2f; } private void Recolour() { //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_0041: Unknown result type (might be due to invalid IL or missing references) Color color = PoopColor(); foreach (Renderer item in _hidden) { if ((Object)(object)item == (Object)null) { continue; } Material[] materials = item.materials; for (int i = 0; i < materials.Length; i++) { if ((Object)(object)materials[i] != (Object)null) { Paint(materials[i], color); } } item.materials = materials; } } } internal static class BirdFood { private static HashSet _pool; private static bool _looked; internal static void Forget(Item item) { if ((Object)(object)item == (Object)null) { return; } try { if (!_looked) { _looked = true; _pool = AccessTools.Field(typeof(ItemManager), "_itemsForBirds")?.GetValue(null) as HashSet; } _pool?.Remove(item); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not remove item from the seagull pool: " + ex.Message)); } } } }