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);
}
}
}
}