Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TuckMyChooksIn v1.1.1
plugins/TuckMyChooksIn.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; 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: AssemblyCompany("TuckMyChooksIn")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+52e01f41167f74e9be2c5be814fc0ad6e10c7558")] [assembly: AssemblyProduct("TuckMyChooksIn")] [assembly: AssemblyTitle("TuckMyChooksIn")] [assembly: AssemblyVersion("1.0.0.0")] namespace TuckMyChooksIn; public class ChickenBed : MonoBehaviour, Hoverable, Interactable { private struct HuddleInfo { public Character hen; public MonsterAI ai; } public static readonly List<ChickenBed> AllBeds = new List<ChickenBed>(); public Transform m_spawnPoint; private ZNetView m_nview; private Coroutine m_tuckCoroutine; private float m_originalWalkSpeed; public static int s_pendingTucks = 0; private static readonly List<HuddleInfo> s_huddlers = new List<HuddleInfo>(); public static float s_sleepBlockStart = 0f; public MonsterAI OccupantAI { get; set; } public Character Occupant { get; set; } public bool IsOccupied { get { if ((Object)(object)Occupant != (Object)null) { return (Object)(object)OccupantAI != (Object)null; } return false; } } internal static void AddHuddler(Character hen, MonsterAI ai, ChickenBed nearestBed) { s_huddlers.Add(new HuddleInfo { hen = hen, ai = ai }); ai.SetFollowTarget(((Component)nearestBed).gameObject); ((MonoBehaviour)nearestBed).StartCoroutine(nearestBed.HuddleAndSleep(hen, ai)); } private IEnumerator HuddleAndSleep(Character hen, MonsterAI ai) { float timeout = 20f; float elapsed = 0f; while (elapsed < timeout) { if ((Object)(object)hen == (Object)null || (Object)(object)ai == (Object)null) { yield break; } if (Vector3.Distance(((Component)hen).transform.position, ((Component)this).transform.position) <= 3f) { break; } elapsed += Time.deltaTime; yield return null; } if ((Object)(object)hen == (Object)null || (Object)(object)ai == (Object)null) { yield break; } ZNetView component = ((Component)hen).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { Animator componentInChildren = ((Component)hen).GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.SetBool("sleeping", true); } component.GetZDO().Set(ZDOVars.s_sleeping, true); } Plugin.Log.LogInfo((object)"Huddler settled near bed."); } private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)m_spawnPoint == (Object)null) { m_spawnPoint = ((Component)this).transform; } AllBeds.Add(this); } private void OnDestroy() { AllBeds.Remove(this); } public Vector3 GetSleepPoint() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return m_spawnPoint.position; } public string GetHoverText() { if (IsOccupied) { return Occupant.GetHoverName() + " is tucked in <3"; } return "Chicken Bed (vacant)"; } public string GetHoverName() { return "Chicken Bed"; } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold) { return false; } if (IsOccupied) { ((Character)user).Message((MessageType)2, "A chook is sleeping here!", 0, (Sprite)null); } else { ((Character)user).Message((MessageType)2, "This chicken bed is vacant.", 0, (Sprite)null); } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } public void TuckIn(Character hen, MonsterAI ai) { Occupant = hen; OccupantAI = ai; if (!((Object)(object)hen == (Object)null) && !((Object)(object)ai == (Object)null)) { if (s_pendingTucks == 0) { s_sleepBlockStart = Time.time; } s_pendingTucks++; m_tuckCoroutine = ((MonoBehaviour)this).StartCoroutine(WaitAndSleep(hen, ai)); } } private IEnumerator WaitAndSleep(Character hen, MonsterAI ai) { m_originalWalkSpeed = hen.m_walkSpeed; hen.m_walkSpeed = hen.m_runSpeed * 2f; ai.SetFollowTarget(((Component)this).gameObject); float timeout = 20f; float elapsed = 0f; while (elapsed < timeout) { if ((Object)(object)hen == (Object)null || (Object)(object)ai == (Object)null) { yield break; } if (Vector3.Distance(((Component)hen).transform.position, ((Component)this).transform.position) <= 3f) { break; } elapsed += Time.deltaTime; yield return null; } if ((Object)(object)hen == (Object)null || (Object)(object)ai == (Object)null) { yield break; } hen.m_walkSpeed = m_originalWalkSpeed; ai.SetFollowTarget(((Component)this).gameObject); ((Component)hen).transform.position = GetSleepPoint(); ((Component)hen).transform.rotation = m_spawnPoint.rotation; ZNetView component = ((Component)hen).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { Animator componentInChildren = ((Component)hen).GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.SetBool("sleeping", true); } component.GetZDO().Set(ZDOVars.s_sleeping, true); } Plugin.Log.LogInfo((object)$"Chook tucked in at {GetSleepPoint()}!"); s_pendingTucks = Mathf.Max(0, s_pendingTucks - 1); m_tuckCoroutine = null; } public void WakeUp() { if (m_tuckCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(m_tuckCoroutine); m_tuckCoroutine = null; s_pendingTucks = Mathf.Max(0, s_pendingTucks - 1); if ((Object)(object)Occupant != (Object)null) { Occupant.m_walkSpeed = m_originalWalkSpeed; } } if ((Object)(object)Occupant != (Object)null && (Object)(object)OccupantAI != (Object)null) { OccupantAI.SetFollowTarget((GameObject)null); ZNetView component = ((Component)Occupant).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { Animator componentInChildren = ((Component)Occupant).GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.SetBool("sleeping", false); } component.GetZDO().Set(ZDOVars.s_sleeping, false); } Plugin.Log.LogInfo((object)"Chook woke up!"); } Vacate(); } public void Vacate() { Occupant = null; OccupantAI = null; } public static List<ChickenBed> GetVacantBeds() { List<ChickenBed> list = new List<ChickenBed>(); foreach (ChickenBed allBed in AllBeds) { if ((Object)(object)allBed != (Object)null && !allBed.IsOccupied) { list.Add(allBed); } } return list; } public static void WakeAllChickens() { if (s_huddlers.Count <= 0 && !AllBeds.Exists((ChickenBed b) => (Object)(object)b != (Object)null && b.IsOccupied)) { return; } foreach (ChickenBed allBed in AllBeds) { if ((Object)(object)allBed != (Object)null && allBed.IsOccupied) { allBed.WakeUp(); } } foreach (HuddleInfo s_huddler in s_huddlers) { if ((Object)(object)s_huddler.hen == (Object)null || (Object)(object)s_huddler.ai == (Object)null) { continue; } s_huddler.ai.SetFollowTarget((GameObject)null); ZNetView component = ((Component)s_huddler.hen).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { Animator componentInChildren = ((Component)s_huddler.hen).GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.SetBool("sleeping", false); } component.GetZDO().Set(ZDOVars.s_sleeping, false); } } s_huddlers.Clear(); } } [HarmonyPatch(typeof(Player), "AttachStart")] public static class PlayerAttachStartPatch { private struct HenInfo { public Character character; public MonsterAI ai; } private static readonly HashSet<string> HenPrefabs = new HashSet<string> { "Hen", "Chicken", "hen", "chicken" }; private static void Postfix(Player __instance, bool isBed) { if (isBed && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { Plugin.Log.LogInfo((object)"Player got into bed — time to tuck some chooks in!"); TuckChickensIn(); } } private static void TuckChickensIn() { //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) int num = ZNet.instance.GetNrOfPlayers(); if (num < 1) { num = 1; } List<HenInfo> list = FindTamedHens(); if (list.Count == 0) { Plugin.Log.LogInfo((object)"No tamed chooks found nearby."); return; } int num2 = Mathf.Max(1, Mathf.CeilToInt((float)list.Count / (float)num)); int num3 = CountPlayersInBed(); int num4 = Mathf.Min(list.Count, num2 * num3); int num5 = ChickenBed.AllBeds.Count((ChickenBed b) => (Object)(object)b != (Object)null && b.IsOccupied); int num6 = num4 - num5; if (num6 <= 0) { Plugin.Log.LogInfo((object)$"Already enough chooks tucked in ({num5}/{num4})."); return; } List<ChickenBed> vacantBeds = ChickenBed.GetVacantBeds(); if (vacantBeds.Count == 0) { Plugin.Log.LogInfo((object)"No vacant chicken beds available!"); return; } HashSet<Character> tuckedHens = new HashSet<Character>(); foreach (ChickenBed allBed in ChickenBed.AllBeds) { if ((Object)(object)allBed != (Object)null && (Object)(object)allBed.Occupant != (Object)null) { tuckedHens.Add(allBed.Occupant); } } List<HenInfo> list2 = list.Where((HenInfo h) => !tuckedHens.Contains(h.character)).ToList(); int num7 = 0; for (int i = 0; i < num6 && i < vacantBeds.Count && i < list2.Count; i++) { HenInfo henInfo = list2[i]; ChickenBed chickenBed = FindClosestBed(((Component)henInfo.character).transform.position, vacantBeds); if ((Object)(object)chickenBed == (Object)null) { break; } vacantBeds.Remove(chickenBed); chickenBed.TuckIn(henInfo.character, henInfo.ai); num7++; } Plugin.Log.LogInfo((object)$"Tucked {num7} chooks into bed! (total: {num5 + num7}/{list.Count})"); List<ChickenBed> list3 = ChickenBed.AllBeds.FindAll((ChickenBed b) => (Object)(object)b != (Object)null); if (list3.Count <= 0) { return; } int num8 = 0; for (int j = num7; j < list2.Count; j++) { HenInfo henInfo2 = list2[j]; ChickenBed chickenBed2 = FindClosestBed(((Component)henInfo2.character).transform.position, list3); if (!((Object)(object)chickenBed2 == (Object)null)) { ChickenBed.AddHuddler(henInfo2.character, henInfo2.ai, chickenBed2); num8++; } } if (num8 > 0) { Plugin.Log.LogInfo((object)$"Sent {num8} bedless chooks to huddle near the nearest bed."); } } private static List<HenInfo> FindTamedHens() { List<HenInfo> list = new List<HenInfo>(); foreach (Character allCharacter in Character.GetAllCharacters()) { if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.IsPlayer() && allCharacter.IsTamed() && IsHenPrefab(((Object)((Component)allCharacter).gameObject).name)) { MonsterAI component = ((Component)allCharacter).GetComponent<MonsterAI>(); if (!((Object)(object)component == (Object)null)) { list.Add(new HenInfo { character = allCharacter, ai = component }); } } } return list; } private static bool IsHenPrefab(string name) { string text = name.ToLowerInvariant(); if (!text.Contains("hen")) { return text.Contains("chicken"); } return true; } private static int CountPlayersInBed() { int num = 0; foreach (ZDO allCharacterZDO in ZNet.instance.GetAllCharacterZDOS()) { if (allCharacterZDO.GetBool(ZDOVars.s_inBed, false)) { num++; } } return num; } private static ChickenBed FindClosestBed(Vector3 pos, List<ChickenBed> beds) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) ChickenBed result = null; float num = float.MaxValue; foreach (ChickenBed bed in beds) { if (!((Object)(object)bed == (Object)null)) { float num2 = Vector3.Distance(pos, bed.GetSleepPoint()); if (num2 < num) { num = num2; result = bed; } } } return result; } } [HarmonyPatch(typeof(Game), "EverybodyIsTryingToSleep")] public static class GameEverybodyIsTryingSleepPatch { private static bool Prepare() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 return (int)SystemInfo.graphicsDeviceType != 4; } private static void Postfix(ref bool __result) { if (__result && ChickenBed.s_pendingTucks > 0) { if (Time.time - ChickenBed.s_sleepBlockStart < 20f) { __result = false; } else { ChickenBed.s_pendingTucks = 0; } } } } [HarmonyPatch(typeof(Game), "SleepStop")] public static class GameSleepStopPatch { private static bool Prepare() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 return (int)SystemInfo.graphicsDeviceType != 4; } private static void Postfix() { Plugin.Log.LogInfo((object)"Morning! Waking up the chooks."); ChickenBed.WakeAllChickens(); } } [HarmonyPatch(typeof(Player), "AttachStop")] public static class PlayerAttachStopPatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { Plugin.Log.LogInfo((object)"Player got out of bed — waking chooks."); ChickenBed.WakeAllChickens(); } } } [BepInPlugin("tuckmychooksin", "TuckMyChooksIn", "1.1.1")] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "tuckmychooksin"; public const string PluginName = "TuckMyChooksIn"; public const string PluginVersion = "1.1.1"; internal static ManualLogSource Log; internal static Plugin Instance; private Harmony _harmony; private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Instance = this; _harmony = new Harmony("tuckmychooksin"); _harmony.PatchAll(); Log.LogInfo((object)"TuckMyChooksIn v1.1.1 loaded. Time to tuck those chooks in!"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(ZNetScene), "OnDestroy")] public static class ZNetSceneDestroyPatch { private static void Prefix(ZNetScene __instance) { if ((Object)(object)PrefabSetup.s_prefabTemplate != (Object)null) { __instance.m_prefabs.Remove(PrefabSetup.s_prefabTemplate); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class PrefabSetup { private const string ChickenBedName = "piece_chickenbed"; private const float BedScale = 0.35f; internal static GameObject s_prefabTemplate; private static void Postfix(ZNetScene __instance) { CreateChickenBedPrefab(__instance); } private static void CreateChickenBedPrefab(ZNetScene zns) { //IL_00de: 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_0153: 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_0186: 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_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown if ((Object)(object)zns.GetPrefab("piece_chickenbed") != (Object)null) { return; } if ((Object)(object)s_prefabTemplate != (Object)null) { zns.m_prefabs.Add(s_prefabTemplate); Dictionary<int, GameObject> value = Traverse.Create((object)zns).Field("m_namedPrefabs").GetValue<Dictionary<int, GameObject>>(); if (value != null) { value[StringExtensionMethods.GetStableHashCode("piece_chickenbed")] = s_prefabTemplate; } Plugin.Log.LogInfo((object)"Chicken bed re-registered with new ZNetScene."); return; } GameObject val = FindBedPrefab(zns); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"Could not find a bed prefab to clone for the chicken bed!"); return; } Plugin.Log.LogInfo((object)("Cloning bed prefab '" + ((Object)val).name + "' for chicken bed.")); bool activeSelf = val.activeSelf; val.SetActive(false); GameObject val2 = Object.Instantiate<GameObject>(val); val.SetActive(activeSelf); ((Object)val2).name = "piece_chickenbed"; val2.transform.localScale = Vector3.one * 0.35f; Bed component = val2.GetComponent<Bed>(); if ((Object)(object)component != (Object)null) { Transform spawnPoint = component.m_spawnPoint; Object.DestroyImmediate((Object)(object)component); val2.AddComponent<ChickenBed>().m_spawnPoint = spawnPoint; } else { val2.AddComponent<ChickenBed>(); } Piece component2 = val2.GetComponent<Piece>(); if ((Object)(object)component2 != (Object)null) { component2.m_name = "$piece_chickenbed"; component2.m_description = "$piece_chickenbed_desc"; component2.m_category = (PieceCategory)4; GameObject prefab = zns.GetPrefab("Wood"); component2.m_resources = (Requirement[])(object)((!((Object)(object)prefab != (Object)null)) ? new Requirement[0] : new Requirement[1] { new Requirement { m_resItem = prefab.GetComponent<ItemDrop>(), m_amount = 1, m_recover = true } }); } val2.SetActive(true); ZNetView component3 = val2.GetComponent<ZNetView>(); if ((Object)(object)component3 != (Object)null) { ZDO zDO = component3.GetZDO(); if (zDO != null) { component3.ResetZDO(); Traverse.Create((object)zns).Field("m_instances").GetValue<Dictionary<ZDO, ZNetView>>()?.Remove(zDO); ZDOMan.instance.DestroyZDO(zDO); Plugin.Log.LogInfo((object)"Cleaned up spurious ZDO from chicken bed template."); } } ChickenBed component4 = val2.GetComponent<ChickenBed>(); if ((Object)(object)component4 != (Object)null) { ChickenBed.AllBeds.Remove(component4); } zns.m_prefabs.Add(val2); Dictionary<int, GameObject> value2 = Traverse.Create((object)zns).Field("m_namedPrefabs").GetValue<Dictionary<int, GameObject>>(); if (value2 != null) { value2[StringExtensionMethods.GetStableHashCode("piece_chickenbed")] = val2; } Object.DontDestroyOnLoad((Object)(object)val2); s_prefabTemplate = val2; AddToHammer(zns, val2); RegisterLocalization(); Plugin.Log.LogInfo((object)"Chicken bed prefab created and registered!"); } private static GameObject FindBedPrefab(ZNetScene zns) { string[] array = new string[3] { "bed", "piece_bed02", "piece_bed01" }; foreach (string text in array) { GameObject prefab = zns.GetPrefab(text); if ((Object)(object)prefab != (Object)null) { return prefab; } } foreach (GameObject prefab2 in zns.m_prefabs) { if ((Object)(object)prefab2 != (Object)null && (Object)(object)prefab2.GetComponent<Bed>() != (Object)null) { return prefab2; } } return null; } private static void AddToHammer(ZNetScene zns, GameObject chickenBed) { GameObject prefab = zns.GetPrefab("Hammer"); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)"Could not find Hammer prefab!"); return; } ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogWarning((object)"Hammer has no ItemDrop component!"); return; } PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces; if ((Object)(object)buildPieces == (Object)null) { Plugin.Log.LogWarning((object)"Hammer has no PieceTable!"); return; } buildPieces.m_pieces.Add(chickenBed); Plugin.Log.LogInfo((object)"Chicken bed added to hammer build menu."); } private static void RegisterLocalization() { Localization instance = Localization.instance; if (instance != null) { Dictionary<string, string> value = Traverse.Create((object)instance).Field("m_translations").GetValue<Dictionary<string, string>>(); if (value == null) { Plugin.Log.LogWarning((object)"Could not access localisation translations."); return; } value["piece_chickenbed"] = "Chicken Bed"; value["piece_chickenbed_desc"] = "A tiny bed for your chooks. They'll tuck themselves in when you go to sleep!"; } } } [HarmonyPatch(typeof(Player), "OnSpawned")] public static class PlayerSpawnPatch { private static void Postfix(Player __instance) { Traverse.Create((object)__instance).Method("UpdateAvailablePiecesList", Array.Empty<object>()).GetValue(); } }