Decompiled source of Ranensols Villagers v1.0.2

Ranensol.BepInEx.Aska.Villagers.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
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.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Microsoft.CodeAnalysis;
using Ranensol.BepInEx.Aska.Villagers.Components;
using Ranensol.BepInEx.Aska.Villagers.Homesteads;
using Ranensol.BepInEx.Aska.Villagers.Services;
using SSSGame;
using SSSGame.AI;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Ranensol.BepInEx.Aska.Villagers")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2")]
[assembly: AssemblyInformationalVersion("1.0.2+6ad49280390e7dcb51859cdc63cf13c783f36e54")]
[assembly: AssemblyProduct("Ranensol Villagers")]
[assembly: AssemblyTitle("Ranensol.BepInEx.Aska.Villagers")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Ranensol.BepInEx.Aska.Villagers
{
	public class ModConfig
	{
		public ConfigEntry<bool> ModEnabled { get; }

		public ConfigEntry<bool> DisplayBedsAvailable { get; }

		public ConfigEntry<bool> AutoHouseNewVillagers { get; }

		public ConfigEntry<float> AutoAssignDelay { get; }

		public ConfigEntry<Key> HotKeyManualAssignment { get; }

		public ConfigEntry<bool> TierBasedHousing { get; }

		public ConfigEntry<bool> UseHappinessScoring { get; }

		public ConfigEntry<Key> HotKeyMakeAllHomeless { get; }

		public ModConfig(ConfigFile config)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			ModEnabled = config.Bind<bool>("1 - General", "ModEnabled", true, "Enable or disable the entire mod");
			DisplayBedsAvailable = config.Bind<bool>("2 - UI", "DisplayBedsAvailable", true, "Display the 'Beds available' counter in the top-right HUD");
			AutoHouseNewVillagers = config.Bind<bool>("3 - Housing", "AutoHouseNewVillagers", true, "Automatically assign newly summoned villagers to available houses");
			AutoAssignDelay = config.Bind<float>("3 - Housing", "AutoAssignDelay", 3f, new ConfigDescription("Delay in seconds after villager spawns before auto-assignment", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			TierBasedHousing = config.Bind<bool>("3 - Housing", "TierBasedHousing", true, "Prioritize higher-tier villagers when assigning houses (Tier 4 gets first pick, then Tier 3, etc.)");
			UseHappinessScoring = config.Bind<bool>("3 - Housing", "UseHappinessScoring", true, "Use actual game happiness calculations (Comfort + Area Desirability) to determine best houses. If disabled, uses simple house type priority (Longhouse > Cottage > Shelter)");
			HotKeyManualAssignment = config.Bind<Key>("4 - Hotkeys", "ManualAssignmentKey", (Key)101, "Hotkey to manually trigger homeless villager assignment");
			HotKeyMakeAllHomeless = config.Bind<Key>("4 - Hotkeys", "MakeAllVillagersHomelessKey", (Key)102, "Hotkey to make all villagers homeless (useful for testing or re-sorting)");
		}
	}
	[BepInPlugin("Ranensol.BepInEx.Aska.Villagers", "Ranensol Villagers", "1.0.2")]
	public class Plugin : BasePlugin
	{
		public static ManualLogSource Log;

		public static ModConfig Config;

		public override void Load()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BasePlugin)this).Log;
			Config = new ModConfig(((BasePlugin)this).Config);
			if (!Config.ModEnabled.Value)
			{
				Log.LogInfo((object)"Mod is disabled in config");
				return;
			}
			((BasePlugin)this).AddComponent<VillagerAutoAssigner>();
			if (Config.DisplayBedsAvailable.Value)
			{
				((BasePlugin)this).AddComponent<VillagerStatsWidget>();
			}
			new Harmony("Ranensol.BepInEx.Aska.Villagers").PatchAll();
			Log.LogInfo((object)"Mod loaded");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Ranensol.BepInEx.Aska.Villagers";

		public const string PLUGIN_NAME = "Ranensol Villagers";

		public const string PLUGIN_VERSION = "1.0.2";
	}
}
namespace Ranensol.BepInEx.Aska.Villagers.Services
{
	public static class VillagerAssignmentService
	{
		private class HousingSlot
		{
			public Homestead Homestead { get; set; }

			public int FinalOccupants { get; set; }

			public float PredictedScore { get; set; }
		}

