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<Bird, Meal> Meals = new Dictionary<Bird, Meal>();
private static readonly Dictionary<Bird, float> FullUntil = new Dictionary<Bird, float>();
private static readonly List<Bird> Finished = new List<Bird>();
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<Bird, Meal> 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<PoopVisual>() ?? ((Component)item).gameObject.AddComponent<PoopVisual>()).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<PoopVisual>() == (Object)null)
{
((Component)__instance).gameObject.AddComponent<PoopVisual>();
}
}
[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<PoopVisual>();
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<bool> CfgEnabled;
internal static ConfigEntry<bool> CfgOnlyFish;
internal static ConfigEntry<float> CfgMinSeconds;
internal static ConfigEntry<float> CfgMaxSeconds;
internal static ConfigEntry<float> CfgCooldown;
internal static ConfigEntry<int> CfgMinWorth;
internal static ConfigEntry<int> CfgMaxWorth;
internal static ConfigEntry<bool> CfgClampBalance;
internal static ConfigEntry<string> CfgPoopName;
internal static ConfigEntry<bool> CfgReplaceModel;
internal static ConfigEntry<float> CfgPoopScale;
internal static ConfigEntry<string> CfgPoopColor;
internal static ConfigEntry<float> CfgPoopCookness;
internal static ConfigEntry<bool> CfgSound;
internal static ConfigEntry<int> CfgHungerCost;
internal static ConfigEntry<bool> CfgDamageOnEmptyStomach;
internal static ConfigEntry<bool> CfgPoison;
internal static ConfigEntry<bool> 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<bool>("General", "Enabled", true, "Master switch. Seagulls digest the food they steal.");
CfgOnlyFish = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "OnlyFish", false, "Only digest fish. When false, anything a seagull steals can be digested.");
CfgMinSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "MinSeconds", 8f, new ConfigDescription("Shortest time a seagull holds stolen food before eating it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 600f), Array.Empty<object>()));
CfgMaxSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "MaxSeconds", 25f, new ConfigDescription("Longest time a seagull holds stolen food before eating it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 600f), Array.Empty<object>()));
CfgCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("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<float>(0f, 100000f), Array.Empty<object>()));
CfgMinWorth = ((BaseUnityPlugin)this).Config.Bind<int>("Worth", "MinWorth", -60, new ConfigDescription("Low end of the random sell price. Negative costs you money.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-50000, 50000), Array.Empty<object>()));
CfgMaxWorth = ((BaseUnityPlugin)this).Config.Bind<int>("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<int>(-50000, 50000), Array.Empty<object>()));
CfgClampBalance = ((BaseUnityPlugin)this).Config.Bind<bool>("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<string>("Poop", "Name", "Seagull Poop", "Display name of the resulting item.");
CfgReplaceModel = ((BaseUnityPlugin)this).Config.Bind<bool>("Poop", "ReplaceModel", true, "Swap the item's model for a procedurally generated poop. Off = the original model, recoloured.");
CfgPoopScale = ((BaseUnityPlugin)this).Config.Bind<float>("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<float>(0.1f, 3f), Array.Empty<object>()));
CfgPoopColor = ((BaseUnityPlugin)this).Config.Bind<string>("Poop", "Colour", "4A2E17", "Poop colour as an RRGGBB hex string.");
CfgPoopCookness = ((BaseUnityPlugin)this).Config.Bind<float>("Poop", "Cookness", 0.85f, new ConfigDescription("Feeds the game's own cookness shader input, which darkens the surface.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
CfgSound = ((BaseUnityPlugin)this).Config.Bind<bool>("Poop", "PlaySound", true, "Play a seagull squawk at the moment of digestion.");
CfgHungerCost = ((BaseUnityPlugin)this).Config.Bind<int>("Eating", "HungerCost", 25, new ConfigDescription("Fullness a mouthful of poop costs. Paid out of your stomach first.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
CfgDamageOnEmptyStomach = ((BaseUnityPlugin)this).Config.Bind<bool>("Eating", "DamageOnEmptyStomach", true, "Whatever fullness you did not have to pay with is dealt as direct damage instead.");
CfgPoison = ((BaseUnityPlugin)this).Config.Bind<bool>("Eating", "Poison", true, "Apply the game's own poison, exactly like raw pufferfish. Happens regardless of fullness.");
CfgBlockOtherFoodEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("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<DigestionRunner>();
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<int, Mesh> Cache = new Dictionary<int, Mesh>();
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<Vector3> list = new List<Vector3>(976);
List<Vector2> list2 = new List<Vector2>(list.Capacity);
List<int> list3 = new List<int>(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<Renderer> _hidden = new List<Renderer>();
internal Mesh IconMesh { get; private set; }
private void Awake()
{
_item = ((Component)this).GetComponent<Item>();
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<Renderer>(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<Canvas>() != (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<MeshFilter>().sharedMesh = IconMesh;
((Renderer)val2.AddComponent<MeshRenderer>()).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<Item> _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<Item>;
}
_pool?.Remove(item);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not remove item from the seagull pool: " + ex.Message));
}
}
}
}