using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SailwindModdingHelper;
using UnityEngine;
using UnityEngine.Rendering;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("PlayerHome")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PlayerHome")]
[assembly: AssemblyTitle("PlayerHome")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace PlayerHome
{
[BepInPlugin("com.yourname.playerhome", "Player Home", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class PlayerHomePlugin : BaseUnityPlugin
{
public const string GUID = "com.yourname.playerhome";
public const string NAME = "Player Home";
public const string VERSION = "1.0.0";
internal static PlayerHomePlugin I;
internal static ManualLogSource Log;
private ConfigEntry<bool> _dumpPrefabs;
private ConfigEntry<bool> _enableTavernClaim;
private ConfigEntry<bool> _traceSleep;
private ConfigEntry<KeyCode> _captureKey;
private ConfigEntry<KeyCode> _probeKey;
private ConfigEntry<bool> _persistItems;
private ConfigEntry<KeyCode> _recordKey;
private ConfigEntry<KeyCode> _restoreKey;
private ConfigEntry<float> _clearRadius;
private ConfigEntry<float> _furnishRadius;
private ConfigEntry<string> _clearOverrides;
private readonly Dictionary<string, float> _clearRadiusOverrides = new Dictionary<string, float>();
private ConfigEntry<string> _excludedTaverns;
private readonly HashSet<string> _excludedIds = new HashSet<string>();
private ConfigEntry<string> _priceOverrides;
private readonly Dictionary<string, int> _priceOverrideMap = new Dictionary<string, int>();
private readonly List<Home> _homes = new List<Home>();
private SaveData _save = new SaveData();
private bool _worldReady;
private float _claimScanTimer;
private const float RESCAN_INTERVAL = 2f;
private float _watchdogTimer;
private static float CLEAR_RADIUS = 15f;
private int _lastSeenTavernCount = -1;
private int _lastTrackedCount = -1;
private int _btnLayer = -1;
private static readonly Dictionary<string, int> PriceById = new Dictionary<string, int>
{
{ "tavern@32220_-5702", 150 },
{ "tavern@1990_44155", 40 },
{ "tavern@-45174_-47290", 120 },
{ "tavern@10369_35314", 150 },
{ "tavern@7210_40799", 150 },
{ "tavern@6675_42432", 75 }
};
private static readonly List<KeyValuePair<string, int>> PriceTable = new List<KeyValuePair<string, int>>
{
new KeyValuePair<string, int>("nilem", 30),
new KeyValuePair<string, int>("neverdin", 30),
new KeyValuePair<string, int>("oasis", 30),
new KeyValuePair<string, int>("fort aestrin", 100),
new KeyValuePair<string, int>("malific", 150),
new KeyValuePair<string, int>("eastwind", 40),
new KeyValuePair<string, int>("siren", 75),
new KeyValuePair<string, int>("happy", 150),
new KeyValuePair<string, int>("dragon", 50),
new KeyValuePair<string, int>("crab", 80),
new KeyValuePair<string, int>("sage", 80),
new KeyValuePair<string, int>("firefly", 150),
new KeyValuePair<string, int>("dead cove", 75),
new KeyValuePair<string, int>("chronos", 75),
new KeyValuePair<string, int>("aestrin", 100)
};
private const int DEFAULT_PRICE = 75;
private static readonly List<KeyValuePair<string, int>> PriceByTown = new List<KeyValuePair<string, int>>
{
new KeyValuePair<string, int>("nilem", 30),
new KeyValuePair<string, int>("neverdin", 30),
new KeyValuePair<string, int>("oasis", 30),
new KeyValuePair<string, int>("old ankh", 120),
new KeyValuePair<string, int>("ankh", 120),
new KeyValuePair<string, int>("fort aestrin", 100),
new KeyValuePair<string, int>("malefic", 150),
new KeyValuePair<string, int>("eastwind", 40),
new KeyValuePair<string, int>("siren", 75),
new KeyValuePair<string, int>("happy", 150),
new KeyValuePair<string, int>("dragon", 50),
new KeyValuePair<string, int>("crab", 80),
new KeyValuePair<string, int>("sage", 80),
new KeyValuePair<string, int>("firefly", 150),
new KeyValuePair<string, int>("turtle", 75),
new KeyValuePair<string, int>("dead cove", 75),
new KeyValuePair<string, int>("chronos", 75)
};
private static readonly string[] FurnitureKeywords = new string[24]
{
"furniture_table", "furniture chair", "furniture bench", "furniture stool", "bookshelf", "bookcase", "Prefab_BigBarrel", "open barrel", "small keg", "shop stove",
"stove", "carpet", "painting", "wine", "pickaxe", "table", "bench", "chair", "stool", "keg",
"barrel", "shelf", "cabinet", "crate"
};
private static readonly string[] FurnitureExclude = new string[32]
{
"building", "polySurface", "palm", "fence", "dock", "window", "door", "roof", "awning", "wall",
"stair", "floor", "pillar", "beam", "terrain", "rock", "lamppost", "light post", "lantern", "candle",
"torch", "streetlight", "shop item", "shop area", "static shop", "(Clone)", "market_stall", "market stall", "trigger", "mooring",
"crane", "well"
};
private static readonly string[] FurnitureHardExclude = new string[1] { "light post a big" };
private static readonly string[] FurnitureForceInclude = new string[8] { "static shop item", "staticitem", "candle A", "light post a", "building_arab_addon_shelf", "bush_05", "east_market_stall", "ita street banners" };
private static readonly Dictionary<string, float> _clearRadiusDefaults = new Dictionary<string, float> { { "tavern@-48907_-46062", 10f } };
private readonly HashSet<int> _killedFurniture = new HashSet<int>();
private static readonly HashSet<string> _wideBushTaverns = new HashSet<string> { "tavern@43966_-38811" };
private Transform _graveyard;
internal static bool TraceSleep
{
get
{
if ((Object)(object)I != (Object)null && I._traceSleep != null)
{
return I._traceSleep.Value;
}
return false;
}
}
private string PluginDir => Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
private string HomesTxtPath => Path.Combine(PluginDir, "homes.txt");
private static bool OriginReady => (Object)(object)FloatingOriginManager.instance != (Object)null;
private void Awake()
{
//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0307: Expected O, but got Unknown
//IL_030e: Unknown result type (might be due to invalid IL or missing references)
//IL_0318: Expected O, but got Unknown
I = this;
Log = ((BaseUnityPlugin)this).Logger;
_dumpPrefabs = ((BaseUnityPlugin)this).Config.Bind<bool>("Setup", "DumpPrefabs", false, "Log candidate building/bed prefab names after a save loads. Turn off when done.");
_enableTavernClaim = ((BaseUnityPlugin)this).Config.Bind<bool>("Setup", "EnableTavernClaim", true, "Let you claim existing in-world taverns as homes (people + shop cleared, free inn rest kept). This is the main, dependable mode.");
_traceSleep = ((BaseUnityPlugin)this).Config.Bind<bool>("Rest", "TraceSleep", false, "DIAGNOSTIC: log a detailed frame-by-frame trace of needs + sleep state during ANY tavern rest (owned or not). Use it once on a tavern you DON'T own to capture how the game's paid rest restores you, then send the log. Turn off when done.");
_captureKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Setup", "CaptureKey", (KeyCode)289, "Press this in-game to log your current spot as a ready-to-paste homes.txt line.");
_probeKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Setup", "ProbeKey", (KeyCode)290, "DIAGNOSTIC: stand next to a leftover object (e.g. bottles/crate a claimed tavern didn't clear) and press this to log the nearest meshes' exact names, parent chains, positions, and whether each is a live renderer or a baked combine. Use the logged name to extend the furniture keyword list.");
_persistItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Persistence", "PersistTavernItems", true, "Items you leave inside a tavern you own are remembered and put back when you return (like cargo on a ship). Uses the game's own item serialization; never writes the game's save file. Turn off to disable the feature entirely.");
_recordKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Persistence", "RecordKey", (KeyCode)288, "TEST: capture the items you've placed in the owned tavern you're standing in, into the mod save. (Auto-capture also runs on game save.)");
_restoreKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Persistence", "RestoreKey", (KeyCode)287, "TEST: re-spawn the recorded items for the owned tavern you're standing in. (Auto-restore also runs on load.)");
_clearRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Radii", "ClearRadius", 15f, "How far (metres) from a tavern's anchor a CLAIM clears furniture, shop goods and NPCs. Keep this tight — just the room — so claiming doesn't delete neighbouring market stalls or the merchant/passenger-dude tables nearby.");
_furnishRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Radii", "FurnishRadius", 14f, "How far (metres) from a tavern's anchor counts as 'your home' for item persistence: items you leave inside this zone are remembered and restored. Made a bit wider than the room so you can furnish an adjacent porch/deck too.");
_clearOverrides = ((BaseUnityPlugin)this).Config.Bind<string>("Radii", "ClearRadiusOverrides", "", "Per-tavern clear-radius overrides for taverns whose claim reaches something it shouldn't (e.g. a vendor just outside). Format: 'id:metres' pairs separated by ';', where the id is the one shown in the [claim] log line for that tavern. Example: 'tavern@-267_-494:8;tavern@100_200:10'. (As of 0.8.4 these ids are stable across sessions, so an override you set here will keep matching.)");
_excludedTaverns = ((BaseUnityPlugin)this).Config.Bind<string>("Claiming", "ExcludedTaverns", "tavern@-43697_-44065;tavern@42687_-35046", "Taverns that CANNOT be claimed (no buy option appears). Semicolon-separated list of ids as shown in the [claim] log line. Defaults exclude Gold Rock City and New Port, whose decor is baked into a shared city mesh that can't be cleanly removed. Clear this string to make every tavern claimable again.");
_priceOverrides = ((BaseUnityPlugin)this).Config.Bind<string>("Claiming", "PriceOverrides", "", "Override the claim price of specific taverns. Semicolon-separated 'key:price' pairs, where key is either the tavern id (tavern@X_Z from the [claim] log) or a word from its port name (e.g. 'neverdin:25'). Use this to fix any tavern that the built-in price table didn't recognise — the assigned price and detected port name are written to the log on load.");
CLEAR_RADIUS = _clearRadius.Value;
ParseClearOverrides(_clearOverrides.Value);
_excludedIds.Clear();
string[] array = _excludedTaverns.Value.Split(new char[1] { ';' });
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (text.Length > 0)
{
_excludedIds.Add(text);
}
}
_priceOverrideMap.Clear();
array = _priceOverrides.Value.Split(new char[1] { ';' });
for (int i = 0; i < array.Length; i++)
{
string text2 = array[i].Trim();
int num = text2.LastIndexOf(':');
if (num > 0 && int.TryParse(text2.Substring(num + 1).Trim(), out var result))
{
_priceOverrideMap[text2.Substring(0, num).Trim().ToLowerInvariant()] = result;
}
}
Harmony.CreateAndPatchAll(typeof(PlayerHomePlugin).Assembly, "com.yourname.playerhome");
GameEvents.OnSaveLoadPost += (SaveSlotEventHandler)delegate
{
OnWorldReady();
};
GameEvents.OnGameSave += (GameSaveEventHandler)delegate
{
OnGameSave();
};
Log.LogInfo((object)"Player Home 1.0.0 loaded.");
}
private static Vector3 RealToWorld(Vector3 real)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
if (!OriginReady)
{
return real;
}
return FloatingOriginManager.instance.RealPosToShiftingPos(real);
}
private static Vector3 WorldToReal(Vector3 world)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
if (!OriginReady)
{
return world;
}
return FloatingOriginManager.instance.ShiftingPosToRealPos(world);
}
private void Update()
{
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
if (OriginReady)
{
foreach (Home home3 in _homes)
{
if (!((Object)(object)home3.root == (Object)null) && !home3.isClaimedTavern)
{
home3.root.transform.position = RealToWorld(home3.realPos);
}
}
}
if (Input.GetKeyDown(_captureKey.Value) && (Object)(object)Utilities.PlayerTransform != (Object)null)
{
Vector3 val = WorldToReal(Utilities.PlayerTransform.position);
float y = Utilities.PlayerTransform.eulerAngles.y;
Log.LogInfo((object)"==== PLAYER HOME: spot captured ====");
Log.LogInfo((object)$" myhome | TAVERN | | {val.x:F2} | {val.y:F2} | {val.z:F2} | {y:F0} | 25000 | -1 | 12");
Log.LogInfo((object)" (paste that line into homes.txt; change id/prefab/price to taste)");
}
if (Input.GetKeyDown(_probeKey.Value))
{
ProbeNearby();
}
if (Input.GetKeyDown(_recordKey.Value))
{
Home home = NearestOwnedHome();
if (home == null)
{
Log.LogInfo((object)"[persist] record: no owned tavern nearby.");
}
else
{
int num = CaptureItemsFor(home);
ModSave.Save(((BaseUnityPlugin)this).Info, (object)_save);
Log.LogInfo((object)$"[persist] recorded {num} item(s) for '{home.def.id}'.");
}
}
if (Input.GetKeyDown(_restoreKey.Value))
{
Home home2 = NearestOwnedHome();
if (home2 == null)
{
Log.LogInfo((object)"[persist] restore: no owned tavern nearby.");
}
else
{
int num2 = RestoreItemsFor(home2);
Log.LogInfo((object)$"[persist] restored {num2} item(s) for '{home2.def.id}'.");
}
}
if (_worldReady && _persistItems.Value)
{
UpdateHomePresence();
}
if (!_worldReady && _enableTavernClaim.Value && OriginReady && GameState.playing && !GameState.currentlyLoading && (Object)(object)Utilities.PlayerTransform != (Object)null)
{
_watchdogTimer += Time.deltaTime;
if (_watchdogTimer >= 5f && Object.FindObjectsOfType<Tavern>().Length != 0)
{
Log.LogWarning((object)"[watchdog] save-load event never reached PlayerHome — self-triggering world setup.");
OnWorldReady();
}
}
if (_worldReady && _enableTavernClaim.Value)
{
_claimScanTimer += Time.deltaTime;
if (_claimScanTimer >= 2f)
{
_claimScanTimer = 0f;
SetupTavernClaims();
SweepOwnedTavernFurniture();
}
}
}
private void OnWorldReady()
{
try
{
if (_dumpPrefabs.Value)
{
DumpPrefabs();
return;
}
foreach (Home home in _homes)
{
if ((Object)(object)home.root != (Object)null && !home.isClaimedTavern)
{
Object.Destroy((Object)(object)home.root);
}
}
_homes.Clear();
SaveData saveData = default(SaveData);
if (ModSave.Load<SaveData>(((BaseUnityPlugin)this).Info, ref saveData) && saveData != null)
{
_save = saveData;
}
else
{
_save = new SaveData();
}
SpawnPlaceableHomes();
Log.LogInfo((object)$"TAVERNDIAG: OnWorldReady — EnableTavernClaim = {_enableTavernClaim.Value}");
if (_enableTavernClaim.Value)
{
SetupTavernClaims();
}
RestoreWarehouses();
_worldReady = true;
_claimScanTimer = 0f;
}
catch (Exception ex)
{
Log.LogError((object)("Setup failed: " + ex));
}
}
private void SpawnPlaceableHomes()
{
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Expected O, but got Unknown
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_01be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
List<HomeDef> list = LoadHomesConfig();
Vector3 val = default(Vector3);
foreach (HomeDef item in list)
{
if (string.IsNullOrEmpty(item.id))
{
Log.LogWarning((object)"A home in homes.txt has no id; skipped.");
continue;
}
((Vector3)(ref val))..ctor(item.x, item.y, item.z);
Quaternion val2 = Quaternion.Euler(0f, item.yaw, 0f);
GameObject val3 = new GameObject("PlayerHome_" + item.id);
val3.transform.SetPositionAndRotation(RealToWorld(val), val2);
if (!string.IsNullOrEmpty(item.prefab))
{
GameObject prefabGameObject = GameAssets.GetPrefabGameObject(item.prefab);
if ((Object)(object)prefabGameObject != (Object)null)
{
StripBusiness(Object.Instantiate<GameObject>(prefabGameObject, val3.transform.position, val2, val3.transform));
}
else
{
Log.LogWarning((object)("[" + item.id + "] prefab '" + item.prefab + "' not found (use DumpPrefabs)."));
}
}
if (!string.IsNullOrEmpty(item.bedPrefab))
{
GameObject prefabGameObject2 = GameAssets.GetPrefabGameObject(item.bedPrefab);
if ((Object)(object)prefabGameObject2 != (Object)null)
{
Object.Instantiate<GameObject>(prefabGameObject2, val3.transform.position, val2, val3.transform);
}
}
Home home = new Home
{
def = item,
root = val3,
realPos = val,
owned = _save.ownedIds.Contains(item.id),
isClaimedTavern = false
};
_homes.Add(home);
MakeRestButton(home, new Vector3(0.8f, 1.3f, 0f));
if (!home.owned)
{
MakeBuyButton(home, new Vector3(-0.8f, 1.3f, 0f));
}
}
Log.LogInfo((object)$"Spawned {list.Count} placeable home(s).");
}
private void SetupTavernClaims()
{
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_031f: Unknown result type (might be due to invalid IL or missing references)
//IL_0326: Unknown result type (might be due to invalid IL or missing references)
//IL_032b: Unknown result type (might be due to invalid IL or missing references)
//IL_0330: Unknown result type (might be due to invalid IL or missing references)
//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
//IL_0401: Unknown result type (might be due to invalid IL or missing references)
//IL_0406: Unknown result type (might be due to invalid IL or missing references)
//IL_0423: Unknown result type (might be due to invalid IL or missing references)
//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
//IL_0478: Unknown result type (might be due to invalid IL or missing references)
//IL_047d: Unknown result type (might be due to invalid IL or missing references)
//IL_0498: Unknown result type (might be due to invalid IL or missing references)
//IL_048c: Unknown result type (might be due to invalid IL or missing references)
//IL_049d: Unknown result type (might be due to invalid IL or missing references)
//IL_04ba: Unknown result type (might be due to invalid IL or missing references)
//IL_04c1: Unknown result type (might be due to invalid IL or missing references)
//IL_04d2: Unknown result type (might be due to invalid IL or missing references)
//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
int num = 0;
Tavern[] array = Object.FindObjectsOfType<Tavern>();
int num2 = Resources.FindObjectsOfTypeAll<Tavern>().Length;
if (array.Length != _lastSeenTavernCount)
{
_lastSeenTavernCount = array.Length;
Log.LogInfo((object)$"TAVERNDIAG: active Tavern objects = {array.Length}, incl-inactive = {num2}");
}
Tavern[] array2 = array;
foreach (Tavern tav in array2)
{
Transform transform = ((Component)tav).transform;
Vector3 val = WorldToReal(transform.position);
string id = $"tavern@{Mathf.Round(val.x)}_{Mathf.Round(val.z)}";
if (_excludedIds.Contains(id))
{
continue;
}
Home home = _homes.Find((Home h) => h.isClaimedTavern && ((Object)(object)h.tavern == (Object)(object)tav || h.def.id == id));
if (home == null)
{
bool confident;
int price = PriceForTavern(tav, id, out confident);
home = new Home
{
def = new HomeDef
{
id = id,
price = price,
storeRadius = (((Object)(object)I != (Object)null && I._furnishRadius != null) ? I._furnishRadius.Value : 14f)
},
root = ((Component)tav).gameObject,
owned = _save.ownedIds.Contains(id),
isClaimedTavern = true,
tavern = tav,
priceConfirmed = confident
};
_homes.Add(home);
if (home.owned)
{
DisableTavernBusiness(home);
}
num++;
}
else if ((Object)(object)home.tavern != (Object)(object)tav)
{
home.tavern = tav;
home.root = ((Component)tav).gameObject;
home.buttonAnchored = false;
if (home.owned)
{
DisableTavernBusiness(home);
}
if (home.owned && _persistItems != null && _persistItems.Value)
{
int num3 = RestoreItemsFor(home);
if (num3 > 0)
{
Log.LogInfo((object)$"[persist] '{home.def.id}' streamed in: restored {num3} item(s).");
}
}
}
if (!home.owned && !home.priceConfirmed)
{
bool confident2;
int num4 = PriceForTavern(tav, id, out confident2);
if (confident2)
{
home.def.price = num4;
home.priceConfirmed = true;
RefreshBuyLabel(home);
Log.LogInfo((object)$"[price] {id} re-resolved -> {num4}g (town NPC now ready)");
}
}
if (home.owned || home.buttonAnchored)
{
continue;
}
GPButtonTavernSleep val2 = null;
float num5 = float.MaxValue;
GPButtonTavernSleep[] array3 = Object.FindObjectsOfType<GPButtonTavernSleep>();
foreach (GPButtonTavernSleep val3 in array3)
{
Vector3 val4 = ((Component)val3).transform.position - transform.position;
float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
if (sqrMagnitude < num5)
{
num5 = sqrMagnitude;
val2 = val3;
}
}
if ((Object)(object)val2 == (Object)null)
{
if (array.Length == _lastSeenTavernCount)
{
}
}
else
{
if (num5 > 900f)
{
continue;
}
if (home.owned)
{
if (Object.op_Implicit((Object)(object)home.buyButton))
{
((Component)home.buyButton).gameObject.SetActive(false);
}
continue;
}
if ((Object)(object)home.buyButton == (Object)null)
{
MakeBuyButton(home, Vector3.zero);
}
((Component)home.buyButton).gameObject.SetActive(true);
((Component)home.buyButton).transform.position = ((Component)val2).transform.position - Vector3.up * 0.35f;
((Component)home.buyButton).transform.rotation = ((Component)val2).transform.rotation;
((GoPointerButton)home.buyButton).lookText = (home.buyLabelAdded ? "" : $"buy tavern ({home.def.price}g)");
home.buttonAnchored = true;
Vector3 position = ((Component)home.buyButton).transform.position;
Vector3 val5 = (((Object)(object)Utilities.PlayerTransform != (Object)null) ? Utilities.PlayerTransform.position : Vector3.zero);
Log.LogInfo((object)($"TAVERNDIAG: anchored '{((Object)((Component)tav).gameObject).name}' | buttonPos={position} | playerPos={val5} " + $"| dist={Vector3.Distance(position, val5):F1} | sleepDist={Mathf.Sqrt(num5):F1}"));
}
}
if (_homes.Count != _lastTrackedCount)
{
Log.LogInfo((object)$"[experimental] {_homes.Count} tavern home(s) tracked.");
_lastTrackedCount = _homes.Count;
}
}
private int ButtonLayer()
{
if (_btnLayer >= 0)
{
return _btnLayer;
}
GoPointerButton val = Object.FindObjectOfType<GoPointerButton>();
_btnLayer = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject.layer : 0);
return _btnLayer;
}
private GameObject MakeButtonPlate(Home home, Vector3 offset, string name)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
((Object)obj).name = name;
obj.transform.SetParent(home.root.transform, false);
obj.transform.localPosition = offset;
Vector3 val = default(Vector3);
((Vector3)(ref val))..ctor(0.5f, 0.25f, 0.04f);
Vector3 lossyScale = home.root.transform.lossyScale;
obj.transform.localScale = new Vector3(val.x / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.x)), val.y / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.y)), val.z / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.z)));
obj.layer = ButtonLayer();
MeshRenderer component = obj.GetComponent<MeshRenderer>();
if ((Object)(object)component != (Object)null && (Object)(object)((Renderer)component).material != (Object)null)
{
((Renderer)component).material.color = new Color(0.88f, 0.8f, 0.62f);
}
return obj;
}
private void MakeRestButton(Home home, Vector3 offset)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
HomeRestButton homeRestButton = MakeButtonPlate(home, offset, "RestButton").AddComponent<HomeRestButton>();
homeRestButton.home = home;
((GoPointerButton)homeRestButton).lookText = "rest until morning";
((GoPointerButton)homeRestButton).unclickable = !home.owned;
home.restButton = homeRestButton;
}
private void MakeBuyButton(Home home, Vector3 offset)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
GameObject val = MakeButtonPlate(home, offset, "BuyButton");
HomeBuyButton homeBuyButton = val.AddComponent<HomeBuyButton>();
homeBuyButton.home = home;
((GoPointerButton)homeBuyButton).lookText = $"buy this home ({home.def.price} gold)";
home.buyButton = homeBuyButton;
AddBuyLabel(home, val);
}
private void AddBuyLabel(Home home, GameObject plate)
{
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Unknown result type (might be due to invalid IL or missing references)
//IL_019b: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
try
{
if ((Object)(object)home.tavern == (Object)null)
{
return;
}
Component value = Traverse.Create((object)home.tavern).Field("text").GetValue<Component>();
if ((Object)(object)value == (Object)null)
{
return;
}
Type type = ((object)value).GetType();
object value2 = Traverse.Create((object)value).Property("font", (object[])null).GetValue();
MeshRenderer component = value.GetComponent<MeshRenderer>();
Material val = (((Object)(object)component != (Object)null) ? ((Renderer)component).sharedMaterial : null);
float num = Traverse.Create((object)value).Property("characterSize", (object[])null).GetValue<float>();
int num2 = Traverse.Create((object)value).Property("fontSize", (object[])null).GetValue<int>();
Vector3 lossyScale = value.transform.lossyScale;
if (num <= 0f)
{
num = 0.1f;
}
if (num2 <= 0)
{
num2 = 30;
}
GameObject val2 = new GameObject("BuyLabel")
{
layer = plate.layer
};
val2.transform.SetParent(plate.transform, false);
Vector3 lossyScale2 = plate.transform.lossyScale;
val2.transform.localScale = new Vector3(1.3f * lossyScale.x / Mathf.Max(0.0001f, Mathf.Abs(lossyScale2.x)), 1.3f * lossyScale.y / Mathf.Max(0.0001f, Mathf.Abs(lossyScale2.y)), 1.3f * lossyScale.z / Mathf.Max(0.0001f, Mathf.Abs(lossyScale2.z)));
val2.transform.localPosition = new Vector3(0f, 0f, -0.55f);
val2.transform.localRotation = Quaternion.identity;
Component val3 = val2.AddComponent(type);
Traverse val4 = Traverse.Create((object)val3);
val4.Property("text", (object[])null).SetValue((object)$"Buy Tavern\n{home.def.price}g");
val4.Property("color", (object[])null).SetValue((object)Color.black);
val4.Property("characterSize", (object[])null).SetValue((object)num);
val4.Property("fontSize", (object[])null).SetValue((object)num2);
val4.Property("lineSpacing", (object[])null).SetValue((object)0.8f);
if (value2 != null)
{
val4.Property("font", (object[])null).SetValue(value2);
}
SetEnumProp(val3, "anchor", 4);
SetEnumProp(val3, "alignment", 1);
MeshRenderer component2 = val2.GetComponent<MeshRenderer>();
if ((Object)(object)component2 != (Object)null)
{
if ((Object)(object)val != (Object)null)
{
((Renderer)component2).sharedMaterial = val;
}
((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
((Renderer)component2).receiveShadows = false;
}
home.buyLabelTM = val3;
home.buyLabelAdded = true;
}
catch (Exception ex)
{
Log.LogWarning((object)("[buy-label] couldn't add permanent label: " + ex.Message));
}
}
private void RefreshBuyLabel(Home home)
{
try
{
if (home != null && !((Object)(object)home.buyLabelTM == (Object)null))
{
Traverse.Create((object)home.buyLabelTM).Property("text", (object[])null).SetValue((object)$"Buy Tavern\n{home.def.price}g");
}
}
catch
{
}
}
private void SetEnumProp(object obj, string prop, int val)
{
try
{
PropertyInfo property = obj.GetType().GetProperty(prop);
if (property != null)
{
property.SetValue(obj, Enum.ToObject(property.PropertyType, val), null);
}
}
catch
{
}
}
internal void TryBuy(Home home)
{
if (home == null || home.owned)
{
return;
}
int num = 3;
if (PlayerGold.currency == null || num < 0 || num >= PlayerGold.currency.Length)
{
Log.LogWarning((object)$"Bad currency index {num}; cannot charge.");
Notify("Couldn't process the purchase here.");
}
else if (PlayerGold.currency[num] >= home.def.price)
{
PlayerGold.currency[num] -= home.def.price;
home.owned = true;
if (!_save.ownedIds.Contains(home.def.id))
{
_save.ownedIds.Add(home.def.id);
}
if (home.isClaimedTavern)
{
DisableTavernBusiness(home);
}
if (Object.op_Implicit((Object)(object)home.buyButton))
{
((Component)home.buyButton).gameObject.SetActive(false);
}
if (Object.op_Implicit((Object)(object)home.restButton))
{
((GoPointerButton)home.restButton).unclickable = false;
}
Notify(home.isClaimedTavern ? "Tavern claimed!" : "Home purchased!");
ModSave.Save(((BaseUnityPlugin)this).Info, (object)_save);
}
else
{
Notify("Not enough money.");
}
}
private string GetPortName(Transform t)
{
Transform val = t;
while ((Object)(object)val != (Object)null)
{
string name = ((Object)val).name;
int num = name.IndexOf('(');
int num2 = name.IndexOf(')');
if (num >= 0 && num2 > num + 1)
{
return name.Substring(num + 1, num2 - num - 1).Trim().ToLowerInvariant();
}
val = val.parent;
}
return "";
}
private string GetTownName(Tavern tav)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
try
{
TavernRumorsDude[] array = Object.FindObjectsOfType<TavernRumorsDude>();
TavernRumorsDude val = null;
float num = 625f;
Vector3 position = ((Component)tav).transform.position;
TavernRumorsDude[] array2 = array;
foreach (TavernRumorsDude val2 in array2)
{
Vector3 val3 = ((Component)val2).transform.position - position;
float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
if (sqrMagnitude < num)
{
num = sqrMagnitude;
val = val2;
}
}
if ((Object)(object)val == (Object)null)
{
return "";
}
int portIndex = val.portIndex;
Port[] ports = Port.ports;
if (ports == null || portIndex < 0 || portIndex >= ports.Length || (Object)(object)ports[portIndex] == (Object)null)
{
return "";
}
string value = Traverse.Create((object)ports[portIndex]).Field("portName").GetValue<string>();
return (value != null) ? value.Trim().ToLowerInvariant() : "";
}
catch
{
return "";
}
}
private int PriceForTavern(Tavern tav, string id, out bool confident)
{
confident = true;
string portName = GetPortName(((Component)tav).transform);
string townName = GetTownName(tav);
if (_priceOverrideMap.TryGetValue(id.ToLowerInvariant(), out var value))
{
Log.LogInfo((object)$"[price] {id} town='{townName}' -> {value}g (config id override)");
return value;
}
foreach (KeyValuePair<string, int> item in _priceOverrideMap)
{
if (item.Key.Length > 0 && (townName.Contains(item.Key) || portName.Contains(item.Key)))
{
Log.LogInfo((object)$"[price] {id} town='{townName}' -> {item.Value}g (config name override '{item.Key}')");
return item.Value;
}
}
if (PriceById.TryGetValue(id, out var value2))
{
Log.LogInfo((object)$"[price] {id} town='{townName}' -> {value2}g (pinned by id)");
return value2;
}
if (townName.Length > 0)
{
foreach (KeyValuePair<string, int> item2 in PriceByTown)
{
if (townName.Contains(item2.Key))
{
Log.LogInfo((object)$"[price] {id} town='{townName}' -> {item2.Value}g (town '{item2.Key}')");
return item2.Value;
}
}
}
confident = townName.Length > 0;
foreach (KeyValuePair<string, int> item3 in PriceTable)
{
if (portName.Contains(item3.Key))
{
Log.LogWarning((object)string.Format("[price] {0} town='{1}' port='{2}' -> {3}g (island-name fallback '{4}'{5})", id, townName, portName, item3.Value, item3.Key, confident ? "" : "; town NPC not ready — will re-resolve"));
return item3.Value;
}
}
Log.LogWarning((object)string.Format("[price] {0} town='{1}' port='{2}' -> {3}g (DEFAULT{4})", id, townName, portName, 75, confident ? " — town has no price-table entry" : "; town NPC not ready — will re-resolve"));
return 75;
}
internal void Rest(Home home)
{
if (home == null)
{
return;
}
if (!home.owned)
{
Notify("You don't own this home yet.");
}
else if (!Object.op_Implicit((Object)(object)GameState.inBed) && !GameState.sleeping)
{
if ((Object)(object)home.tavern != (Object)null)
{
home.tavern.ClickSleepButton();
}
else
{
Sleep.instance.FallAsleep();
}
}
}
internal bool OwnsTavern(Tavern tav)
{
foreach (Home home in _homes)
{
if (home.owned && home.isClaimedTavern && (Object)(object)home.tavern == (Object)(object)tav)
{
return true;
}
}
return false;
}
internal bool SleepingAtOwnedTavern()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Utilities.PlayerTransform == (Object)null)
{
return false;
}
Vector3 position = Utilities.PlayerTransform.position;
foreach (Home home in _homes)
{
if (home.owned && home.isClaimedTavern && !((Object)(object)home.tavern == (Object)null) && Vector3.Distance(position, ((Component)home.tavern).transform.position) <= 60f)
{
return true;
}
}
return false;
}
internal static string SleepSnapshot()
{
return $"food={PlayerNeeds.food:F3} water={PlayerNeeds.water:F3} sleep={PlayerNeeds.sleep:F3} " + $"foodDebt={PlayerNeeds.foodDebt:F3} sleepDebt={PlayerNeeds.sleepDebt:F3} | " + $"sleeping={GameState.sleeping} inBed={GameState.inBed} sleepingInTavern={GameState.sleepingInTavern}";
}
internal void StartSleepTrace(string trigger)
{
if (TraceSleep)
{
Log.LogInfo((object)("[sleep-trace] === REST TRIGGERED via " + trigger + " === " + SleepSnapshot()));
((MonoBehaviour)this).StartCoroutine(SleepTraceCo());
}
}
private IEnumerator SleepTraceCo()
{
int frame = 0;
float w = 0f;
while (!GameState.sleeping && w < 1f)
{
w += Time.deltaTime;
yield return null;
}
while (GameState.sleeping)
{
Log.LogInfo((object)$"[sleep-trace] frame {frame++}: {SleepSnapshot()}");
yield return null;
}
for (int i = 0; i < 30; i++)
{
Log.LogInfo((object)$"[sleep-trace] post-wake +{i}: {SleepSnapshot()}");
yield return null;
}
Log.LogInfo((object)("[sleep-trace] === TRACE END === " + SleepSnapshot()));
}
private Home NearestOwnedHome()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: 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 ((Object)(object)Utilities.PlayerTransform == (Object)null)
{
return null;
}
Vector3 position = Utilities.PlayerTransform.position;
Home result = null;
float num = float.MaxValue;
foreach (Home home in _homes)
{
if (home.owned)
{
Vector3 val = HomeAnchor(home);
float num2 = Vector3.Distance(position, val);
if (num2 < num)
{
num = num2;
result = home;
}
}
}
return result;
}
private static Vector3 HomeAnchor(Home home)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)home.root != (Object)null)
{
return home.root.transform.position;
}
if ((Object)(object)home.tavern != (Object)null)
{
return ((Component)home.tavern).transform.position;
}
return Vector3.zero;
}
private static HashSet<long> LiveInstanceIds()
{
HashSet<long> hashSet = new HashSet<long>();
SaveablePrefab[] array = Object.FindObjectsOfType<SaveablePrefab>();
foreach (SaveablePrefab val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
try
{
object value = Traverse.Create((object)val).Field("instanceId").GetValue();
if (value != null)
{
hashSet.Add(Convert.ToInt64(value));
}
}
catch
{
}
}
return hashSet;
}
private int CaptureItemsFor(Home home)
{
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
Warehouse warehouse = _save.warehouses.Find((Warehouse w) => w.homeId == home.def.id);
if (warehouse == null)
{
warehouse = new Warehouse
{
homeId = home.def.id
};
_save.warehouses.Add(warehouse);
}
Vector3 val = HomeAnchor(home);
List<StoredItem> list = new List<StoredItem>();
SaveablePrefab[] array = Object.FindObjectsOfType<SaveablePrefab>();
foreach (SaveablePrefab val2 in array)
{
if ((Object)(object)val2 == (Object)null)
{
continue;
}
try
{
if (Traverse.Create((object)val2).Method("GetParentObject", Array.Empty<object>()).GetValue<int>() > 0)
{
continue;
}
object value = Traverse.Create((object)val2).Field("item").GetValue();
if (value == null || !Convert.ToBoolean(Traverse.Create(value).Field("sold").GetValue()) || Vector3.Distance(((Component)val2).transform.position, val) > home.def.storeRadius)
{
continue;
}
SavePrefabData value2 = Traverse.Create((object)val2).Method("PrepareSaveData", Array.Empty<object>()).GetValue<SavePrefabData>();
if (value2 != null)
{
string blob;
using (MemoryStream memoryStream = new MemoryStream())
{
new BinaryFormatter().Serialize(memoryStream, value2);
blob = Convert.ToBase64String(memoryStream.ToArray());
}
list.Add(new StoredItem
{
prefab = CleanName(((Object)((Component)val2).gameObject).name),
blob = blob
});
}
}
catch (Exception ex)
{
Log.LogWarning((object)("[persist] capture failed for '" + ((Object)((Component)val2).gameObject).name + "': " + ex.Message));
}
}
if (list.Count == 0 && warehouse.items.Count > 0)
{
Log.LogInfo((object)$"[persist] capture for '{home.def.id}' found 0 items but {warehouse.items.Count} are stored — keeping the stored set (guard).");
return warehouse.items.Count;
}
warehouse.items = list;
return list.Count;
}
private int RestoreItemsFor(Home home)
{
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Expected O, but got Unknown
Warehouse warehouse = _save.warehouses.Find((Warehouse w) => w.homeId == home.def.id);
if (warehouse == null || warehouse.items.Count == 0)
{
return 0;
}
HashSet<long> hashSet = LiveInstanceIds();
PrefabsDirectory val = Object.FindObjectOfType<PrefabsDirectory>();
GameObject[] array = (((Object)(object)val != (Object)null) ? Traverse.Create((object)val).Field("directory").GetValue<GameObject[]>() : null);
if (array == null)
{
Log.LogWarning((object)"[persist] restore: prefab directory unavailable.");
return 0;
}
int num = 0;
foreach (StoredItem item2 in warehouse.items)
{
if (string.IsNullOrEmpty(item2.blob))
{
continue;
}
try
{
SavePrefabData val2;
using (MemoryStream serializationStream = new MemoryStream(Convert.FromBase64String(item2.blob)))
{
val2 = (SavePrefabData)new BinaryFormatter().Deserialize(serializationStream);
}
if (val2 == null)
{
continue;
}
long item = Convert.ToInt64(val2.instanceId);
if (hashSet.Contains(item))
{
continue;
}
int prefabIndex = val2.prefabIndex;
if (prefabIndex < 0 || prefabIndex >= array.Length || (Object)(object)array[prefabIndex] == (Object)null)
{
Log.LogWarning((object)$"[persist] restore: bad prefab index {prefabIndex} for '{item2.prefab}'.");
continue;
}
GameObject val3 = Object.Instantiate<GameObject>(array[prefabIndex]);
SaveablePrefab component = val3.GetComponent<SaveablePrefab>();
if ((Object)(object)component == (Object)null)
{
Object.Destroy((Object)(object)val3);
continue;
}
Traverse.Create((object)component).Method("Load", new object[1] { val2 }).GetValue();
hashSet.Add(item);
num++;
}
catch (Exception ex)
{
Log.LogWarning((object)("[persist] restore failed for '" + item2.prefab + "': " + ex.Message));
}
}
return num;
}
private void OnGameSave()
{
if (!_persistItems.Value)
{
return;
}
try
{
foreach (Home home in _homes)
{
if (home.owned && home.playerInside)
{
CaptureItemsFor(home);
}
}
ModSave.Save(((BaseUnityPlugin)this).Info, (object)_save);
}
catch (Exception ex)
{
Log.LogWarning((object)("[persist] OnGameSave failed: " + ex.Message));
}
}
private void RestoreWarehouses()
{
foreach (Home home in _homes)
{
home.playerInside = false;
}
}
private void UpdateHomePresence()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Utilities.PlayerTransform == (Object)null)
{
return;
}
Vector3 position = Utilities.PlayerTransform.position;
foreach (Home home in _homes)
{
if (!home.owned)
{
continue;
}
if (home.isClaimedTavern)
{
if ((Object)(object)home.tavern == (Object)null)
{
continue;
}
}
else if ((Object)(object)home.root == (Object)null)
{
continue;
}
bool flag = Vector3.Distance(position, HomeAnchor(home)) <= home.def.storeRadius;
if (flag && !home.playerInside)
{
int num = RestoreItemsFor(home);
if (num > 0)
{
Log.LogInfo((object)$"[persist] entered '{home.def.id}': restored {num} item(s).");
}
}
else if (!flag && home.playerInside)
{
int num2 = CaptureItemsFor(home);
ModSave.Save(((BaseUnityPlugin)this).Info, (object)_save);
Log.LogInfo((object)$"[persist] left '{home.def.id}': captured {num2} item(s).");
}
home.playerInside = flag;
}
}
private void StripBusiness(GameObject building)
{
Tavern[] componentsInChildren = building.GetComponentsInChildren<Tavern>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
Object.Destroy((Object)(object)componentsInChildren[i]);
}
GPButtonTavernSleep[] componentsInChildren2 = building.GetComponentsInChildren<GPButtonTavernSleep>(true);
for (int i = 0; i < componentsInChildren2.Length; i++)
{
Object.Destroy((Object)(object)((Component)componentsInChildren2[i]).gameObject);
}
Shopkeeper[] componentsInChildren3 = building.GetComponentsInChildren<Shopkeeper>(true);
for (int i = 0; i < componentsInChildren3.Length; i++)
{
Object.Destroy((Object)(object)((Component)componentsInChildren3[i]).gameObject);
}
ShopItemSpawner[] componentsInChildren4 = building.GetComponentsInChildren<ShopItemSpawner>(true);
for (int i = 0; i < componentsInChildren4.Length; i++)
{
Object.Destroy((Object)(object)((Component)componentsInChildren4[i]).gameObject);
}
}
private static bool IsFurnitureName(string nm)
{
string[] furnitureHardExclude = FurnitureHardExclude;
foreach (string value in furnitureHardExclude)
{
if (nm.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
{
return false;
}
}
furnitureHardExclude = FurnitureForceInclude;
foreach (string value2 in furnitureHardExclude)
{
if (nm.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
}
furnitureHardExclude = FurnitureExclude;
foreach (string value3 in furnitureHardExclude)
{
if (nm.IndexOf(value3, StringComparison.OrdinalIgnoreCase) >= 0)
{
return false;
}
}
furnitureHardExclude = FurnitureKeywords;
foreach (string value4 in furnitureHardExclude)
{
if (nm.IndexOf(value4, StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
}
return false;
}
private void ParseClearOverrides(string raw)
{
_clearRadiusOverrides.Clear();
if (string.IsNullOrEmpty(raw))
{
return;
}
string[] array = raw.Split(new char[1] { ';' });
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (text.Length == 0)
{
continue;
}
int num = text.LastIndexOf(':');
if (num > 0 && num < text.Length - 1)
{
string key = text.Substring(0, num).Trim();
if (float.TryParse(text.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result > 0f)
{
_clearRadiusOverrides[key] = result;
}
}
}
}
private float ClearRadiusFor(Home home)
{
if (home != null && home.def != null && _clearRadiusOverrides.TryGetValue(home.def.id, out var value))
{
return value;
}
if (home != null && home.def != null && _clearRadiusDefaults.TryGetValue(home.def.id, out var value2))
{
return value2;
}
return CLEAR_RADIUS;
}
private int RevertCombinersNear(Vector3 anchor, bool verbose, float radius = -1f)
{
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
int num = 0;
float num2 = ((radius > 0f) ? radius : CLEAR_RADIUS);
float num3 = (num2 + 5f) * (num2 + 5f);
MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>();
foreach (MonoBehaviour val in array)
{
if ((Object)(object)val == (Object)null || ((object)val).GetType().Name != "MeshCombiner" || (Object)(object)((Component)val).transform == (Object)null)
{
continue;
}
GameObject[] array2 = null;
try
{
array2 = Traverse.Create((object)val).Field("combinedObjects").GetValue<GameObject[]>();
}
catch
{
}
if (array2 == null || array2.Length == 0)
{
continue;
}
float num4 = float.MaxValue;
GameObject[] array3 = array2;
foreach (GameObject val2 in array3)
{
if (!((Object)(object)val2 == (Object)null))
{
Vector3 val3 = val2.transform.position - anchor;
float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
if (sqrMagnitude < num4)
{
num4 = sqrMagnitude;
}
}
}
if (verbose)
{
Log.LogInfo((object)$"[furn-scan] '{((Object)((Component)val).gameObject).name}' baked={array2.Length} nearest={((num4 == float.MaxValue) ? (-1f) : Mathf.Sqrt(num4)):F1}u (threshold {CLEAR_RADIUS + 5f:F0}u)");
}
if (!(num4 > num3))
{
try
{
Traverse.Create((object)val).Method("RevertCombinedMeshes", Array.Empty<object>()).GetValue();
num++;
Log.LogInfo((object)$"[furn-revert] reverted MeshCombiner on '{((Object)((Component)val).gameObject).name}' (baked {array2.Length} objs, nearest {Mathf.Sqrt(num4):F1}u)");
}
catch (Exception ex)
{
Log.LogInfo((object)("[furn-revert] failed on '" + ((Object)((Component)val).gameObject).name + "': " + ex.Message));
}
}
}
return num;
}
private static bool HasSaveablePrefabInChain(Transform t)
{
Transform val = t;
while ((Object)(object)val != (Object)null)
{
if ((Object)(object)((Component)val).GetComponent("SaveablePrefab") != (Object)null)
{
return true;
}
val = val.parent;
}
return false;
}
private int ClearFurnitureNear(Vector3 anchor, bool logKills, float radius = -1f, string anchorId = null)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: Unknown result type (might be due to invalid IL or missing references)
//IL_014f: Unknown result type (might be due to invalid IL or missing references)
float num = ((radius > 0f) ? radius : CLEAR_RADIUS);
float num2 = num * num;
RevertCombinersNear(anchor, logKills, num);
int num3 = 0;
HashSet<GameObject> hashSet = new HashSet<GameObject>();
MeshFilter[] array = Object.FindObjectsOfType<MeshFilter>();
foreach (MeshFilter val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
Vector3 val2 = ((Component)val).transform.position - anchor;
if (((Vector3)(ref val2)).sqrMagnitude > num2)
{
continue;
}
Transform val3 = ((Component)val).transform;
GameObject val4 = null;
while ((Object)(object)val3 != (Object)null)
{
if (IsFurnitureName(((Object)((Component)val3).gameObject).name))
{
val4 = ((Component)val3).gameObject;
break;
}
val3 = val3.parent;
}
if ((Object)(object)val4 == (Object)null || !hashSet.Add(val4))
{
continue;
}
string name = ((Object)val4).name;
float num4 = 0f;
if (name.IndexOf("bush", StringComparison.OrdinalIgnoreCase) >= 0)
{
num4 = ((anchorId != null && _wideBushTaverns.Contains(anchorId)) ? (num * num) : 25f);
}
else if (name.IndexOf("light post a", StringComparison.OrdinalIgnoreCase) >= 0)
{
num4 = 36f;
}
else if (name.IndexOf("east_market_stall", StringComparison.OrdinalIgnoreCase) >= 0)
{
num4 = 64f;
}
if (num4 > 0f)
{
val2 = val4.transform.position - anchor;
if (((Vector3)(ref val2)).sqrMagnitude > num4)
{
continue;
}
}
if (HasSaveablePrefabInChain(val4.transform))
{
continue;
}
bool flag = false;
Renderer[] componentsInChildren = val4.GetComponentsInChildren<Renderer>(true);
foreach (Renderer val5 in componentsInChildren)
{
if ((Object)(object)val5 != (Object)null && val5.enabled && ((Component)val5).gameObject.activeInHierarchy)
{
flag = true;
break;
}
}
if (!flag)
{
continue;
}
int instanceID = ((Object)val4).GetInstanceID();
if (_killedFurniture.Add(instanceID))
{
num3++;
if (logKills)
{
Log.LogInfo((object)string.Format("[furn-kill] '{0}' static={1} parent='{2}'", ((Object)val4).name, val4.isStatic, Object.op_Implicit((Object)(object)val4.transform.parent) ? ((Object)val4.transform.parent).name : "none"));
}
}
if ((Object)(object)val4.transform.parent != (Object)(object)Graveyard())
{
val4.transform.SetParent(Graveyard(), false);
}
if (val4.activeSelf)
{
val4.SetActive(false);
}
}
return num3;
}
private Transform Graveyard()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_graveyard == (Object)null)
{
GameObject val = new GameObject("PlayerHomeRemovedFurniture");
val.transform.position = new Vector3(0f, -5000f, 0f);
val.SetActive(false);
_graveyard = val.transform;
}
return _graveyard;
}
private void SweepOwnedTavernFurniture()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Utilities.PlayerTransform == (Object)null)
{
return;
}
Vector3 position = Utilities.PlayerTransform.position;
foreach (Home home in _homes)
{
if (!home.owned || !home.isClaimedTavern || (Object)(object)home.tavern == (Object)null)
{
continue;
}
Vector3 position2 = ((Component)home.tavern).transform.position;
float num = Vector3.Distance(position, position2);
float num2 = ClearRadiusFor(home);
if (!(num > num2 + 25f))
{
int num3 = ClearFurnitureNear(position2, logKills: false, num2, home.def.id);
if (num3 > 0)
{
Log.LogInfo((object)$"[furn-sweep] hid {num3} new furniture object(s); player {num:F0}u from anchor.");
}
}
}
}
private void DisableTavernBusiness(Home home)
{
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
//IL_017f: Unknown result type (might be due to invalid IL or missing references)
//IL_0184: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01df: Unknown result type (might be due to invalid IL or missing references)
//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
//IL_0235: Unknown result type (might be due to invalid IL or missing references)
//IL_023a: Unknown result type (might be due to invalid IL or missing references)
//IL_023b: Unknown result type (might be due to invalid IL or missing references)
//IL_0240: Unknown result type (might be due to invalid IL or missing references)
//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
//IL_0290: Unknown result type (might be due to invalid IL or missing references)
//IL_0295: Unknown result type (might be due to invalid IL or missing references)
//IL_0296: Unknown result type (might be due to invalid IL or missing references)
//IL_029b: Unknown result type (might be due to invalid IL or missing references)
//IL_030a: Unknown result type (might be due to invalid IL or missing references)
//IL_030f: Unknown result type (might be due to invalid IL or missing references)
//IL_0310: Unknown result type (might be due to invalid IL or missing references)
//IL_0315: Unknown result type (might be due to invalid IL or missing references)
GameObject root = home.root;
if ((Object)(object)root == (Object)null)
{
return;
}
if ((Object)(object)home.tavern != (Object)null)
{
try
{
home.tavern.rawPrice = 0f;
Traverse.Create((object)home.tavern).Method("UpdateTextAndPrice", Array.Empty<object>()).GetValue();
}
catch (Exception ex)
{
Log.LogWarning((object)("Could not zero tavern price: " + ex.Message));
}
}
Vector3 position = root.transform.position;
float num = float.MaxValue;
GPButtonTavernSleep[] array = Object.FindObjectsOfType<GPButtonTavernSleep>();
Vector3 val2;
foreach (GPButtonTavernSleep val in array)
{
val2 = ((Component)val).transform.position - root.transform.position;
float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
if (sqrMagnitude < num)
{
num = sqrMagnitude;
position = ((Component)val).transform.position;
}
}
float num2 = ClearRadiusFor(home);
float num3 = Mathf.Min(14f, num2);
float num4 = num2 * num2;
float num5 = num3 * num3;
int num6 = 0;
int num7 = 0;
Shopkeeper[] array2 = Object.FindObjectsOfType<Shopkeeper>();
foreach (Shopkeeper val3 in array2)
{
if (Object.op_Implicit((Object)(object)val3))
{
val2 = ((Component)val3).transform.position - position;
if (((Vector3)(ref val2)).sqrMagnitude <= num5)
{
Object.Destroy((Object)(object)((Component)val3).gameObject);
num6++;
}
}
}
TavernRumorsDude[] array3 = Object.FindObjectsOfType<TavernRumorsDude>();
foreach (TavernRumorsDude val4 in array3)
{
if (Object.op_Implicit((Object)(object)val4))
{
val2 = ((Component)val4).transform.position - position;
if (((Vector3)(ref val2)).sqrMagnitude <= num4)
{
Object.Destroy((Object)(object)((Component)val4).gameObject);
num6++;
}
}
}
NPCAnimations[] array4 = Object.FindObjectsOfType<NPCAnimations>();
foreach (NPCAnimations val5 in array4)
{
if (Object.op_Implicit((Object)(object)val5))
{
val2 = ((Component)val5).transform.position - position;
if (((Vector3)(ref val2)).sqrMagnitude <= num5)
{
Object.Destroy((Object)(object)((Component)val5).gameObject);
num6++;
}
}
}
ShopItemSpawner[] array5 = Object.FindObjectsOfType<ShopItemSpawner>();
foreach (ShopItemSpawner val6 in array5)
{
if (Object.op_Implicit((Object)(object)val6))
{
val2 = ((Component)val6).transform.position - position;
if (((Vector3)(ref val2)).sqrMagnitude <= num4)
{
Object.Destroy((Object)(object)((Component)val6).gameObject);
num7++;
}
}
}
ShopArea[] array6 = Object.FindObjectsOfType<ShopArea>();
foreach (ShopArea val7 in array6)
{
if (Object.op_Implicit((Object)(object)val7))
{
val2 = ((Component)val7).transform.position - position;
if (((Vector3)(ref val2)).sqrMagnitude <= num4)
{
Object.Destroy((Object)(object)val7);
num7++;
}
}
}
int num8 = ClearFurnitureNear(position, logKills: true, num2, home.def.id);
HashSet<string> hashSet = new HashSet<string>();
MeshFilter[] array7 = Object.FindObjectsOfType<MeshFilter>();
foreach (MeshFilter val8 in array7)
{
if ((Object)(object)val8 == (Object)null)
{
continue;
}
val2 = ((Component)val8).transform.position - position;
if (!(((Vector3)(ref val2)).sqrMagnitude > num4))
{
string name = ((Object)((Component)val8).gameObject).name;
string text = (((Object)(object)((Component)val8).transform.parent != (Object)null) ? ((Object)((Component)((Component)val8).transform.parent).gameObject).name : "(no parent)");
string item = name + " <- " + text;
if (hashSet.Add(item))
{
Log.LogInfo((object)("[near-mesh] '" + name + "' parent='" + text + "'"));
}
}
}
Log.LogInfo((object)$"[claim] '{home.def.id}': removed {num6} people + {num7} shop + {num8} furniture within {num2:F0}u of anchor, kept free inn rest.");
}
private static string CleanName(string raw)
{
string text = raw.Replace("(Clone)", "").Trim();
int num = text.IndexOf(' ');
if (num > 0 && int.TryParse(text.Substring(0, num), out var _))
{
text = text.Substring(num + 1);
}
return text;
}
private List<HomeDef> LoadHomesConfig()
{
List<HomeDef> list = new List<HomeDef>();
try
{
if (!File.Exists(HomesTxtPath))
{
WriteExampleHomes();
return list;
}
string[] array = File.ReadAllLines(HomesTxtPath);
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (text.Length == 0 || text.StartsWith("#"))
{
continue;
}
string[] array2 = text.Split(new char[1] { '|' });
if (array2.Length < 10)
{
Log.LogWarning((object)("homes.txt: need 10 fields -> " + text));
continue;
}
try
{
list.Add(new HomeDef
{
id = array2[0].Trim(),
prefab = array2[1].Trim(),
bedPrefab = array2[2].Trim(),
x = F(array2[3]),
y = F(array2[4]),
z = F(array2[5]),
yaw = F(array2[6]),
price = (int)F(array2[7]),
currency = (int)F(array2[8]),
storeRadius = F(array2[9])
});
}
catch (Exception ex)
{
Log.LogWarning((object)("homes.txt skipped line: " + text + " (" + ex.Message + ")"));
}
}
}
catch (Exception ex2)
{
Log.LogError((object)("Could not read homes.txt: " + ex2.Message));
}
return list;
}
private static float F(string s)
{
return float.Parse(s.Trim(), CultureInfo.InvariantCulture);
}
private void WriteExampleHomes()
{
string[] contents = new string[11]
{
"# Player Home definitions. One home per line. Lines starting with # are ignored.", "# id | prefab | bedPrefab | x | y | z | yaw | price | currency | storeRadius", "# - id: any unique label (remembers ownership + stored cargo). Don't reuse.", "# - prefab/bedPrefab: names from the prefab dump (bedPrefab may be left empty).", "# - x y z: a STABLE position. Press F8 in-game where you want a home to log a", "# ready-to-paste line, then copy it below.", "# - price: in GOLD (homes cost universal gold, like boats). currency is ignored.", "# - use a period for decimals (e.g. 12.5), regardless of your Windows language.", "#", "# example (replace prefab + numbers with a real one captured via F8):",
"# myhome | TAVERN | | 0 | 0 | 0 | 0 | 25000 | -1 | 12"
};
File.WriteAllLines(HomesTxtPath, contents);
Log.LogInfo((object)"Wrote example homes.txt — capture a spot with F8, then add a line.");
}
private void DumpPrefabs()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
Log.LogInfo((object)"==== PLAYER HOME: prefab dump (filtered) ====");
foreach (SailwindPrefab prefab in GameAssets.Prefabs)
{
SailwindPrefab current = prefab;
string text = ((SailwindPrefab)(ref current)).PrefabName.ToLower();
if (text.Contains("tavern") || text.Contains("gallery") || text.Contains("house") || text.Contains("hut") || text.Contains("building") || text.Contains("shack") || text.Contains("studio") || text.Contains("art") || text.Contains("bed") || text.Contains("room") || text.Contains("home") || text.Contains("shop"))
{
Log.LogInfo((object)(" " + ((SailwindPrefab)(ref current)).FullPrefabName));
}
}
Log.LogInfo((object)"==== end dump (set DumpPrefabs=false when done) ====");
}
private void ProbeNearby()
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = (((Object)(object)Utilities.PlayerTransform != (Object)null) ? Utilities.PlayerTransform.position : Vector3.zero);
Home home = NearestOwnedHome();
bool flag = home != null;
Vector3 val2 = (flag ? HomeAnchor(home) : val);
Tavern val3 = null;
float num = float.MaxValue;
Tavern[] array = Object.FindObjectsOfType<Tavern>();
foreach (Tavern val4 in array)
{
Vector3 val5 = ((Component)val4).transform.position - val;
float sqrMagnitude = ((Vector3)(ref val5)).sqrMagnitude;
if (sqrMagnitude < num)
{
num = sqrMagnitude;
val3 = val4;
}
}
Vector3 val6 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).transform.position : val);
string tid = (((Object)(object)val3 != (Object)null) ? $"tavern@{Mathf.Round(WorldToReal(val6).x)}_{Mathf.Round(WorldToReal(val6).z)}" : "none");
string[] array2 = new string[11]
{
"CenterEyeAnchor", "OVRCameraRig", "OVRPlayerController", "TrackingSpace", "Skybox", "Z environment", "RealisticSkies", "needs UI", "needs minibars", "reputation notif",
"head (cam)"
};
List<KeyValuePair<float, string>> list = new List<KeyValuePair<float, string>>();
HashSet<int> hashSet = new HashSet<int>();
MeshFilter[] array3 = Object.FindObjectsOfType<MeshFilter>();
foreach (MeshFilter val7 in array3)
{
if ((Object)(object)val7 == (Object)null)
{
continue;
}
float num2 = Vector3.Distance(((Component)val7).transform.position, val);
if (num2 > 20f)
{
continue;
}
GameObject gameObject = ((Component)val7).gameObject;
if (!hashSet.Add(((Object)gameObject).GetInstanceID()))
{
continue;
}
string text = ((Object)gameObject).name;
Transform parent = gameObject.transform.parent;
for (int j = 0; j < 8; j++)
{
if (!((Object)(object)parent != (Object)null))
{
break;
}
text = ((Object)parent).name + " / " + text;
parent = parent.parent;
}
bool flag2 = false;
string[] array4 = array2;
foreach (string value in array4)
{
if (text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
{
flag2 = true;
break;
}
}
if (!flag2)
{
Renderer component = gameObject.GetComponent<Renderer>();
string text2 = (((Object)(object)component == (Object)null) ? "no-renderer" : ("renderer=" + (component.enabled ? "ON" : "OFF(baked?)")));
string text3 = (flag ? $"anchor={Vector3.Distance(((Component)val7).transform.position, val2):F1}m " : "");
string text4 = (((Object)(object)val3 != (Object)null) ? $"tav={Vector3.Distance(((Component)val7).transform.position, val6):F1}m " : "");
list.Add(new KeyValuePair<float, string>(num2, $"[probe] d={num2:F1}m {text4}{text3}static={gameObject.isStatic} {text2} | {text}"));
}
}
list.Sort((KeyValuePair<float, string> a, KeyValuePair<float, string> b) => a.Key.CompareTo(b.Key));
string text5 = (flag ? $" | nearest owned anchor '{home.def.id}' (clear radius {ClearRadiusFor(home):F0}m)" : "");
object obj;
if (!((Object)(object)val3 != (Object)null))
{
obj = "";
}
else
{
string arg = tid;
Home home2 = _homes.Find((Home h) => h.def != null && h.def.id == tid);
obj = $" | nearest tavern '{arg}' (clear radius {((home2 != null) ? ClearRadiusFor(home2) : CLEAR_RADIUS):F0}m)";
}
string text6 = (string)obj;
Log.LogInfo((object)$"==== PROBE: {list.Count} world mesh(es) within {20f}m of player (UI/camera/sky filtered out){text5}{text6} ====");
for (int num3 = 0; num3 < list.Count && num3 < 60; num3++)
{
Log.LogInfo((object)list[num3].Value);
}
Log.LogInfo((object)"==== end probe ====");
}
internal void Notify(string msg)
{
try
{
NotificationUi instance = NotificationUi.instance;
if (instance != null)
{
instance.ShowNotification(msg);
}
}
catch
{
Log.LogInfo((object)("[notify] " + msg));
}
}
}
[HarmonyPatch(typeof(Tavern), "ClickSleepButton")]
internal static class Tavern_ClickSleep_Patch
{
private static void Postfix(Tavern __instance)
{
PlayerHomePlugin i = PlayerHomePlugin.I;
if (!((Object)(object)i == (Object)null))
{
bool flag = i.OwnsTavern(__instance);
i.StartSleepTrace(flag ? "owned tavern ClickSleepButton" : "UNOWNED tavern ClickSleepButton");
}
}
}
[HarmonyPatch(typeof(Tavern), "UpdateTextAndPrice")]
internal static class Tavern_UpdateText_Patch
{
private static void Postfix(Tavern __instance)
{
PlayerHomePlugin i = PlayerHomePlugin.I;
if ((Object)(object)i == (Object)null || !i.OwnsTavern(__instance))
{
return;
}
try
{
Component value = Traverse.Create((object)__instance).Field("text").GetValue<Component>();
if ((Object)(object)value == (Object)null)
{
return;
}
Traverse.Create((object)value).Property("text", (object[])null).SetValue((object)"Welcome Home");
Transform val = value.transform;
for (int j = 0; j < 3; j++)
{
if (!((Object)(object)val.parent != (Object)null))
{
break;
}
val = val.parent;
}
Component[] componentsInChildren = ((Component)val).GetComponentsInChildren<Component>(true);
foreach (Component val2 in componentsInChildren)
{
if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)value) && !(((object)val2).GetType().Name != "TextMesh"))
{
Traverse val3 = Traverse.Create((object)val2).Property("text", (object[])null);
string text = val3.GetValue<string>() ?? "";
if (text.Contains("Rent a room") || text.Contains("Food and drink") || text.Contains("until next morning") || text.Contains("included in the price") || text.Contains("next morning"))
{
val3.SetValue((object)"");
}
}
}
}
catch
{
}
}
}
public class Home
{
public HomeDef def;
public GameObject root;
public Vector3 realPos;
public bool owned;
public bool isClaimedTavern;
public Tavern tavern;
public HomeRestButton restButton;
public HomeBuyButton buyButton;
public bool buttonAnchored;
public bool buyLabelAdded;
public Component buyLabelTM;
public bool priceConfirmed;
public bool playerInside;
}
public class HomeDef
{
public string id = "";
public string prefab = "";
public string bedPrefab = "";
public float x;
public float y;
public float z;
public float yaw;
public int price = 25000;
public int currency = -1;
public float storeRadius = 12f;
}
[Serializable]
public class SaveData
{
public List<string> ownedIds = new List<string>();
public List<Warehouse> warehouses = new List<Warehouse>();
}
[Serializable]
public class Warehouse
{
public string homeId = "";
public List<StoredItem> items = new List<StoredItem>();
}
[Serializable]
public class StoredItem
{
public string prefab = "";
public string blob = "";
public float px;
public float py;
public float pz;
public float qx;
public float qy;
public float qz;
public float qw;
}
public class HomeRestButton : GoPointerButton
{
public Home home;
public override void OnActivate()
{
PlayerHomePlugin.I?.Rest(home);
}
}
public class HomeBuyButton : GoPointerButton
{
public Home home;
public override void OnActivate()
{
PlayerHomePlugin.I?.TryBuy(home);
}
}
}