		public static void AssignHomelessVillagers(bool assignOnlyNewest)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				List<Villager> homelessVillagers = GetHomelessVillagers(assignOnlyNewest);
				if (homelessVillagers.Count == 0)
				{
					Plugin.Log.LogDebug((object)"No homeless villagers found");
					return;
				}
				List<Homestead> availableHomesteads = HomesteadFinder.GetAvailableHomesteads();
				if (availableHomesteads.Count == 0)
				{
					Plugin.Log.LogWarning((object)"No available homesteads!");
					return;
				}
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(61, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Assigning ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(homelessVillagers.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" villagers to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(availableHomesteads.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" available homesteads in main village");
				}
				log.LogInfo(val);
				List<HousingSlot> slots = CreateHousingSlotsWithFinalOccupancy(availableHomesteads, homelessVillagers.Count, !assignOnlyNewest);
				AssignVillagersToSlots(homelessVillagers, slots);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(38, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Exception in AssignHomelessVillagers: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log2.LogError(val2);
				Plugin.Log.LogError((object)ex.StackTrace);
			}
		}

		public static void MakeAllVillagersHomeless()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				IEnumerable<Villager> enumerable = ((IEnumerable<Villager>)Object.FindObjectsOfType<Villager>()).Where((Villager v) => v.GetHomeOutpostId() == 0);
				int num = 0;
				foreach (Villager item in enumerable)
				{
					Homestead homestead = item.GetHomestead();
					if ((Object)(object)homestead != (Object)null)
					{
						ReleaseVillagerFromHomestead(item, homestead);
						num++;
					}
				}
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(40, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Made ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" villagers in main village homeless");
				}
				log.LogInfo(val);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(39, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Exception in MakeAllVillagersHomeless: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log2.LogError(val2);
			}
		}

		private static List<Villager> GetHomelessVillagers(bool onlyNewest)
		{
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			List<Villager> list = ((IEnumerable<Villager>)Object.FindObjectsOfType<Villager>()).Where((Villager v) => (Object)(object)v.GetHomestead() == (Object)null).ToList();
			if (list.Count == 0)
			{
				return list;
			}
			if (Plugin.Config.TierBasedHousing.Value)
			{
				list = list.OrderByDescending((Villager v) => v.GetProficiencyTier()).ToList();
				Plugin.Log.LogDebug((object)"Sorted villagers by proficiency tier");
			}
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2;
			if (onlyNewest)
			{
				Villager val = list.OrderByDescending((Villager v) => v.PersistentUniqueID).First();
				ManualLogSource log = Plugin.Log;
				val2 = new BepInExInfoLogInterpolatedStringHandler(47, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Auto-assign: targeting newest villager (");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Character)val).GetName());
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ID: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(val.PersistentUniqueID);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(")");
				}
				log.LogInfo(val2);
				return new List<Villager>(1) { val };
			}
			ManualLogSource log2 = Plugin.Log;
			val2 = new BepInExInfoLogInterpolatedStringHandler(25, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Found ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(list.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" homeless villagers");
			}
			log2.LogInfo(val2);
			return list;
		}

		private static List<HousingSlot> CreateHousingSlotsWithFinalOccupancy(List<Homestead> homesteads, int villagersToAssign, bool sortBestFirst)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			List<(Homestead homestead, int finalOccupancy)> list = CalculateGreedyDistribution(homesteads, villagersToAssign, sortBestFirst);
			List<HousingSlot> list2 = new List<HousingSlot>();
			foreach (var item3 in list)
			{
				Homestead item = item3.homestead;
				int item2 = item3.finalOccupancy;
				int agentsCount = item.GetAgentsCount();
				int num = item2 - agentsCount;
				if (num > 0)
				{
					float predictedScore = CalculateFinalScore(item, item2);
					for (int i = 0; i < num; i++)
					{
						list2.Add(new HousingSlot
						{
							Homestead = item,
							FinalOccupants = item2,
							PredictedScore = predictedScore
						});
					}
				}
			}
			list2 = list2.OrderByDescending((HousingSlot s) => s.PredictedScore).ToList();
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(22, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Created ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list2.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" housing slots");
			}
			log.LogDebug(val);
			return list2;
		}

		private static List<(Homestead homestead, int finalOccupancy)> CalculateGreedyDistribution(List<Homestead> homesteads, int villagersToAssign, bool pickBestHouses)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Expected O, but got Unknown
			Dictionary<Homestead, int> occupancy = homesteads.ToDictionary((Homestead h) => h, (Homestead h) => h.GetAgentsCount());
			Dictionary<Homestead, int> capacity = homesteads.ToDictionary((Homestead h) => h, (Homestead h) => h.GetAgentsCapacity());
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(68, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Greedy distribution for ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(villagersToAssign);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" villagers across ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(homesteads.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" houses (picking ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pickBestHouses ? "best" : "worst");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" houses):");
			}
			log.LogDebug(val);
			for (int i = 0; i < villagersToAssign; i++)
			{
				var source = from h in homesteads
					where occupancy[h] < capacity[h]
					select new
					{
						House = h,
						Score = HomesteadScorer.PredictFinalHappinessScore(h, occupancy[h] + 1)
					};
				Homestead val2 = ((!pickBestHouses) ? source.OrderBy(x => x.Score).FirstOrDefault()?.House : source.OrderByDescending(x => x.Score).FirstOrDefault()?.House);
				if ((Object)(object)val2 == (Object)null)
				{
					break;
				}
				occupancy[val2]++;
			}
			List<(Homestead, int)> result = occupancy.Where<KeyValuePair<Homestead, int>>((KeyValuePair<Homestead, int> kvp) => kvp.Value > kvp.Key.GetAgentsCount()).Select(delegate(KeyValuePair<Homestead, int> kvp)
			{
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Expected O, but got Unknown
				float num = HomesteadScorer.PredictFinalHappinessScore(kvp.Key, kvp.Value);
				int num2 = capacity[kvp.Key] - kvp.Key.GetAgentsCount();
				int num3 = kvp.Value - kvp.Key.GetAgentsCount();
				ManualLogSource log3 = Plugin.Log;
				bool flag2 = default(bool);
				BepInExDebugLogInterpolatedStringHandler val3 = new BepInExDebugLogInterpolatedStringHandler(56, 6, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("  ");
					Structure structure = kvp.Key._structure;
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>((structure != null) ? structure.GetName() : null);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(": final score per person ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(num, "F1");
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", assigning ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num3);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("/");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num2);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" beds (final: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(kvp.Value);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("/");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(capacity[kvp.Key]);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(")");
				}
				log3.LogDebug(val3);
				return (kvp.Key, kvp.Value);
			}).ToList();
			ManualLogSource log2 = Plugin.Log;
			val = new BepInExDebugLogInterpolatedStringHandler(44, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Distribution complete: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(occupancy.Values.Sum() - homesteads.Sum((Homestead h) => h.GetAgentsCount()));
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(villagersToAssign);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" villagers allocated");
			}
			log2.LogDebug(val);
			return result;
		}

		private static float CalculateFinalScore(Homestead h, int finalOccupants)
		{
			if (Plugin.Config.UseHappinessScoring.Value)
			{
				return HomesteadScorer.PredictFinalHappinessScore(h, finalOccupants);
			}
			return (float)HomesteadScorer.GetHouseTierPriority(h) * 100f;
		}

		private static void AssignVillagersToSlots(List<Villager> villagers, List<HousingSlot> slots)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			int num = 0;
			int num2 = Math.Min(villagers.Count, slots.Count);
			bool flag = default(bool);
			for (int i = 0; i < num2; i++)
			{
				Villager val = villagers[i];
				HousingSlot housingSlot = slots[i];
				if (AssignVillagerToHomestead(val, housingSlot.Homestead))
				{
					num++;
					LogAssignment(val, housingSlot);
					continue;
				}
				ManualLogSource log = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(21, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to assign ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Character)val).GetName());
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" to ");
					Structure structure = housingSlot.Homestead._structure;
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>((structure != null) ? structure.GetName() : null);
				}
				log.LogError(val2);
			}
			ManualLogSource log2 = Plugin.Log;
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(39, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Assignment complete: ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("/");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(villagers.Count);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" villagers housed");
			}
			log2.LogInfo(val3);
		}

		private static void LogAssignment(Villager villager, HousingSlot slot)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			if (Plugin.Config.TierBasedHousing.Value)
			{
				int num = villager.GetProficiencyTier() + 1;
				string text = $"{slot.FinalOccupants}/{slot.Homestead.GetAgentsCapacity()}";
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(44, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Assigned ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Character)villager).GetName());
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (Tier ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") to ");
					Structure structure = slot.Homestead._structure;
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((structure != null) ? structure.GetName() : null);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (Score: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(slot.PredictedScore, "F1");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", Occupancy: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
				}
				log.LogDebug(val);
			}
		}

		private static bool AssignVillagerToHomestead(Villager villager, Homestead homestead)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			try
			{
				ITaskAgent obj = ((Il2CppObjectBase)villager).Cast<ITaskAgent>();
				IWorkstation val = ((Il2CppObjectBase)homestead).Cast<IWorkstation>();
				return obj.AssignToWorkstation(val);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(30, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Exception assigning villager: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val2);
				return false;
			}
		}

		private static void ReleaseVillagerFromHomestead(Villager villager, Homestead homestead)
		{
			((Il2CppObjectBase)villager).Cast<ITaskAgent>().ReleaseFromWorkstation(((Il2CppObjectBase)homestead).Cast<IWorkstation>(), villager.GetHomeOutpostId());
		}
	}
}
namespace Ranensol.BepInEx.Aska.Villagers.Patches
{
	[HarmonyPatch(typeof(VillagerOutlet), "SpawnVillager")]
	internal class VillagerSpawnedPatch
	{
		private static void Postfix()
		{
			if (Plugin.Config.AutoHouseNewVillagers.Value)
			{
				Plugin.Log.LogInfo((object)"Villager spawned from Eye of Odin");
				VillagerAutoAssigner.Instance?.TriggerDelayedAssignment();
			}
		}
	}
}
namespace Ranensol.BepInEx.Aska.Villagers.Homesteads
{
	public static class HomesteadFinder
	{
		private static readonly string[] ValidHomesteadNames = new string[3] { "Shelter_L1(Clone)", "House_L1(Clone)", "House_L2(Clone)" };

