using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("MultiPlant")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("MultiPlant")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("f4ffda28-275e-405d-906b-28e0d2f550e2")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace HardheimMultiPlant; [BepInPlugin("h4nz0.hardheimmultiplant", "Hardheim Multi Plant", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] public class HardheimMultiPlantPlugin : BaseUnityPlugin { public const string ModGuid = "h4nz0.hardheimmultiplant"; public const string ModName = "Hardheim Multi Plant"; public const string ModVersion = "1.2.0"; internal static HardheimMultiPlantPlugin Instance; internal static ManualLogSource Log; private Harmony _harmony; internal static ConfigEntry Enabled; internal static ConfigEntry RequiredFarmingSkill; internal static ConfigEntry ExtraPlantsAtThreshold; internal static ConfigEntry MaxExtraPlants; internal static ConfigEntry PlantSpacing; internal static ConfigEntry UseSelectedPlantRequiredSpace; internal static ConfigEntry PlantRequiredSpaceMultiplier; internal static ConfigEntry MinimumSmallPlantSpacing; internal static ConfigEntry MinimumTreePlantSpacing; internal static ConfigEntry RequireCultivatorEquipped; internal static ConfigEntry AllowedPrefabKeywords; internal static ConfigEntry EnableSnapping; internal static ConfigEntry SnapStep; internal static ConfigEntry SnapUseGhostRight; internal static ConfigEntry PreviewExtraPlants; internal static ConfigEntry OnlyLocalPreview; internal static ConfigEntry ExtraPlacementRequiresFreeSpace; internal static ConfigEntry GroundSnapToTerrain; internal static ConfigEntry GroundSnapRayHeight; internal static ConfigEntry DebugEnabled; internal static ConfigEntry DebugGhostUpdate; internal static ConfigEntry DebugPlacement; internal static ConfigEntry DebugConfigSync; internal static ConfigEntry DebugShowPositionDetails; internal static ConfigEntry DebugDumpConfigOnLoad; internal static ConfigEntry DebugDumpConfigOnSync; internal static ConfigEntry DebugDumpAdminState; internal static ConfigEntry DebugCollisionCheck; internal static ConfigEntry UseSquarePattern; internal static ConfigEntry UseGroundRaySnap; internal static ConfigEntry GroundRayStartHeight; internal static ConfigEntry GroundRayDistance; internal static ConfigEntry RequireRealGroundHit; internal static ConfigEntry GroundNormalMinY; internal static ConfigEntry CheckExistingPlants; internal static ConfigEntry ExistingPlantCheckMultiplier; internal static ConfigEntry CheckNearbyObjectsForGrowthSpace; internal static ConfigEntry NearbyObjectCheckMultiplier; private static readonly List PreviewGhosts = new List(); private static readonly List CachedExtraPositions = new List(); private static readonly List CachedExtraCells = new List(); private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); private static readonly BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static string _lastGhostName = string.Empty; private static int _lastExtraCount = -1; private static bool _lastPreviewVisible = false; private static Quaternion _stickyRotation = Quaternion.identity; private static bool _hasStickyRotation = false; private static Quaternion _lastGoodPreviewRotation = Quaternion.identity; private static bool _hasLastGoodPreviewRotation = false; private static GameObject _lastPlacedPrefabVisualSource; private static string _lastPlacedPrefabName = string.Empty; private static string _lastSelectedPlantKey = string.Empty; private void Awake() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; CreateConfigValues(); HookJotunnEvents(); _harmony = new Harmony("h4nz0.hardheimmultiplant"); _harmony.PatchAll(); Log.LogInfo((object)"=================================================="); Log.LogInfo((object)"Hardheim Multi Plant 1.2.0 betöltve."); Log.LogInfo((object)"Jotunn dependency aktív: igen"); Log.LogInfo((object)"Config sync mód: AdminOnlyStrictness.IfOnServer"); Log.LogInfo((object)"=================================================="); if (DebugDumpConfigOnLoad.Value) { DumpAllConfig("Awake"); } } private void OnDestroy() { try { _harmony.UnpatchSelf(); } catch { } DestroyPreviewGhosts(); } private void CreateConfigValues() { Enabled = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Általános", "Enabled", true, "A mod fő kapcsolója. Ha kikapcsolod, sem preview, sem extra ültetés nem fut.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config = ((BaseUnityPlugin)this).Config; AcceptableValueBase val = (AcceptableValueBase)(object)new AcceptableValueRange(0, 100); RequiredFarmingSkill = ConfigFileExtensions.BindConfig(config, "Egyensúly", "RequiredFarmingSkill", 60, "Minimum Farming skill szint, ami felett aktiválódik a többes ültetés.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config2 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0, 16); ExtraPlantsAtThreshold = ConfigFileExtensions.BindConfig(config2, "Egyensúly", "ExtraPlantsAtThreshold", 8, "Ennyi extra növény jelenik meg és ültethető le, amikor a játékos eléri a minimum skill szintet.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config3 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0, 32); MaxExtraPlants = ConfigFileExtensions.BindConfig(config3, "Egyensúly", "MaxExtraPlants", 8, "Maximum ennyi extra növényt enged a mod összesen.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config4 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 10f); PlantSpacing = ConfigFileExtensions.BindConfig(config4, "Elhelyezés", "PlantSpacing", 1.15f, "Régi/fallback távolság. Csak akkor használja, ha az aktuálisan ültetett növényből nem tud minimum helyet kiolvasni.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); UseSelectedPlantRequiredSpace = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Elhelyezés", "UseSelectedPlantRequiredSpace", true, "Ha igaz, a rács távolságát az aktuálisan kiválasztott növény Plant komponenséből / collider méretéből számolja, nem egy fix közös értékből.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config5 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 3f); PlantRequiredSpaceMultiplier = ConfigFileExtensions.BindConfig(config5, "Elhelyezés", "PlantRequiredSpaceMultiplier", 1.05f, "Szorzó az aktuális növény minimum helyigényére. 1.05 = kis biztonsági ráhagyás.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config6 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 5f); MinimumSmallPlantSpacing = ConfigFileExtensions.BindConfig(config6, "Elhelyezés", "MinimumSmallPlantSpacing", 1.15f, "Minimum rácstávolság kis növényeknél, ha a játékból kiolvasott érték ennél kisebb lenne.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config7 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f); MinimumTreePlantSpacing = ConfigFileExtensions.BindConfig(config7, "Elhelyezés", "MinimumTreePlantSpacing", 4f, "Minimum rácstávolság fáknál/csemetéknél, ha a játékból kiolvasott érték ennél kisebb lenne.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); RequireCultivatorEquipped = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Szabályok", "RequireCultivatorEquipped", true, "Ha igaz, a mod csak akkor működik, ha a játékosnál Cultivator van használatban.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); AllowedPrefabKeywords = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Szűrő", "AllowedPrefabKeywords", "carrot,turnip,onion,seed,seedling,sapling,beech,birch,fir,pine,jotunpuffs,magecap,barley,flax", "Vesszővel elválasztott kulcsszavak. Csak az ezekre illeszkedő ültethető ghostokra aktiválódik a mod.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); EnableSnapping = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Snapping", "EnableSnapping", false, "Régi X/Z rács-snapping kapcsoló. Alapból kikapcsolva, mert a 3x3 previewt szétcsúsztathatja vagy eltolhatja a vanilla középső ghosthoz képest.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config8 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 5f); SnapStep = ConfigFileExtensions.BindConfig(config8, "Snapping", "SnapStep", 0.5f, "A snapping rácslépése méterben. Például 0.5 = félméteres igazítás.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); SnapUseGhostRight = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Snapping", "SnapUseGhostRight", true, "Ha igaz, az extra növények az aktuális placement ghost jobb oldali tengelye mentén sorakoznak fel. Ha hamis, a játékos jobb oldali tengelyét használja.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); PreviewExtraPlants = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Preview", "PreviewExtraPlants", true, "Ha igaz, ültetés előtt megjelennek az extra ghostok.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); OnlyLocalPreview = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Preview", "OnlyLocalPreview", true, "Ha igaz, a preview csak a helyi játékosnak jelenik meg.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ExtraPlacementRequiresFreeSpace = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Szabályok", "ExtraPlacementRequiresFreeSpace", true, "Ha igaz, az extra növény csak akkor kerül lerakásra, ha a célpozíció szabadnak látszik.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); GroundSnapToTerrain = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Snapping", "GroundSnapToTerrain", true, "Ha igaz, az extra preview és lerakás a talaj felszínére igazodik, nem csak X/Z rácsra.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config9 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f); GroundSnapRayHeight = ConfigFileExtensions.BindConfig(config9, "Snapping", "GroundSnapRayHeight", 10f, "Milyen magasról induljon a talajra igazító raycast az extra pozícióknál.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); UseSquarePattern = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Elhelyezés", "UseSquarePattern", true, "Ha igaz, az extra ültetési pontok négyzetes mintában helyezkednek el az eredeti pont körül.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); UseGroundRaySnap = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Snapping", "UseGroundRaySnap", true, "Ha igaz, a számolt extra pontokat lefelé sugárvetéssel a talajhoz igazítja.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config10 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 20f); GroundRayStartHeight = ConfigFileExtensions.BindConfig(config10, "Snapping", "GroundRayStartHeight", 3f, "Ennyivel a célpont fölül indul a lefelé sugárvetés a talaj megkereséséhez.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config11 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f); GroundRayDistance = ConfigFileExtensions.BindConfig(config11, "Snapping", "GroundRayDistance", 10f, "A lefelé sugárvetés maximális hossza a talaj megkereséséhez.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); RequireRealGroundHit = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Snapping", "RequireRealGroundHit", true, "Ha igaz, az extra ghost/növény csak akkor jelenik meg és csak akkor kerül lerakásra, ha a lefelé raycast valódi terepet/Heightmap-et talál. Kerítésre, játékosra, itemre nem snapel.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config12 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1f); GroundNormalMinY = ConfigFileExtensions.BindConfig(config12, "Snapping", "GroundNormalMinY", 0.55f, "Minimum talaj-normál Y érték. 1 = vízszintes, 0.55 körül még lejtős talajt enged, de falat/kerítést nem.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); CheckExistingPlants = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Szabályok", "CheckExistingPlants", true, "Ha igaz, az extra ghost és extra ültetés figyeli a már elültetett növényeket is, és pirosra vált / kihagyja a túl közeli pontokat.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config13 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 2f); ExistingPlantCheckMultiplier = ConfigFileExtensions.BindConfig(config13, "Szabályok", "ExistingPlantCheckMultiplier", 0.95f, "A kiválasztott növény spacing értékének ekkora részén belül már túl közelinek számít egy meglévő növény. 0.95 = majdnem teljes spacing.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); CheckNearbyObjectsForGrowthSpace = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Szabályok", "CheckNearbyObjectsForGrowthSpace", true, "Ha igaz, a preview és az extra ültetés nem csak meglévő növényeket figyel, hanem építményeket és tereptárgyakat is a növekedési hely körül. Így nem enged túl közel kerítéshez, falhoz, ládához stb.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile config14 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 2f); NearbyObjectCheckMultiplier = ConfigFileExtensions.BindConfig(config14, "Szabályok", "NearbyObjectCheckMultiplier", 0.55f, "A kiválasztott növény spacing értékének ekkora részén belül számít túl közelinek egy építmény vagy tereptárgy. Kis növénynél 0.55 kb. 0.63m, fáknál arányosan nagyobb.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); DebugEnabled = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Debug", "DebugEnabled", false, "Fő debug kapcsoló. Erősen részletes naplózást engedélyez.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); DebugGhostUpdate = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Debug", "DebugGhostUpdate", true, "Részletes log az előnézeti ghost frissítésről.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); DebugPlacement = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Debug", "DebugPlacement", true, "Részletes log a tényleges extra lerakásról.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); DebugConfigSync = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Debug", "DebugConfigSync", true, "Részletes log a Jotunn config sync eseményekről.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); DebugShowPositionDetails = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Debug", "DebugShowPositionDetails", true, "Kiírja a számolt pozíciókat, snap előtti és snap utáni adatokat.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); DebugDumpConfigOnLoad = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Debug", "DebugDumpConfigOnLoad", true, "A mod indulásakor kiírja az összes fontos konfig értéket.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); DebugDumpConfigOnSync = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Debug", "DebugDumpConfigOnSync", true, "Config sync után kiírja az összes fontos konfig értéket.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); DebugDumpAdminState = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Debug", "DebugDumpAdminState", true, "Kiírja a Jotunn által ismert admin állapotot és annak változásait.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); DebugCollisionCheck = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "Debug", "DebugCollisionCheck", true, "Kiírja a helyfoglalás-ellenőrzés találatait az extra lerakásoknál.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); } private void HookJotunnEvents() { SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized; SynchronizationManager.OnAdminStatusChanged += OnAdminStatusChanged; } private void OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs args) { if (DebugEnabled.Value && DebugConfigSync.Value) { Log.LogInfo((object)"[CFGSYNC] =================================================="); Log.LogInfo((object)"[CFGSYNC] Konfig szinkron esemény érkezett."); Log.LogInfo((object)("[CFGSYNC] InitialSynchronization = " + args.InitialSynchronization)); Log.LogInfo((object)("[CFGSYNC] PlayerIsAdmin = " + SafeGetAdminState())); Log.LogInfo((object)"[CFGSYNC] =================================================="); if (DebugDumpConfigOnSync.Value) { DumpAllConfig("OnConfigurationSynchronized"); } } } private void OnAdminStatusChanged() { if (DebugEnabled.Value && DebugDumpAdminState.Value) { Log.LogInfo((object)"[ADMIN] ================================================"); Log.LogInfo((object)"[ADMIN] Admin státusz változás érkezett."); Log.LogInfo((object)("[ADMIN] PlayerIsAdmin = " + SafeGetAdminState())); Log.LogInfo((object)"[ADMIN] ================================================"); } } internal static bool SafeGetAdminState() { try { return SynchronizationManager.Instance != null && SynchronizationManager.Instance.PlayerIsAdmin; } catch { return false; } } internal static void DumpAllConfig(string source) { Log.LogInfo((object)("[DUMP][" + source + "] ------------------------------")); Log.LogInfo((object)("[DUMP][" + source + "] Enabled = " + Enabled.Value)); Log.LogInfo((object)("[DUMP][" + source + "] RequiredFarmingSkill = " + RequiredFarmingSkill.Value)); Log.LogInfo((object)("[DUMP][" + source + "] ExtraPlantsAtThreshold = " + ExtraPlantsAtThreshold.Value)); Log.LogInfo((object)("[DUMP][" + source + "] MaxExtraPlants = " + MaxExtraPlants.Value)); Log.LogInfo((object)("[DUMP][" + source + "] PlantSpacing = " + PlantSpacing.Value)); Log.LogInfo((object)("[DUMP][" + source + "] UseSelectedPlantRequiredSpace = " + UseSelectedPlantRequiredSpace.Value)); Log.LogInfo((object)("[DUMP][" + source + "] PlantRequiredSpaceMultiplier = " + PlantRequiredSpaceMultiplier.Value)); Log.LogInfo((object)("[DUMP][" + source + "] MinimumSmallPlantSpacing = " + MinimumSmallPlantSpacing.Value)); Log.LogInfo((object)("[DUMP][" + source + "] MinimumTreePlantSpacing = " + MinimumTreePlantSpacing.Value)); Log.LogInfo((object)("[DUMP][" + source + "] RequireCultivatorEquipped = " + RequireCultivatorEquipped.Value)); Log.LogInfo((object)("[DUMP][" + source + "] AllowedPrefabKeywords = " + AllowedPrefabKeywords.Value)); Log.LogInfo((object)("[DUMP][" + source + "] EnableSnapping = " + EnableSnapping.Value)); Log.LogInfo((object)("[DUMP][" + source + "] SnapStep = " + SnapStep.Value)); Log.LogInfo((object)("[DUMP][" + source + "] SnapUseGhostRight = " + SnapUseGhostRight.Value)); Log.LogInfo((object)("[DUMP][" + source + "] PreviewExtraPlants = " + PreviewExtraPlants.Value)); Log.LogInfo((object)("[DUMP][" + source + "] OnlyLocalPreview = " + OnlyLocalPreview.Value)); Log.LogInfo((object)("[DUMP][" + source + "] ExtraPlacementRequiresFreeSpace = " + ExtraPlacementRequiresFreeSpace.Value)); Log.LogInfo((object)("[DUMP][" + source + "] GroundSnapToTerrain = " + GroundSnapToTerrain.Value)); Log.LogInfo((object)("[DUMP][" + source + "] GroundSnapRayHeight = " + GroundSnapRayHeight.Value)); Log.LogInfo((object)("[DUMP][" + source + "] CheckExistingPlants = " + CheckExistingPlants.Value)); Log.LogInfo((object)("[DUMP][" + source + "] ExistingPlantCheckMultiplier = " + ExistingPlantCheckMultiplier.Value)); Log.LogInfo((object)("[DUMP][" + source + "] CheckNearbyObjectsForGrowthSpace = " + CheckNearbyObjectsForGrowthSpace.Value)); Log.LogInfo((object)("[DUMP][" + source + "] NearbyObjectCheckMultiplier = " + NearbyObjectCheckMultiplier.Value)); Log.LogInfo((object)("[DUMP][" + source + "] PlayerIsAdmin = " + SafeGetAdminState())); Log.LogInfo((object)("[DUMP][" + source + "] ------------------------------")); } internal static void LogDebug(string msg) { if (DebugEnabled.Value) { Log.LogInfo((object)("[DEBUG] " + msg)); } } internal static void LogGhost(string msg) { if (DebugEnabled.Value && DebugGhostUpdate.Value) { Log.LogInfo((object)("[GHOST] " + msg)); } } internal static void LogPlacement(string msg) { if (DebugEnabled.Value && DebugPlacement.Value) { Log.LogInfo((object)("[PLACE] " + msg)); } } internal static string CleanName(string name) { return string.IsNullOrEmpty(name) ? string.Empty : name.Replace("(Clone)", "").Trim(); } internal static string[] SplitKeywords(string raw) { if (string.IsNullOrWhiteSpace(raw)) { return new string[0]; } string[] array = raw.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); List list = new List(); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (!string.IsNullOrWhiteSpace(text)) { list.Add(text); } } return list.ToArray(); } internal static string Vec(Vector3 v) { return "(" + v.x.ToString("0.000") + ", " + v.y.ToString("0.000") + ", " + v.z.ToString("0.000") + ")"; } internal static GameObject GetPlacementGhost(Player player) { if ((Object)(object)player == (Object)null || PlacementGhostField == null) { return null; } try { object? value = PlacementGhostField.GetValue(player); return (GameObject)((value is GameObject) ? value : null); } catch (Exception ex) { Log.LogWarning((object)("[GHOST] Nem sikerült kiolvasni az m_placementGhost mezőt: " + ex)); return null; } } internal static ItemData GetRightItemSafe(Player player) { if ((Object)(object)player == (Object)null) { return null; } try { FieldInfo fieldInfo = typeof(Humanoid).GetField("m_rightItem", AllInstance) ?? typeof(Player).GetField("m_rightItem", AllInstance); if (fieldInfo != null) { object? value = fieldInfo.GetValue(player); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val != null) { return val; } } } catch { } try { MethodInfo methodInfo = typeof(Humanoid).GetMethod("GetCurrentWeapon", AllInstance) ?? typeof(Player).GetMethod("GetCurrentWeapon", AllInstance); if (methodInfo != null) { object? obj2 = methodInfo.Invoke(player, null); ItemData val2 = (ItemData)((obj2 is ItemData) ? obj2 : null); if (val2 != null) { return val2; } } } catch { } return null; } internal static bool HasCultivatorEquipped(Player player, GameObject placementGhost) { if ((Object)(object)player == (Object)null) { return false; } if (!RequireCultivatorEquipped.Value) { return true; } ItemData rightItemSafe = GetRightItemSafe(player); string text = ((rightItemSafe != null && rightItemSafe.m_shared != null) ? (rightItemSafe.m_shared.m_name ?? string.Empty) : string.Empty); string text2 = ((rightItemSafe != null && (Object)(object)rightItemSafe.m_dropPrefab != (Object)null) ? (((Object)rightItemSafe.m_dropPrefab).name ?? string.Empty) : string.Empty); string text3 = (((Object)(object)placementGhost != (Object)null) ? CleanName(((Object)placementGhost).name) : string.Empty); if (text3.StartsWith("HH_", StringComparison.OrdinalIgnoreCase)) { return false; } bool flag = text.IndexOf("cultivator", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("kultiv", StringComparison.OrdinalIgnoreCase) >= 0 || text.Equals("$item_cultivator", StringComparison.OrdinalIgnoreCase) || text2.IndexOf("cultivator", StringComparison.OrdinalIgnoreCase) >= 0; bool flag2 = text3.IndexOf("cultivate", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("sapling", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("seed", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("carrot", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("turnip", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("onion", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("barley", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("flax", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("beech", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("birch", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("fir", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("pine", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("jotunpuffs", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("magecap", StringComparison.OrdinalIgnoreCase) >= 0; bool result = flag || flag2; if (DebugEnabled.Value && DebugGhostUpdate.Value) { Log.LogInfo((object)("[GHOST] HasCultivatorEquipped -> " + result + " | sharedName=" + text + " | dropName=" + text2 + " | ghostName=" + text3)); } return result; } internal static bool IsPlantPlacement(GameObject placementGhost) { if ((Object)(object)placementGhost == (Object)null) { return false; } string text = CleanName(((Object)placementGhost).name); if (text.StartsWith("HH_", StringComparison.OrdinalIgnoreCase)) { return false; } string text2 = text.ToLowerInvariant(); return text2.Contains("sapling") || text2.Contains("seed") || text2.Contains("carrot") || text2.Contains("turnip") || text2.Contains("onion") || text2.Contains("barley") || text2.Contains("flax") || text2.Contains("beech") || text2.Contains("birch") || text2.Contains("fir") || text2.Contains("pine") || text2.Contains("jotunpuffs") || text2.Contains("magecap"); } internal static bool IsPlantableGhost(GameObject ghost) { if ((Object)(object)ghost == (Object)null) { return false; } string text = CleanName(((Object)ghost).name); if (text.StartsWith("HH_")) { return false; } string text2 = text; if (string.IsNullOrWhiteSpace(text2)) { return false; } string[] array = SplitKeywords(AllowedPrefabKeywords.Value); for (int i = 0; i < array.Length; i++) { if (text2.IndexOf(array[i], StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } internal static bool TryGetFarmingSkillType(out SkillType skillType) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected I4, but got Unknown skillType = (SkillType)0; try { skillType = (SkillType)(int)(SkillType)Enum.Parse(typeof(SkillType), "Farming"); return true; } catch (Exception ex) { Log.LogWarning((object)("[SKILL] Nem sikerült feloldani a Skills.SkillType.Farming enumot: " + ex)); return false; } } internal static float GetFarmingLevel(Player player) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return 0f; } if (!TryGetFarmingSkillType(out var skillType)) { return 0f; } try { return ((Character)player).GetSkillLevel(skillType); } catch (Exception ex) { Log.LogWarning((object)("[SKILL] Nem sikerült lekérni a Farming skill szintet: " + ex)); return 0f; } } internal static int GetExtraPlantCount(Player player) { float farmingLevel = GetFarmingLevel(player); int num = Mathf.Max(0, RequiredFarmingSkill.Value); if (farmingLevel < (float)num) { if (DebugEnabled.Value && DebugGhostUpdate.Value) { Log.LogInfo((object)("[COUNT] Farming skill túl alacsony. current=" + farmingLevel + " required=" + num)); } return 0; } int num2 = Mathf.Max(0, ExtraPlantsAtThreshold.Value); if (farmingLevel > (float)num) { int num3 = Mathf.FloorToInt((farmingLevel - (float)num) / 20f); num2 += num3; } num2 = Mathf.Clamp(num2, 0, Mathf.Max(0, MaxExtraPlants.Value)); if (DebugEnabled.Value && (DebugGhostUpdate.Value || DebugPlacement.Value)) { Log.LogInfo((object)("[COUNT] Farming=" + farmingLevel + " required=" + num + " -> extra=" + num2)); } return num2; } internal static Piece GetSelectedPieceSafe(Player player) { if ((Object)(object)player == (Object)null) { return null; } try { FieldInfo field = typeof(Player).GetField("m_buildPieces", AllInstance); PieceTable val = (PieceTable)((field != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null) { return null; } MethodInfo method = typeof(PieceTable).GetMethod("GetSelectedPiece", AllInstance, null, Type.EmptyTypes, null); if (method != null) { object? obj = method.Invoke(val, null); Piece val2 = (Piece)((obj is Piece) ? obj : null); if ((Object)(object)val2 != (Object)null) { return val2; } } FieldInfo field2 = typeof(PieceTable).GetField("m_selectedPiece", AllInstance); if (field2 != null) { object? value = field2.GetValue(val); Piece val3 = (Piece)((value is Piece) ? value : null); if ((Object)(object)val3 != (Object)null) { return val3; } } } catch (Exception ex) { if (DebugEnabled.Value && DebugGhostUpdate.Value) { Log.LogInfo((object)("[SELECTED] Nem sikerült kiolvasni az aktuális Piece-t: " + ex.Message)); } } return null; } internal static string GetPlantKey(GameObject placementGhost, Piece selectedPiece) { string text = (((Object)(object)selectedPiece != (Object)null && (Object)(object)((Component)selectedPiece).gameObject != (Object)null) ? CleanName(((Object)((Component)selectedPiece).gameObject).name) : string.Empty); string text2 = (((Object)(object)placementGhost != (Object)null) ? CleanName(((Object)placementGhost).name) : string.Empty); return text + "|" + text2; } internal static bool IsSmallPlantName(string name) { if (string.IsNullOrWhiteSpace(name)) { return false; } string text = name.ToLowerInvariant(); return text.Contains("carrot") || text.Contains("turnip") || text.Contains("onion") || text.Contains("barley") || text.Contains("flax") || text.Contains("jotunpuffs") || text.Contains("magecap"); } internal static bool IsTreePlantName(string name) { if (string.IsNullOrWhiteSpace(name)) { return false; } string text = name.ToLowerInvariant(); return text.Contains("beech") || text.Contains("birch") || text.Contains("fir") || text.Contains("pine") || text.Contains("oak") || text.Contains("yggdrasil"); } internal static float GetExplicitPlantSpacingByName(string name) { if (string.IsNullOrWhiteSpace(name)) { return 0f; } string name2 = name.ToLowerInvariant(); if (IsSmallPlantName(name2)) { return Mathf.Max(0.2f, MinimumSmallPlantSpacing.Value); } if (IsTreePlantName(name2)) { return Mathf.Max(1f, MinimumTreePlantSpacing.Value); } return 0f; } internal static float ReadPlantRequiredSpace(GameObject plantObject) { //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: 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_0179: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)plantObject == (Object)null) { return 0f; } float num = 0f; Plant componentInChildren = plantObject.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { FieldInfo[] fields = typeof(Plant).GetFields(AllInstance); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType != typeof(float)) { continue; } string text = fieldInfo.Name.ToLowerInvariant(); if (!text.Contains("radius") && !text.Contains("space") && !text.Contains("distance")) { continue; } try { float num2 = (float)fieldInfo.GetValue(componentInChildren); if (num2 > num && num2 >= 0.05f && num2 <= 20f) { num = num2; } } catch { } } } if (num <= 0f) { Collider[] componentsInChildren = plantObject.GetComponentsInChildren(true); foreach (Collider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !val.isTrigger) { Bounds bounds = val.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num3 = Mathf.Max(size.x, size.z); if (num3 > num && num3 >= 0.05f && num3 <= 20f) { num = num3; } } } } return num; } internal static float GetSpacingForSelectedPlant(Player player, GameObject sourceGhost, Piece selectedPiece) { float num = Mathf.Max(0.2f, PlantSpacing.Value); if (!UseSelectedPlantRequiredSpace.Value) { return num; } GameObject val = (((Object)(object)selectedPiece != (Object)null) ? ((Component)selectedPiece).gameObject : null); string text = (((Object)(object)val != (Object)null) ? CleanName(((Object)val).name) : string.Empty); string text2 = (((Object)(object)sourceGhost != (Object)null) ? CleanName(((Object)sourceGhost).name) : string.Empty); string name = text + "|" + text2; float explicitPlantSpacingByName = GetExplicitPlantSpacingByName(name); if (explicitPlantSpacingByName > 0f) { if (DebugEnabled.Value && (DebugGhostUpdate.Value || DebugPlacement.Value)) { Log.LogInfo((object)("[SPACING] explicit selected=" + text + " | ghost=" + text2 + " | finalSpacing=" + explicitPlantSpacingByName.ToString("0.###"))); } return Mathf.Clamp(explicitPlantSpacingByName, 0.2f, 10f); } float num2 = ReadPlantRequiredSpace(val); float num3 = Mathf.Max(0.5f, PlantRequiredSpaceMultiplier.Value); float num4 = ((num2 > 0f) ? (num2 * num3) : num); num4 = Mathf.Max(num4, num); num4 = Mathf.Clamp(num4, 0.2f, 10f); if (DebugEnabled.Value && (DebugGhostUpdate.Value || DebugPlacement.Value)) { Log.LogInfo((object)("[SPACING] fallback selected=" + text + " | ghost=" + text2 + " | plantRequired=" + num2.ToString("0.###") + " | multiplier=" + num3.ToString("0.###") + " | finalSpacing=" + num4.ToString("0.###"))); } return num4; } internal static float SnapValue(float value, float step) { return Mathf.Round(value / step) * step; } internal static Vector3 ApplySnapping(Vector3 position) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0049: 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_0012: 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_0051: Unknown result type (might be due to invalid IL or missing references) if (!EnableSnapping.Value) { return position; } float step = Mathf.Max(0.05f, SnapStep.Value); return new Vector3(SnapValue(position.x, step), position.y, SnapValue(position.z, step)); } internal static bool IsValidPlantingGroundHit(RaycastHit hit) { //IL_001c: 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_0089: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)((RaycastHit)(ref hit)).collider == (Object)null) { return false; } if (((RaycastHit)(ref hit)).normal.y < Mathf.Clamp(GroundNormalMinY.Value, 0.1f, 1f)) { if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[GROUND] Elutasítva: túl meredek felület. collider=" + ((Object)((RaycastHit)(ref hit)).collider).name + " normalY=" + ((RaycastHit)(ref hit)).normal.y.ToString("0.###"))); } return false; } GameObject gameObject = ((Component)((RaycastHit)(ref hit)).collider).gameObject; string text = (((Object)(object)gameObject != (Object)null) ? (((Object)gameObject).name ?? string.Empty) : string.Empty); string text2 = text.ToLowerInvariant(); if ((Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent() != (Object)null) { return true; } if (text2.Contains("terrain") || text2.Contains("heightmap") || text2.Contains("ground")) { return true; } if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[GROUND] Elutasítva: nem valódi talaj. collider=" + text + " layer=" + LayerMask.LayerToName(gameObject.layer))); } return false; } internal static bool TrySnapToGround(Vector3 position, out Vector3 snapped) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: 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_0039: 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) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) snapped = position; if (!GroundSnapToTerrain.Value) { return true; } float num = Mathf.Max(1f, GroundSnapRayHeight.Value); Vector3 val = position + Vector3.up * num; float num2 = num * 2f + 20f; RaycastHit[] array = Physics.RaycastAll(new Ray(val, Vector3.down), num2, -1, (QueryTriggerInteraction)1); if (array == null || array.Length == 0) { if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[GROUND] Nincs raycast találat: " + Vec(position))); } return !RequireRealGroundHit.Value; } Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); for (int i = 0; i < array.Length; i++) { RaycastHit hit = array[i]; if (IsValidPlantingGroundHit(hit)) { snapped = new Vector3(position.x, ((RaycastHit)(ref hit)).point.y, position.z); if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[GROUND] valid hit=" + (((Object)(object)((RaycastHit)(ref hit)).collider != (Object)null) ? ((Object)((Component)((RaycastHit)(ref hit)).collider).gameObject).name : "null") + " | from=" + Vec(position) + " -> " + Vec(snapped))); } return true; } } if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[GROUND] Nem talált valódi talajt ezen a ponton: " + Vec(position))); } return !RequireRealGroundHit.Value; } internal static Vector3 SnapToGround(Vector3 position) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!UseGroundRaySnap.Value) { return position; } if (TrySnapToGround(position, out var snapped)) { return snapped; } return position; } internal static List BuildOffsetPattern(int count) { List list = new List(); int num = 1; while (list.Count < count) { list.Add(num); if (list.Count >= count) { break; } list.Add(-num); num++; } return list; } internal static bool IsIgnoredPlacementCollider(Collider hit) { if ((Object)(object)hit == (Object)null || (Object)(object)((Component)hit).gameObject == (Object)null) { return true; } string text = ((Object)((Component)hit).gameObject).name ?? string.Empty; if (text.Length == 0) { return true; } return text.IndexOf("cultivated", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("ghost", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("vfx", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("terrain", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("PlantingPreview", StringComparison.OrdinalIgnoreCase) >= 0; } internal static bool IsExistingPlantCollider(Collider hit) { if ((Object)(object)hit == (Object)null || (Object)(object)((Component)hit).gameObject == (Object)null) { return false; } GameObject gameObject = ((Component)hit).gameObject; string text = ((Object)gameObject).name ?? string.Empty; if (text.IndexOf("PlantingPreview", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (text.IndexOf("ghost", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (text.IndexOf("vfx", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (text.IndexOf("terrain", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return false; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return true; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null && (IsSmallPlantName(text) || IsTreePlantName(text) || IsPlantPlacement(gameObject))) { return true; } if (IsSmallPlantName(text) || IsTreePlantName(text) || IsPlantPlacement(gameObject)) { return true; } Transform root = gameObject.transform.root; if ((Object)(object)root != (Object)null) { string name = ((Object)((Component)root).gameObject).name ?? string.Empty; if (IsSmallPlantName(name) || IsTreePlantName(name) || IsPlantPlacement(((Component)root).gameObject)) { return true; } } return false; } internal static bool IsInsidePreviewRoot(Collider hit) { if ((Object)(object)hit == (Object)null) { return false; } Transform val = ((Component)hit).transform; while ((Object)(object)val != (Object)null) { string text = (((Object)(object)((Component)val).gameObject != (Object)null) ? (((Object)((Component)val).gameObject).name ?? string.Empty) : string.Empty); if (text.IndexOf("PlantingPreview", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } val = val.parent; } return false; } internal static bool ExistingPlantIsOutsideOnThisGridEdge(Vector3 candidatePosition, Vector3 plantPosition, Vector2Int cell, Vector3 right, Vector3 forward) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) Vector3 val = plantPosition - candidatePosition; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { return true; } bool flag = false; bool flag2 = false; if (((Vector2Int)(ref cell)).x > 0) { flag = true; flag2 |= Vector3.Dot(val, right) > 0.05f; } else if (((Vector2Int)(ref cell)).x < 0) { flag = true; flag2 |= Vector3.Dot(val, right) < -0.05f; } if (((Vector2Int)(ref cell)).y > 0) { flag = true; flag2 |= Vector3.Dot(val, forward) > 0.05f; } else if (((Vector2Int)(ref cell)).y < 0) { flag = true; flag2 |= Vector3.Dot(val, forward) < -0.05f; } return !flag || flag2; } internal static bool IsNearbyObjectBlockingPlantGrowth(Collider hit) { if ((Object)(object)hit == (Object)null || (Object)(object)((Component)hit).gameObject == (Object)null) { return false; } if (IsInsidePreviewRoot(hit)) { return false; } if (IsIgnoredPlacementCollider(hit)) { return false; } if (IsExistingPlantCollider(hit)) { return false; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return false; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return false; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return false; } GameObject gameObject = ((Component)hit).gameObject; string text = ((Object)gameObject).name ?? string.Empty; string text2 = text.ToLowerInvariant(); if (text2.Contains("heightmap") || text2.Contains("terrain") || text2.Contains("ground")) { return false; } if (text2.Contains("water")) { return false; } if (text2.Contains("leviathan")) { return false; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return true; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return true; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return true; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return true; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return true; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return true; } return true; } internal static bool HasNearbyObjectTooCloseForGrowth(Vector3 position, float spacing) { //IL_0044: 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) if (!CheckNearbyObjectsForGrowthSpace.Value) { return false; } float num = Mathf.Clamp(spacing * Mathf.Clamp(NearbyObjectCheckMultiplier.Value, 0.1f, 2f), 0.1f, 10f); Collider[] array = Physics.OverlapSphere(position, num, -1, (QueryTriggerInteraction)1); foreach (Collider val in array) { if (IsNearbyObjectBlockingPlantGrowth(val)) { if (DebugEnabled.Value && DebugCollisionCheck.Value) { string text = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : "null"); Log.LogInfo((object)("[OBJECT BLOCK] Tereptárgy/építmény túl közel a növekedési helyhez. pos=" + Vec(position) + " radius=" + num.ToString("0.###") + " hit=" + text)); } return true; } } return false; } internal static bool HasExistingPlantTooClose(Vector3 position, float spacing) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) return HasExistingPlantTooCloseOnGridEdge(position, spacing, Vector2Int.zero, Vector3.right, Vector3.forward, useEdgeDirection: false); } internal static bool HasExistingPlantTooCloseOnGridEdge(Vector3 position, float spacing, Vector2Int cell, Vector3 right, Vector3 forward, bool useEdgeDirection) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_00ab: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) if (!CheckExistingPlants.Value) { return false; } float num = Mathf.Clamp(spacing * Mathf.Clamp(ExistingPlantCheckMultiplier.Value, 0.2f, 2f), 0.2f, 10f); Collider[] array = Physics.OverlapSphere(position, num, -1, (QueryTriggerInteraction)1); foreach (Collider val in array) { if (IsInsidePreviewRoot(val) || !IsExistingPlantCollider(val)) { continue; } Vector3 plantPosition = (((Object)(object)((Component)val).transform != (Object)null) ? ((Component)val).transform.position : position); Vector2Int val2; if (useEdgeDirection && !ExistingPlantIsOutsideOnThisGridEdge(position, plantPosition, cell, right, forward)) { if (DebugEnabled.Value && DebugCollisionCheck.Value) { string text = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : "null"); ManualLogSource log = Log; string[] obj = new string[6] { "[PLANT EDGE IGNORE] Meglévő növény közel van, de nem ezen a rács-szélen. cell=", null, null, null, null, null }; val2 = cell; obj[1] = ((object)(Vector2Int)(ref val2)).ToString(); obj[2] = " pos="; obj[3] = Vec(position); obj[4] = " hit="; obj[5] = text; log.LogInfo((object)string.Concat(obj)); } continue; } if (DebugEnabled.Value && DebugCollisionCheck.Value) { string text2 = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : "null"); ManualLogSource log2 = Log; string[] obj2 = new string[8] { "[PLANT BLOCK] Meglévő növény túl közel a rács szélén. cell=", null, null, null, null, null, null, null }; val2 = cell; obj2[1] = ((object)(Vector2Int)(ref val2)).ToString(); obj2[2] = " pos="; obj2[3] = Vec(position); obj2[4] = " radius="; obj2[5] = num.ToString("0.###"); obj2[6] = " hit="; obj2[7] = text2; log2.LogInfo((object)string.Concat(obj2)); } return true; } return false; } internal static bool CanPlaceAt(Vector3 position, float spacing) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) return CanPlaceAt(position, spacing, Vector2Int.zero, Vector3.right, Vector3.forward, useEdgeDirection: false); } internal static bool CanPlaceAt(Vector3 position, float spacing, Vector2Int cell, Vector3 right, Vector3 forward, bool useEdgeDirection) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) if (!ExtraPlacementRequiresFreeSpace.Value) { if (DebugEnabled.Value && DebugCollisionCheck.Value) { Log.LogInfo((object)("[COLLISION] Ellenőrzés kikapcsolva. Pozíció automatikusan elfogadva: " + Vec(position))); } return true; } if (HasExistingPlantTooCloseOnGridEdge(position, spacing, cell, right, forward, useEdgeDirection)) { if (DebugEnabled.Value && DebugCollisionCheck.Value) { Log.LogInfo((object)("[COLLISION] Eredmény pozíción " + Vec(position) + " -> blocked=true, reason=existing plant edge")); } return false; } if (HasNearbyObjectTooCloseForGrowth(position, spacing)) { if (DebugEnabled.Value && DebugCollisionCheck.Value) { Log.LogInfo((object)("[COLLISION] Eredmény pozíción " + Vec(position) + " -> blocked=true, reason=nearby object growth space")); } return false; } Collider[] array = Physics.OverlapSphere(position, 0.18f, -1, (QueryTriggerInteraction)1); bool flag = false; foreach (Collider val in array) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) { continue; } string text = ((Object)((Component)val).gameObject).name ?? string.Empty; if (text.Length != 0) { bool flag2 = IsIgnoredPlacementCollider(val); if (DebugEnabled.Value && DebugCollisionCheck.Value) { Log.LogInfo((object)("[COLLISION] Hit: " + text + " | ignore=" + flag2 + " | pos=" + Vec(position))); } if (!flag2) { flag = true; } } } if (DebugEnabled.Value && DebugCollisionCheck.Value) { Log.LogInfo((object)("[COLLISION] Eredmény pozíción " + Vec(position) + " -> blocked=" + flag)); } return !flag; } internal static bool CanPreviewPlaceAt(Vector3 position, float spacing) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) return CanPreviewPlaceAt(position, spacing, Vector2Int.zero, Vector3.right, Vector3.forward, useEdgeDirection: false); } internal static bool CanPreviewPlaceAt(Vector3 position, float spacing, Vector2Int cell, Vector3 right, Vector3 forward, bool useEdgeDirection) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!ExtraPlacementRequiresFreeSpace.Value) { return true; } if (HasExistingPlantTooCloseOnGridEdge(position, spacing, cell, right, forward, useEdgeDirection)) { return false; } if (HasNearbyObjectTooCloseForGrowth(position, spacing)) { return false; } Collider[] array = Physics.OverlapSphere(position, 0.18f, -1, (QueryTriggerInteraction)1); foreach (Collider val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && !IsIgnoredPlacementCollider(val)) { return false; } } return true; } internal static Quaternion GetPreviewRotation(GameObject sourceGhost) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0042: 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_0045: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_0051: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (_hasStickyRotation) { _lastGoodPreviewRotation = _stickyRotation; _hasLastGoodPreviewRotation = true; return _stickyRotation; } if ((Object)(object)sourceGhost != (Object)null) { Quaternion rotation = sourceGhost.transform.rotation; Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles; if (rotation != Quaternion.identity || eulerAngles.y > 0.01f) { _lastGoodPreviewRotation = rotation; _hasLastGoodPreviewRotation = true; return rotation; } } if (_hasLastGoodPreviewRotation) { return _lastGoodPreviewRotation; } return Quaternion.identity; } internal static int LimitExtraCountByResources(Player player, Piece piece, int requestedExtra, bool reserveVanillaCenterCost) { if (requestedExtra <= 0) { return 0; } if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null || piece.m_resources == null || piece.m_resources.Length == 0) { return requestedExtra; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return 0; } int num = requestedExtra; for (int i = 0; i < piece.m_resources.Length; i++) { Requirement val = piece.m_resources[i]; if (val != null && !((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; int num2 = inventory.CountItems(name, -1, true); if (reserveVanillaCenterCost) { num2 -= val.m_amount; } int num3 = Mathf.Max(0, num2) / val.m_amount; num = Mathf.Min(num, num3); } } return Mathf.Clamp(num, 0, requestedExtra); } internal static List CalculateExtraPositions(Player player, GameObject sourceGhost, Piece selectedPiece) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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) //IL_013c: 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_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0166: 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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: 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_01e8: 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) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: 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_0425: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_044e: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Unknown result type (might be due to invalid IL or missing references) CachedExtraPositions.Clear(); CachedExtraCells.Clear(); if ((Object)(object)player == (Object)null || (Object)(object)sourceGhost == (Object)null) { LogGhost("CalculateExtraPositions megszakítva: player vagy sourceGhost null."); return CachedExtraPositions; } int extraPlantCount = GetExtraPlantCount(player); extraPlantCount = LimitExtraCountByResources(player, selectedPiece, extraPlantCount, reserveVanillaCenterCost: true); if (extraPlantCount <= 0) { LogGhost("CalculateExtraPositions: extraCount <= 0, nincs extra pozíció."); return CachedExtraPositions; } float spacingForSelectedPlant = GetSpacingForSelectedPlant(player, sourceGhost, selectedPiece); Vector3 position = sourceGhost.transform.position; Quaternion previewRotation = GetPreviewRotation(sourceGhost); Vector3 val = previewRotation * Vector3.right; Vector3 val2 = previewRotation * Vector3.forward; val.y = 0f; val2.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = Vector3.right; } if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f) { val2 = Vector3.forward; } ((Vector3)(ref val)).Normalize(); ((Vector3)(ref val2)).Normalize(); List list = new List(); List list2 = new List(); if (UseSquarePattern.Value) { List list3 = new List { new Vector2Int(1, 1), new Vector2Int(-1, 1), new Vector2Int(1, -1), new Vector2Int(-1, -1), new Vector2Int(1, 0), new Vector2Int(-1, 0), new Vector2Int(0, 1), new Vector2Int(0, -1), new Vector2Int(2, 2), new Vector2Int(-2, 2), new Vector2Int(2, -2), new Vector2Int(-2, -2), new Vector2Int(2, 0), new Vector2Int(-2, 0), new Vector2Int(0, 2), new Vector2Int(0, -2) }; for (int i = 0; i < extraPlantCount && i < list3.Count; i++) { Vector2Int item = list3[i]; list.Add((val * (float)((Vector2Int)(ref item)).x + val2 * (float)((Vector2Int)(ref item)).y) * spacingForSelectedPlant); list2.Add(item); } } else { Vector3 val3; if (!SnapUseGhostRight.Value) { Vector3 right = ((Component)player).transform.right; val3 = ((Vector3)(ref right)).normalized; } else { val3 = val; } Vector3 val4 = val3; List list4 = BuildOffsetPattern(extraPlantCount); for (int j = 0; j < list4.Count; j++) { list.Add(val4 * ((float)list4[j] * spacingForSelectedPlant)); list2.Add(new Vector2Int(list4[j], 0)); } } if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[POS] origin=" + Vec(position) + " spacing=" + spacingForSelectedPlant + " extraCount=" + extraPlantCount + " square=" + UseSquarePattern.Value)); } for (int k = 0; k < list.Count; k++) { Vector3 val5 = position + list[k]; Vector3 val6 = val5; bool flag = false; if (TrySnapToGround(val5, out var snapped)) { val6 = snapped; flag = true; Vector3 val7 = val6; CachedExtraPositions.Add(val7); if (k < list2.Count) { CachedExtraCells.Add(list2[k]); } else { CachedExtraCells.Add(Vector2Int.zero); } if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[POS] idx=" + k + " raw=" + Vec(val5) + " terrainHit=" + flag + " final=" + Vec(val7))); } } else if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[POS] idx=" + k + " kihagyva, mert nincs valódi talaj. raw=" + Vec(val5))); } } return CachedExtraPositions; } internal static GameObject GetBestPreviewVisualSource(Player player, GameObject sourceGhost) { if ((Object)(object)player == (Object)null) { return null; } GameObject placementGhost = GetPlacementGhost(player); if ((Object)(object)placementGhost == (Object)null) { LogGhost("Preview visual source: placementGhost null."); return null; } string text = CleanName(((Object)placementGhost).name); if (text.Equals("cultivate_v2", StringComparison.OrdinalIgnoreCase)) { if ((Object)(object)_lastPlacedPrefabVisualSource != (Object)null) { LogGhost("Preview visual source fallback: utolsó lerakott prefab: " + _lastPlacedPrefabName); return _lastPlacedPrefabVisualSource; } LogGhost("Preview visual source: cultivate_v2 -> nincs még lerakott prefab, skip."); return null; } LogGhost("Preview visual source: placementGhost használva: " + text); return placementGhost; } internal static bool CopyVisualChildrenOnly(GameObject source, GameObject targetRoot) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || (Object)(object)targetRoot == (Object)null) { return false; } bool result = false; Renderer[] componentsInChildren = source.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { GameObject gameObject = ((Component)val).gameObject; GameObject val2; try { val2 = Object.Instantiate(gameObject); } catch (Exception ex) { Log.LogWarning((object)("[GHOST] Renderer child klónozás hiba: " + ex)); continue; } ((Object)val2).name = "PreviewVisual_" + ((Object)gameObject).name; val2.transform.SetParent(targetRoot.transform, false); Transform transform = gameObject.transform; val2.transform.localPosition = source.transform.InverseTransformPoint(transform.position); val2.transform.localRotation = Quaternion.Inverse(source.transform.rotation) * transform.rotation; val2.transform.localScale = transform.lossyScale; StripNonVisualComponents(val2); Renderer[] componentsInChildren2 = val2.GetComponentsInChildren(true); if (componentsInChildren2.Length != 0) { result = true; } else { Object.Destroy((Object)(object)val2); } } } return result; } internal static void StripNonVisualComponents(GameObject go) { if ((Object)(object)go == (Object)null) { return; } MonoBehaviour[] componentsInChildren = go.GetComponentsInChildren(true); foreach (MonoBehaviour val in componentsInChildren) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } Collider[] componentsInChildren2 = go.GetComponentsInChildren(true); for (int j = 0; j < componentsInChildren2.Length; j++) { Object.Destroy((Object)(object)componentsInChildren2[j]); } Rigidbody[] componentsInChildren3 = go.GetComponentsInChildren(true); for (int k = 0; k < componentsInChildren3.Length; k++) { Object.Destroy((Object)(object)componentsInChildren3[k]); } Joint[] componentsInChildren4 = go.GetComponentsInChildren(true); for (int l = 0; l < componentsInChildren4.Length; l++) { Object.Destroy((Object)(object)componentsInChildren4[l]); } ZNetView[] componentsInChildren5 = go.GetComponentsInChildren(true); for (int m = 0; m < componentsInChildren5.Length; m++) { Object.Destroy((Object)(object)componentsInChildren5[m]); } ZSyncTransform[] componentsInChildren6 = go.GetComponentsInChildren(true); for (int n = 0; n < componentsInChildren6.Length; n++) { Object.Destroy((Object)(object)componentsInChildren6[n]); } Piece[] componentsInChildren7 = go.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren7.Length; num++) { Object.Destroy((Object)(object)componentsInChildren7[num]); } WearNTear[] componentsInChildren8 = go.GetComponentsInChildren(true); for (int num2 = 0; num2 < componentsInChildren8.Length; num2++) { Object.Destroy((Object)(object)componentsInChildren8[num2]); } TerrainModifier[] componentsInChildren9 = go.GetComponentsInChildren(true); for (int num3 = 0; num3 < componentsInChildren9.Length; num3++) { Object.Destroy((Object)(object)componentsInChildren9[num3]); } Plant[] componentsInChildren10 = go.GetComponentsInChildren(true); for (int num4 = 0; num4 < componentsInChildren10.Length; num4++) { Object.Destroy((Object)(object)componentsInChildren10[num4]); } Pickable[] componentsInChildren11 = go.GetComponentsInChildren(true); for (int num5 = 0; num5 < componentsInChildren11.Length; num5++) { Object.Destroy((Object)(object)componentsInChildren11[num5]); } } internal static void PreparePreviewVisuals(GameObject go) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00da: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0178: 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_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)go == (Object)null) { return; } Renderer[] componentsInChildren = go.GetComponentsInChildren(true); Color val4 = default(Color); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } val.enabled = true; val.shadowCastingMode = (ShadowCastingMode)0; val.receiveShadows = false; Material[] sharedMaterials = val.sharedMaterials; Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if ((Object)(object)val2 == (Object)null) { array[j] = null; continue; } Material val3; try { val3 = new Material(val2); } catch { array[j] = val2; continue; } try { ((Color)(ref val4))..ctor(0.35f, 1f, 0.35f, 0.65f); if (val3.HasProperty("_Color")) { Color color = val3.color; color.r *= val4.r; color.g *= val4.g; color.b *= val4.b; color.a = Mathf.Min(color.a, val4.a); val3.color = color; } if (val3.HasProperty("_BaseColor")) { Color color2 = val3.GetColor("_BaseColor"); color2.r *= val4.r; color2.g *= val4.g; color2.b *= val4.b; color2.a = Mathf.Min(color2.a, val4.a); val3.SetColor("_BaseColor", color2); } if (val3.HasProperty("_EmissionColor")) { val3.EnableKeyword("_EMISSION"); val3.SetColor("_EmissionColor", new Color(0.08f, 0.35f, 0.08f, 1f)); } if (val3.HasProperty("_ZWrite")) { val3.SetInt("_ZWrite", 0); } val3.renderQueue = 3000; } catch (Exception ex) { Log.LogWarning((object)("[GHOST] Preview material finomítás hiba: " + ex)); } array[j] = val3; } val.materials = array; } } internal static void SetPreviewValidState(GameObject go, bool valid) { //IL_0097: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: 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_017a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)go == (Object)null) { return; } Renderer[] componentsInChildren = go.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Material[] materials = val.materials; foreach (Material val2 in materials) { if ((Object)(object)val2 == (Object)null) { continue; } Color val3 = (valid ? new Color(0.35f, 1f, 0.35f, 0.65f) : new Color(1f, 0.25f, 0.25f, 0.65f)); try { if (val2.HasProperty("_Color")) { Color color = val2.color; color.r = val3.r; color.g = val3.g; color.b = val3.b; color.a = val3.a; val2.color = color; } if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", val3); } if (val2.HasProperty("_EmissionColor")) { val2.EnableKeyword("_EMISSION"); val2.SetColor("_EmissionColor", valid ? new Color(0.08f, 0.35f, 0.08f, 1f) : new Color(0.35f, 0.05f, 0.05f, 1f)); } } catch (Exception ex) { Log.LogWarning((object)("[GHOST] SetPreviewValidState hiba: " + ex)); } } } } internal static GameObject CreatePreviewGhost(Player player, GameObject sourceGhost) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown GameObject bestPreviewVisualSource = GetBestPreviewVisualSource(player, sourceGhost); if ((Object)(object)bestPreviewVisualSource == (Object)null) { return null; } GameObject val = new GameObject("PlantingPreview_" + CleanName(((Object)bestPreviewVisualSource).name)); val.SetActive(false); if (!CopyVisualChildrenOnly(bestPreviewVisualSource, val)) { Object.Destroy((Object)(object)val); Log.LogWarning((object)"[GHOST] Nem sikerült vizuális elemet másolni a preview ghosthoz."); return null; } PreparePreviewVisuals(val); int num = val.GetComponentsInChildren(true).Length; LogGhost("Vizuális preview ghost létrehozva: " + ((Object)val).name + " | source=" + CleanName(((Object)bestPreviewVisualSource).name) + " | renderers=" + num); return val; } internal static void EnsurePreviewGhostCount(int count, Player player, GameObject sourceGhost) { while (PreviewGhosts.Count < count) { GameObject val = CreatePreviewGhost(player, sourceGhost); if ((Object)(object)val == (Object)null) { break; } PreviewGhosts.Add(val); } while (PreviewGhosts.Count > count) { int index = PreviewGhosts.Count - 1; if ((Object)(object)PreviewGhosts[index] != (Object)null) { Object.Destroy((Object)(object)PreviewGhosts[index]); } PreviewGhosts.RemoveAt(index); } } internal static void DestroyPreviewGhosts() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) for (int i = 0; i < PreviewGhosts.Count; i++) { if ((Object)(object)PreviewGhosts[i] != (Object)null) { Object.Destroy((Object)(object)PreviewGhosts[i]); } } PreviewGhosts.Clear(); CachedExtraPositions.Clear(); _hasStickyRotation = false; _stickyRotation = Quaternion.identity; _lastGoodPreviewRotation = Quaternion.identity; _hasLastGoodPreviewRotation = false; LogGhost("Minden preview ghost törölve."); } internal static void HidePreviewGhosts() { for (int i = 0; i < PreviewGhosts.Count; i++) { if ((Object)(object)PreviewGhosts[i] != (Object)null) { PreviewGhosts[i].SetActive(false); } } if (_lastPreviewVisible) { LogGhost("Preview ghostok elrejtve."); } _lastPreviewVisible = false; _hasStickyRotation = false; } internal static void UpdatePreviewGhosts(Player player) { //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: 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) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: 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_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0400: 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_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: 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) if (!Enabled.Value || !PreviewExtraPlants.Value) { HidePreviewGhosts(); return; } if ((Object)(object)player == (Object)null) { HidePreviewGhosts(); return; } if (OnlyLocalPreview.Value && (Object)(object)player != (Object)(object)Player.m_localPlayer) { HidePreviewGhosts(); return; } GameObject placementGhost = GetPlacementGhost(player); if ((Object)(object)placementGhost == (Object)null) { HidePreviewGhosts(); return; } string text = CleanName(((Object)placementGhost).name); if (text.StartsWith("HH_", StringComparison.OrdinalIgnoreCase)) { HidePreviewGhosts(); return; } int extraPlantCount = GetExtraPlantCount(player); bool flag = HasCultivatorEquipped(player, placementGhost); Piece selectedPieceSafe = GetSelectedPieceSafe(player); GameObject val = (((Object)(object)selectedPieceSafe != (Object)null) ? ((Component)selectedPieceSafe).gameObject : null); bool flag2 = IsPlantPlacement(placementGhost) || IsPlantPlacement(val); bool flag3 = (IsPlantableGhost(placementGhost) || IsPlantableGhost(val)) && flag2; bool flag4 = flag3 && flag && extraPlantCount > 0; if (DebugEnabled.Value && DebugGhostUpdate.Value && (text != _lastGhostName || extraPlantCount != _lastExtraCount || flag4 != _lastPreviewVisible)) { Log.LogInfo((object)("[GHOST] Állapotváltás | ghost=" + text + " | cultivator=" + flag + " | plantPlacement=" + flag2 + " | plantable=" + flag3 + " | extraCount=" + extraPlantCount + " | shouldShow=" + flag4)); _lastGhostName = text; _lastExtraCount = extraPlantCount; } if (!flag4) { HidePreviewGhosts(); return; } Piece selectedPiece = selectedPieceSafe; string plantKey = GetPlantKey(placementGhost, selectedPiece); if (plantKey != _lastSelectedPlantKey) { LogGhost("Kiválasztott növény változott: " + _lastSelectedPlantKey + " -> " + plantKey + ". Preview újraépítés."); DestroyPreviewGhosts(); _lastSelectedPlantKey = plantKey; } List list = CalculateExtraPositions(player, placementGhost, selectedPiece); EnsurePreviewGhostCount(list.Count, player, placementGhost); Quaternion previewRotation = GetPreviewRotation(placementGhost); float spacingForSelectedPlant = GetSpacingForSelectedPlant(player, placementGhost, selectedPiece); if (_hasStickyRotation) { try { placementGhost.transform.rotation = previewRotation; } catch { } } Vector3 right = previewRotation * Vector3.right; Vector3 forward = previewRotation * Vector3.forward; right.y = 0f; forward.y = 0f; if (((Vector3)(ref right)).sqrMagnitude < 0.0001f) { right = Vector3.right; } if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { forward = Vector3.forward; } ((Vector3)(ref right)).Normalize(); ((Vector3)(ref forward)).Normalize(); for (int i = 0; i < PreviewGhosts.Count; i++) { GameObject val2 = PreviewGhosts[i]; if ((Object)(object)val2 == (Object)null) { continue; } if (i >= list.Count) { val2.SetActive(false); continue; } Vector2Int cell = ((i < CachedExtraCells.Count) ? CachedExtraCells[i] : Vector2Int.zero); bool valid = CanPreviewPlaceAt(list[i], spacingForSelectedPlant, cell, right, forward, useEdgeDirection: true); Vector3 val3 = list[i] + Vector3.up * 0.08f; val2.transform.SetPositionAndRotation(val3, previewRotation); SetPreviewValidState(val2, valid); if (!val2.activeSelf) { val2.SetActive(true); } if (!DebugEnabled.Value || !DebugGhostUpdate.Value || !DebugShowPositionDetails.Value) { continue; } Renderer[] componentsInChildren = val2.GetComponentsInChildren(true); int num = 0; for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)null && componentsInChildren[j].enabled) { num++; } } Log.LogInfo((object)("[GHOST] Preview[" + i + "] -> " + Vec(list[i]) + " | valid=" + valid + " | renderers=" + componentsInChildren.Length + " | enabled=" + num + " | activeSelf=" + val2.activeSelf)); } _lastPreviewVisible = true; } internal static void PlaceExtraPlants(Player player, Piece piece, Quaternion rot) { //IL_04c7: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null) { LogPlacement("PlaceExtraPlants megszakítva: player vagy piece null."); return; } if (!Enabled.Value) { LogPlacement("PlaceExtraPlants megszakítva: mod kikapcsolva."); return; } GameObject placementGhost = GetPlacementGhost(player); if ((Object)(object)placementGhost == (Object)null) { LogPlacement("PlaceExtraPlants megszakítva: nincs aktív placement ghost."); return; } if (!HasCultivatorEquipped(player, placementGhost)) { LogPlacement("PlaceExtraPlants megszakítva: nincs Cultivator."); return; } GameObject gameObject = ((Component)piece).gameObject; bool flag = IsPlantableGhost(placementGhost) && IsPlantPlacement(placementGhost); bool flag2 = (Object)(object)gameObject != (Object)null && IsPlantableGhost(gameObject) && IsPlantPlacement(gameObject); if (!flag && !flag2) { LogPlacement("PlaceExtraPlants megszakítva: sem a placement ghost, sem a selected piece nem támogatott növény. ghost=" + CleanName(((Object)placementGhost).name) + " piece=" + (((Object)(object)gameObject != (Object)null) ? CleanName(((Object)gameObject).name) : "null")); return; } if ((Object)(object)gameObject == (Object)null) { LogPlacement("PlaceExtraPlants megszakítva: piece.gameObject null."); return; } CalculateExtraPositions(player, placementGhost, piece); float spacingForSelectedPlant = GetSpacingForSelectedPlant(player, placementGhost, piece); if (CachedExtraPositions.Count <= 0) { LogPlacement("PlaceExtraPlants megszakítva: nincs extra pozíció újraszámolás után."); return; } _lastPlacedPrefabVisualSource = gameObject; _lastPlacedPrefabName = CleanName(((Object)gameObject).name); _stickyRotation = rot; _hasStickyRotation = true; _lastGoodPreviewRotation = rot; _hasLastGoodPreviewRotation = true; LogPlacement("Extra lerakás indul. piece=" + CleanName(((Object)gameObject).name) + " cachedPositions=" + CachedExtraPositions.Count + " | rotY=" + ((Quaternion)(ref rot)).eulerAngles.y.ToString("0.0")); Vector3 right = rot * Vector3.right; Vector3 forward = rot * Vector3.forward; right.y = 0f; forward.y = 0f; if (((Vector3)(ref right)).sqrMagnitude < 0.0001f) { right = Vector3.right; } if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { forward = Vector3.forward; } ((Vector3)(ref right)).Normalize(); ((Vector3)(ref forward)).Normalize(); int num = 0; int num2 = 0; int num3 = LimitExtraCountByResources(player, piece, CachedExtraPositions.Count, reserveVanillaCenterCost: false); for (int i = 0; i < CachedExtraPositions.Count; i++) { if (num >= num3) { LogPlacement("Extra lerakás megállítva mag limit miatt. placed=" + num + " max=" + num3); break; } Vector3 val = CachedExtraPositions[i]; Vector2Int cell = ((i < CachedExtraCells.Count) ? CachedExtraCells[i] : Vector2Int.zero); if (!CanPlaceAt(val, spacingForSelectedPlant, cell, right, forward, useEdgeDirection: true)) { num2++; LogPlacement("Pozíció tiltva: index=" + i + " pos=" + Vec(val)); continue; } try { GameObject val2 = Object.Instantiate(gameObject, val, rot); ((Object)val2).name = CleanName(((Object)gameObject).name); Piece component = val2.GetComponent(); if ((Object)(object)component != (Object)null) { try { component.SetCreator(player.GetPlayerID()); } catch (Exception ex) { Log.LogWarning((object)("[PLACE] SetCreator hiba: " + ex)); } } ZNetView component2 = val2.GetComponent(); if ((Object)(object)component2 != (Object)null && component2.IsValid()) { try { ZDO zDO = component2.GetZDO(); if (zDO != null) { zDO.SetOwner(ZDOMan.GetSessionID()); } } catch (Exception ex2) { Log.LogWarning((object)("[PLACE] ZDO owner beállítás hiba: " + ex2)); } } player.ConsumeResources(piece.m_resources, 0, -1, 1); num++; LogPlacement("Extra növény lerakva: index=" + i + " pos=" + Vec(val) + " name=" + ((Object)val2).name); } catch (Exception ex3) { Log.LogWarning((object)("[PLACE] Extra növény lerakás hiba index=" + i + " pos=" + Vec(val) + " -> " + ex3)); } } LogPlacement("Extra lerakás vége. placed=" + num + " blocked=" + num2 + " requested=" + CachedExtraPositions.Count); } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] public static class Player_UpdatePlacementGhost_Patch { [HarmonyPostfix] private static void Postfix(Player __instance) { try { if ((Object)(object)__instance != (Object)null) { HardheimMultiPlantPlugin.UpdatePreviewGhosts(__instance); } } catch (Exception ex) { HardheimMultiPlantPlugin.Log.LogWarning((object)("[PATCH] UpdatePlacementGhost postfix hiba: " + ex)); } } } [HarmonyPatch(typeof(Player), "PlacePiece")] public static class Player_PlacePiece_Patch { [HarmonyPostfix] private static void Postfix(Player __instance, Piece piece, Vector3 pos, Quaternion rot, bool doAttack) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) try { HardheimMultiPlantPlugin.LogPlacement("Player.PlacePiece postfix meghívva. pos=" + HardheimMultiPlantPlugin.Vec(pos) + " doAttack=" + doAttack); HardheimMultiPlantPlugin.PlaceExtraPlants(__instance, piece, rot); } catch (Exception ex) { HardheimMultiPlantPlugin.Log.LogWarning((object)("[PATCH] PlacePiece postfix hiba: " + ex)); } } } [HarmonyPatch(typeof(Player), "UpdatePlacement")] public static class Player_UpdatePlacement_Patch { [HarmonyPostfix] private static void Postfix(Player __instance, bool takeInput) { try { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { GameObject placementGhost = HardheimMultiPlantPlugin.GetPlacementGhost(__instance); if ((Object)(object)placementGhost == (Object)null) { HardheimMultiPlantPlugin.HidePreviewGhosts(); } } } catch (Exception ex) { HardheimMultiPlantPlugin.Log.LogWarning((object)("[PATCH] UpdatePlacement postfix hiba: " + ex)); } } } [HarmonyPatch(typeof(Game), "Logout")] public static class Game_Logout_Patch { [HarmonyPrefix] private static void Prefix() { try { HardheimMultiPlantPlugin.DestroyPreviewGhosts(); } catch (Exception ex) { HardheimMultiPlantPlugin.Log.LogWarning((object)("[PATCH] Logout prefix hiba: " + ex)); } } }