Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of HardheimMultiPlant v1.0.0
plugins/MultiPlant.dll
Decompiled 3 hours agousing 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("58fda8fc-703c-4199-b3f4-ddcd0647aaa4")] [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.0.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.0.0"; internal static HardheimMultiPlantPlugin Instance; internal static ManualLogSource Log; private Harmony _harmony; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> RequiredFarmingSkill; internal static ConfigEntry<int> ExtraPlantsAtThreshold; internal static ConfigEntry<int> MaxExtraPlants; internal static ConfigEntry<float> PlantSpacing; internal static ConfigEntry<bool> RequireCultivatorEquipped; internal static ConfigEntry<string> AllowedPrefabKeywords; internal static ConfigEntry<bool> EnableSnapping; internal static ConfigEntry<float> SnapStep; internal static ConfigEntry<bool> SnapUseGhostRight; internal static ConfigEntry<bool> PreviewExtraPlants; internal static ConfigEntry<bool> OnlyLocalPreview; internal static ConfigEntry<bool> ExtraPlacementRequiresFreeSpace; internal static ConfigEntry<bool> GroundSnapToTerrain; internal static ConfigEntry<float> GroundSnapRayHeight; internal static ConfigEntry<bool> DebugEnabled; internal static ConfigEntry<bool> DebugGhostUpdate; internal static ConfigEntry<bool> DebugPlacement; internal static ConfigEntry<bool> DebugConfigSync; internal static ConfigEntry<bool> DebugShowPositionDetails; internal static ConfigEntry<bool> DebugDumpConfigOnLoad; internal static ConfigEntry<bool> DebugDumpConfigOnSync; internal static ConfigEntry<bool> DebugDumpAdminState; internal static ConfigEntry<bool> DebugCollisionCheck; internal static ConfigEntry<bool> UseSquarePattern; internal static ConfigEntry<bool> UseGroundRaySnap; internal static ConfigEntry<float> GroundRayStartHeight; internal static ConfigEntry<float> GroundRayDistance; private static readonly List<GameObject> PreviewGhosts = new List<GameObject>(); private static readonly List<Vector3> CachedExtraPositions = new List<Vector3>(); 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 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.0.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<bool>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ConfigFile config = ((BaseUnityPlugin)this).Config; AcceptableValueBase val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100); RequiredFarmingSkill = ConfigFileExtensions.BindConfig<int>(config, "Egyensúly", "RequiredFarmingSkill", 60, "Minimum Farming skill szint, ami felett aktiválódik a többes ültetés.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ConfigFile config2 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 16); ExtraPlantsAtThreshold = ConfigFileExtensions.BindConfig<int>(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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ConfigFile config3 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 32); MaxExtraPlants = ConfigFileExtensions.BindConfig<int>(config3, "Egyensúly", "MaxExtraPlants", 8, "Maximum ennyi extra növényt enged a mod összesen.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ConfigFile config4 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 5f); PlantSpacing = ConfigFileExtensions.BindConfig<float>(config4, "Elhelyezés", "PlantSpacing", 1.15f, "Az extra növények távolsága az eredeti ültetési ponttól.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); RequireCultivatorEquipped = ConfigFileExtensions.BindConfig<bool>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); AllowedPrefabKeywords = ConfigFileExtensions.BindConfig<string>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); EnableSnapping = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Snapping", "EnableSnapping", true, "Ha igaz, az extra növények pozíciója rácsra lesz igazítva.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ConfigFile config5 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f); SnapStep = ConfigFileExtensions.BindConfig<float>(config5, "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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); SnapUseGhostRight = ConfigFileExtensions.BindConfig<bool>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); PreviewExtraPlants = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Preview", "PreviewExtraPlants", true, "Ha igaz, ültetés előtt megjelennek az extra ghostok.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); OnlyLocalPreview = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Preview", "OnlyLocalPreview", true, "Ha igaz, a preview csak a helyi játékosnak jelenik meg.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ExtraPlacementRequiresFreeSpace = ConfigFileExtensions.BindConfig<bool>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); GroundSnapToTerrain = ConfigFileExtensions.BindConfig<bool>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ConfigFile config6 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f); GroundSnapRayHeight = ConfigFileExtensions.BindConfig<float>(config6, "Snapping", "GroundSnapRayHeight", 10f, "Milyen magasról induljon a talajra igazító raycast az extra pozícióknál.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); UseSquarePattern = ConfigFileExtensions.BindConfig<bool>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); UseGroundRaySnap = ConfigFileExtensions.BindConfig<bool>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ConfigFile config7 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f); GroundRayStartHeight = ConfigFileExtensions.BindConfig<float>(config7, "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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ConfigFile config8 = ((BaseUnityPlugin)this).Config; val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f); GroundRayDistance = ConfigFileExtensions.BindConfig<float>(config8, "Snapping", "GroundRayDistance", 10f, "A lefelé sugárvetés maximális hossza a talaj megkereséséhez.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugEnabled = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Debug", "DebugEnabled", false, "Fő debug kapcsoló. Erősen részletes naplózást engedélyez.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugGhostUpdate = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Debug", "DebugGhostUpdate", true, "Részletes log az előnézeti ghost frissítésről.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugPlacement = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Debug", "DebugPlacement", true, "Részletes log a tényleges extra lerakásról.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugConfigSync = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Debug", "DebugConfigSync", true, "Részletes log a Jotunn config sync eseményekről.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugShowPositionDetails = ConfigFileExtensions.BindConfig<bool>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugDumpConfigOnLoad = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Debug", "DebugDumpConfigOnLoad", true, "A mod indulásakor kiírja az összes fontos konfig értéket.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugDumpConfigOnSync = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Debug", "DebugDumpConfigOnSync", true, "Config sync után kiírja az összes fontos konfig értéket.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugDumpAdminState = ConfigFileExtensions.BindConfig<bool>(((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<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugCollisionCheck = ConfigFileExtensions.BindConfig<bool>(((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<ConfigEntryBase>)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 + "] 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 + "] 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<string> list = new List<string>(); 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); 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).ToLowerInvariant(); if (text.Contains("cultivate") || text.Contains("sapling") || text.Contains("seed") || text.Contains("carrot") || text.Contains("turnip") || text.Contains("onion") || text.Contains("barley") || text.Contains("flax") || text.Contains("beech") || text.Contains("birch") || text.Contains("fir") || text.Contains("pine") || text.Contains("jotunpuffs") || text.Contains("magecap")) { return true; } return (Object)(object)placementGhost.GetComponent<Piece>() != (Object)null; } internal static bool IsPlantableGhost(GameObject ghost) { if ((Object)(object)ghost == (Object)null) { return false; } string text = CleanName(((Object)ghost).name); if (string.IsNullOrWhiteSpace(text)) { return false; } string[] array = SplitKeywords(AllowedPrefabKeywords.Value); for (int i = 0; i < array.Length; i++) { if (text.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 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 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_0036: 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_0042: 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_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_0074: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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) snapped = position; if (!GroundSnapToTerrain.Value) { return false; } float num = Mathf.Max(1f, GroundSnapRayHeight.Value); Vector3 val = position + Vector3.up * num; RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(new Ray(val, Vector3.down), ref val2, num * 2f + 20f, -1, (QueryTriggerInteraction)1)) { snapped = new Vector3(position.x, ((RaycastHit)(ref val2)).point.y, position.z); if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[GROUND] hit=" + (((Object)(object)((RaycastHit)(ref val2)).collider != (Object)null) ? ((Object)((Component)((RaycastHit)(ref val2)).collider).gameObject).name : "null") + " | from=" + Vec(position) + " -> " + Vec(snapped))); } return true; } if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[GROUND] Nincs talaj találat: " + Vec(position))); } return false; } internal static Vector3 SnapToGround(Vector3 position) { //IL_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_013b: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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) if (!UseGroundRaySnap.Value) { return position; } Vector3 val = position + Vector3.up * Mathf.Max(0.5f, GroundRayStartHeight.Value); float num = Mathf.Max(1f, GroundRayDistance.Value); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, Vector3.down, ref val2, num, -1, (QueryTriggerInteraction)1)) { if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[GROUND] hit point=" + Vec(((RaycastHit)(ref val2)).point) + " collider=" + (Object.op_Implicit((Object)(object)((RaycastHit)(ref val2)).collider) ? ((Object)((RaycastHit)(ref val2)).collider).name : "null"))); } return new Vector3(position.x, ((RaycastHit)(ref val2)).point.y, position.z); } if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[GROUND] nincs találat. start=" + Vec(val) + " dist=" + num)); } return position; } internal static List<int> BuildOffsetPattern(int count) { List<int> list = new List<int>(); int num = 1; while (list.Count < count) { list.Add(num); if (list.Count >= count) { break; } list.Add(-num); num++; } return list; } internal static bool CanPlaceAt(Vector3 position) { //IL_0053: 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_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_016e: 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; } 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 = 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; 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) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!ExtraPlacementRequiresFreeSpace.Value) { return true; } 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)) { string text = ((Object)((Component)val).gameObject).name ?? string.Empty; if (text.Length != 0 && 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) { 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 List<Vector3> CalculateExtraPositions(Player player, GameObject sourceGhost) { //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) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_0097: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_0164: 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_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018e: 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_01ab: 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_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_0391: 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_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: 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_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_043d: Unknown result type (might be due to invalid IL or missing references) CachedExtraPositions.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); if (extraPlantCount <= 0) { LogGhost("CalculateExtraPositions: extraCount <= 0, nincs extra pozíció."); return CachedExtraPositions; } float num = Mathf.Max(0.2f, PlantSpacing.Value); 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<Vector3> list = new List<Vector3>(); if (UseSquarePattern.Value) { List<Vector2Int> list2 = new List<Vector2Int> { 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 < list2.Count; i++) { Vector2Int val3 = list2[i]; list.Add((val * (float)((Vector2Int)(ref val3)).x + val2 * (float)((Vector2Int)(ref val3)).y) * num); } } else { Vector3 val4; if (!SnapUseGhostRight.Value) { Vector3 right = ((Component)player).transform.right; val4 = ((Vector3)(ref right)).normalized; } else { val4 = val; } Vector3 val5 = val4; List<int> list3 = BuildOffsetPattern(extraPlantCount); for (int j = 0; j < list3.Count; j++) { list.Add(val5 * ((float)list3[j] * num)); } } if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[POS] origin=" + Vec(position) + " spacing=" + num + " extraCount=" + extraPlantCount + " square=" + UseSquarePattern.Value)); } for (int k = 0; k < list.Count; k++) { Vector3 val6 = position + list[k]; Vector3 val7 = ApplySnapping(val6); Vector3 position2 = val7; bool flag = false; if (TrySnapToGround(val7, out var snapped)) { position2 = snapped; flag = true; } Vector3 val8 = SnapToGround(position2); CachedExtraPositions.Add(val8); if (DebugEnabled.Value && DebugShowPositionDetails.Value) { Log.LogInfo((object)("[POS] idx=" + k + " raw=" + Vec(val6) + " snappedXZ=" + Vec(val7) + " terrainHit=" + flag + " final=" + Vec(val8))); } } 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<Renderer>(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>(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<Renderer>(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<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } Collider[] componentsInChildren2 = go.GetComponentsInChildren<Collider>(true); for (int j = 0; j < componentsInChildren2.Length; j++) { Object.Destroy((Object)(object)componentsInChildren2[j]); } Rigidbody[] componentsInChildren3 = go.GetComponentsInChildren<Rigidbody>(true); for (int k = 0; k < componentsInChildren3.Length; k++) { Object.Destroy((Object)(object)componentsInChildren3[k]); } Joint[] componentsInChildren4 = go.GetComponentsInChildren<Joint>(true); for (int l = 0; l < componentsInChildren4.Length; l++) { Object.Destroy((Object)(object)componentsInChildren4[l]); } ZNetView[] componentsInChildren5 = go.GetComponentsInChildren<ZNetView>(true); for (int m = 0; m < componentsInChildren5.Length; m++) { Object.Destroy((Object)(object)componentsInChildren5[m]); } ZSyncTransform[] componentsInChildren6 = go.GetComponentsInChildren<ZSyncTransform>(true); for (int n = 0; n < componentsInChildren6.Length; n++) { Object.Destroy((Object)(object)componentsInChildren6[n]); } Piece[] componentsInChildren7 = go.GetComponentsInChildren<Piece>(true); for (int num = 0; num < componentsInChildren7.Length; num++) { Object.Destroy((Object)(object)componentsInChildren7[num]); } WearNTear[] componentsInChildren8 = go.GetComponentsInChildren<WearNTear>(true); for (int num2 = 0; num2 < componentsInChildren8.Length; num2++) { Object.Destroy((Object)(object)componentsInChildren8[num2]); } TerrainModifier[] componentsInChildren9 = go.GetComponentsInChildren<TerrainModifier>(true); for (int num3 = 0; num3 < componentsInChildren9.Length; num3++) { Object.Destroy((Object)(object)componentsInChildren9[num3]); } Plant[] componentsInChildren10 = go.GetComponentsInChildren<Plant>(true); for (int num4 = 0; num4 < componentsInChildren10.Length; num4++) { Object.Destroy((Object)(object)componentsInChildren10[num4]); } Pickable[] componentsInChildren11 = go.GetComponentsInChildren<Pickable>(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<Renderer>(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<Renderer>(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<Renderer>(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_0260: 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) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: 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); int extraPlantCount = GetExtraPlantCount(player); bool flag = HasCultivatorEquipped(player, placementGhost); bool flag2 = IsPlantPlacement(placementGhost); bool flag3 = IsPlantableGhost(placementGhost) || 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; } List<Vector3> list = CalculateExtraPositions(player, placementGhost); EnsurePreviewGhostCount(list.Count, player, placementGhost); Quaternion previewRotation = GetPreviewRotation(placementGhost); if (_hasStickyRotation) { try { placementGhost.transform.rotation = previewRotation; } catch { } } for (int i = 0; i < PreviewGhosts.Count; i++) { GameObject val = PreviewGhosts[i]; if ((Object)(object)val == (Object)null) { continue; } if (i >= list.Count) { val.SetActive(false); continue; } bool valid = CanPreviewPlaceAt(list[i]); Vector3 val2 = list[i] + Vector3.up * 0.08f; val.transform.SetPositionAndRotation(val2, previewRotation); SetPreviewValidState(val, valid); if (!val.activeSelf) { val.SetActive(true); } if (!DebugEnabled.Value || !DebugGhostUpdate.Value || !DebugShowPositionDetails.Value) { continue; } Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(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=" + val.activeSelf)); } _lastPreviewVisible = true; } internal static void PlaceExtraPlants(Player player, Piece piece, Quaternion rot) { //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_012e: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) 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; } if (!IsPlantableGhost(placementGhost) && !IsPlantPlacement(placementGhost)) { LogPlacement("PlaceExtraPlants megszakítva: a placement ghost nem támogatott növény."); return; } if (CachedExtraPositions.Count <= 0) { LogPlacement("PlaceExtraPlants megszakítva: nincs cache-elt extra pozíció."); return; } GameObject gameObject = ((Component)piece).gameObject; if ((Object)(object)gameObject == (Object)null) { LogPlacement("PlaceExtraPlants megszakítva: piece.gameObject null."); 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")); int num = 0; int num2 = 0; for (int i = 0; i < CachedExtraPositions.Count; i++) { Vector3 val = CachedExtraPositions[i]; if (!CanPlaceAt(val)) { num2++; LogPlacement("Pozíció tiltva: index=" + i + " pos=" + Vec(val)); continue; } try { GameObject val2 = Object.Instantiate<GameObject>(gameObject, val, rot); ((Object)val2).name = CleanName(((Object)gameObject).name); Piece component = val2.GetComponent<Piece>(); 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<ZNetView>(); 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)); } } 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)); } } }