		public static List<Homestead> GetAvailableHomesteads()
		{
			return ((IEnumerable<Homestead>)Object.FindObjectsOfType<Homestead>()).Where((Homestead homestead) => IsValidHomestead(homestead) && HasAvailableBeds(homestead) && IsInMainVillage(homestead)).ToList();
		}

		public static List<Homestead> GetAllHomesteads()
		{
			return ((IEnumerable<Homestead>)Object.FindObjectsOfType<Homestead>()).Where((Homestead homestead) => IsValidHomestead(homestead) && IsInMainVillage(homestead)).ToList();
		}

		private static bool IsValidHomestead(Homestead homestead)
		{
			if (ValidHomesteadNames.Contains(((Object)homestead).name))
			{
				return ((Component)homestead).gameObject.activeSelf;
			}
			return false;
		}

		private static bool HasAvailableBeds(Homestead homestead)
		{
			return homestead.GetAgentsCapacity() > homestead.GetAgentsCount();
		}

		private static bool IsInMainVillage(Homestead homestead)
		{
			Structure component = ((Component)homestead).GetComponent<Structure>();
			if ((Object)(object)component != (Object)null)
			{
				return component.OutpostId == 0;
			}
			return false;
		}
	}
	public static class HomesteadScorer
	{
		private const int HOUSING_POINTS_ID = 145;

