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 Il2CppInterop.Runtime.InteropTypes.Arrays;
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.1")]
[assembly: AssemblyInformationalVersion("1.0.1+0c59d37951c9b83589abcb9fe5c344d3043ae144")]
[assembly: AssemblyProduct("Ranensol Villagers")]
[assembly: AssemblyTitle("Ranensol.BepInEx.Aska.Villagers")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.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 ConfigEntry<bool> IncludeOutposts { 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)");
IncludeOutposts = config.Bind<bool>("3 - Housing", "IncludeOutposts", false, "Include outpost houses when assigning villagers. WARNING: Villagers will be assigned to ANY available bed (main village or outposts) with no logic for which outpost they should go to. Leave disabled if you want to manage outpost housing manually.");
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.1")]
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.1";
}
}
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(45, 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");
}
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_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Expected O, but got Unknown
bool flag = default(bool);
try
{
Il2CppArrayBase<Villager> obj = Object.FindObjectsOfType<Villager>();
int num = 0;
foreach (Villager item in obj)
{
Homestead homestead = item.GetHomestead();
if ((Object)(object)homestead != (Object)null)
{
ReleaseVillagerFromHomestead(item, homestead);
num++;
}
}
ManualLogSource log = Plugin.Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(24, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Made ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" villagers 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 h) => IsValidHomestead(h) && HasAvailableBeds(h) && IsInMainVillage(h)).ToList();
}
public static List<Homestead> GetAllHomesteads()
{
return ((IEnumerable<Homestead>)Object.FindObjectsOfType<Homestead>()).Where((Homestead h) => IsValidHomestead(h) && IsInMainVillage(h)).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 h)
{
return h.GetAgentsCapacity() > h.GetAgentsCount();
}
private static bool IsInMainVillage(Homestead h)
{
if (Plugin.Config.IncludeOutposts.Value)
{
return true;
}
Structure component = ((Component)h).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);
}
}
}
}