		private const int EXTERIOR_HOUSING_POINTS_ID = 148;

		public static float GetBaseHappinessScore(Homestead homestead)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				float num = 0f;
				foreach (StructureScoreManager component in ((Component)homestead).GetComponents<StructureScoreManager>())
				{
					if (!((Object)(object)component.scoreAttrConfig == (Object)null))
					{
						int attributeId = component.scoreAttrConfig.attributeId;
						flag = ((attributeId == 145 || attributeId == 148) ? true : false);
						if (flag)
						{
							num += component.Score;
						}
					}
				}
				return num;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(31, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to get base score for ");
					Structure structure = homestead._structure;
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((structure != null) ? structure.GetName() : null);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
				return 0f;
			}
		}

		public static float GetOccupancyMultiplier(Homestead homestead, int occupants)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			try
			{
				foreach (StructureScoreManager component in ((Component)homestead).GetComponents<StructureScoreManager>())
				{
					if (component.agentsCountMultiplierCurve != null)
					{
						return component.agentsCountMultiplierCurve.Evaluate((float)occupants);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(31, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to get multiplier for ");
					object obj;
					if (homestead == null)
					{
						obj = null;
					}
					else
					{
						Structure structure = homestead._structure;
						obj = ((structure != null) ? structure.GetName() : null);
					}
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((string)obj);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
			}
			return 1f / (float)Mathf.Max(1, occupants);
		}

		public static float PredictFinalHappinessScore(Homestead homestead, int finalOccupants)
		{
			float baseHappinessScore = GetBaseHappinessScore(homestead);
			float occupancyMultiplier = GetOccupancyMultiplier(homestead, finalOccupants);
			return baseHappinessScore * occupancyMultiplier;
		}

		public static int GetHouseTierPriority(Homestead homestead)
		{
			return ((Object)homestead).name switch
			{
				"House_L2(Clone)" => 3, 
				"House_L1(Clone)" => 2, 
				"Shelter_L1(Clone)" => 1, 
				_ => 0, 
			};
		}
	}
}
namespace Ranensol.BepInEx.Aska.Villagers.Components
{
	public class VillagerAutoAssigner : MonoBehaviour
	{
		private float _delayedCheckTimer = -1f;

		public static VillagerAutoAssigner Instance { get; private set; }

		public VillagerAutoAssigner(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Awake()
		{
			Instance = this;
			Plugin.Log.LogInfo((object)"VillagerAutoAssigner initialized");
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Update()
		{
			HandleHotkeys();
			HandleDelayedAssignment();
		}

		public void TriggerDelayedAssignment()
		{
			_delayedCheckTimer = Plugin.Config.AutoAssignDelay.Value;
		}

		private static void HandleHotkeys()
		{
			//IL_0017: 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)
			if (Keyboard.current != null)
			{
				if (((ButtonControl)Keyboard.current[Plugin.Config.HotKeyManualAssignment.Value]).wasPressedThisFrame)
				{
					Plugin.Log.LogInfo((object)"Manual assignment hotkey pressed");
					VillagerAssignmentService.AssignHomelessVillagers(assignOnlyNewest: false);
				}
				if (((ButtonControl)Keyboard.current[Plugin.Config.HotKeyMakeAllHomeless.Value]).wasPressedThisFrame)
				{
					Plugin.Log.LogInfo((object)"Make all homeless hotkey pressed");
					VillagerAssignmentService.MakeAllVillagersHomeless();
				}
			}
		}

		private void HandleDelayedAssignment()
		{
			if (!(_delayedCheckTimer < 0f))
			{
				_delayedCheckTimer -= Time.deltaTime;
				if (_delayedCheckTimer <= 0f)
				{
					Plugin.Log.LogInfo((object)"Running delayed auto-assignment");
					VillagerAssignmentService.AssignHomelessVillagers(assignOnlyNewest: true);
					_delayedCheckTimer = -1f;
				}
			}
		}
	}
	public class VillagerStatsWidget : MonoBehaviour
	{
		private TMP_Text _bedStatsText;

		private float _updateTimer;

		private bool _uiCreated;

		public VillagerStatsWidget(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			CheckForDestroyedUI();
			if (!_uiCreated)
			{
				CreateBedStatsUI();
			}
			else
			{
				UpdateBedStatsText();
			}
		}

		private void CheckForDestroyedUI()
		{
			if (_uiCreated && (Object)(object)_bedStatsText == (Object)null)
			{
				_uiCreated = false;
				Plugin.Log.LogInfo((object)"Bed stats UI was destroyed, will recreate");
			}
		}

		private void CreateBedStatsUI()
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			try
			{
				GameObject val = GameObject.Find("TemperatureList");
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Transform val2 = val.transform.Find("VillagersPanel");
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Log.LogError((object)"Could not find VillagersPanel");
					_uiCreated = true;
					return;
				}
				GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, val.transform);
				((Object)val3).name = "BedStatsPanel";
				_bedStatsText = val3.GetComponentInChildren<TMP_Text>();
				if ((Object)(object)_bedStatsText != (Object)null)
				{
					_bedStatsText.text = "Beds available: 0";
				}
				_uiCreated = true;
				Plugin.Log.LogInfo((object)"Bed stats UI created successfully");
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(31, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Failed to create bed stats UI: ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val4);
				_uiCreated = true;
			}
		}

		private void UpdateBedStatsText()
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			if ((Object)(object)_bedStatsText == (Object)null)
			{
				return;
			}
			_updateTimer += Time.deltaTime;
			if (_updateTimer < 1f)
			{
				return;
			}
			_updateTimer = 0f;
			try
			{
				List<Homestead> allHomesteads = HomesteadFinder.GetAllHomesteads();
				int num = allHomesteads.Sum((Homestead h) => h.GetAgentsCapacity());
				int num2 = allHomesteads.Sum((Homestead h) => h.GetAgentsCount());
				int value = Math.Max(0, num - num2);
				_bedStatsText.text = $"Beds available: {value}";
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error updating bed stats: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val);
			}
		}
	}
}