Please disclose if any significant portion of your mod was created 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 AdvancedTerrainModifiersCompatible v1.4.8
TerrainTools.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using TerrainTools.Configs; using TerrainTools.Extensions; using TerrainTools.Helpers; using TerrainTools.Visualization; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("TerrainTools")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("TerrainTools")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("1.4.8")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.8.0")] [module: UnverifiableCode] namespace MVBP.Extensions { internal static class GameObjectExtensions { internal static GameObject DeepCopy(this GameObject obj) { bool activeSelf = obj.activeSelf; obj.SetActive(false); GameObject result = Object.Instantiate<GameObject>(obj); obj.SetActive(activeSelf); return result; } public static bool HasAnyComponent(this GameObject gameObject, params Type[] components) { foreach (Type type in components) { if (Object.op_Implicit((Object)(object)gameObject.GetComponent(type))) { return true; } } return false; } public static bool HasAnyComponent(this GameObject gameObject, params string[] componentNames) { foreach (string text in componentNames) { if (Object.op_Implicit((Object)(object)gameObject.GetComponent(text))) { return true; } } return false; } public static bool HasAllComponents(this GameObject gameObject, params string[] componentNames) { foreach (string text in componentNames) { if (!Object.op_Implicit((Object)(object)gameObject.GetComponent(text))) { return false; } } return true; } public static bool HasAllComponents(this GameObject gameObject, params Type[] components) { foreach (Type type in components) { if (!Object.op_Implicit((Object)(object)gameObject.GetComponent(type))) { return false; } } return true; } public static bool HasAnyComponentInChildren(this GameObject gameObject, bool includeInactive = false, params Type[] components) { foreach (Type type in components) { if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren(type, includeInactive))) { return true; } } return false; } public static Transform FindDeepChild(this GameObject gameObject, string childName, IterativeSearchType searchType = (IterativeSearchType)1) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return gameObject.transform.FindDeepChild(childName, searchType); } public static void DestroyComponentsInChildren<T>(this GameObject gameObject, bool includeInactive = false) where T : Component { T[] componentsInChildren = gameObject.GetComponentsInChildren<T>(includeInactive); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } } } internal static class StringExtensions { internal static bool ContainsAny(this string str, params string[] substrings) { foreach (string value in substrings) { if (str.Contains(value)) { return true; } } return false; } internal static bool EndsWithAny(this string str, params string[] suffixes) { foreach (string value in suffixes) { if (str.EndsWith(value)) { return true; } } return false; } internal static bool StartsWithAny(this string str, params string[] suffixes) { foreach (string value in suffixes) { if (str.StartsWith(value)) { return true; } } return false; } internal static string RemoveSuffix(this string s, string suffix) { if (s.EndsWith(suffix)) { return s.Substring(0, s.Length - suffix.Length); } return s; } internal static string RemovePrefix(this string s, string prefix) { if (s.StartsWith(prefix)) { return s.Substring(prefix.Length, s.Length - prefix.Length); } return s; } internal static string CapitalizeFirstLetter(this string s) { if (s.Length == 0) { return s; } if (s.Length == 1) { return $"{char.ToUpper(s[0])}"; } return char.ToUpper(s[0]) + s.Substring(1); } } public static class TransformExtensions { public static Transform FindDeepChild(this Transform transform, string childName, IterativeSearchType searchType = (IterativeSearchType)1) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return Utils.FindChild(transform, childName, searchType); } } } namespace TerrainTools { [BepInPlugin("Searica.Valheim.TerrainTools", "AdvancedTerrainModifiers", "1.4.8")] [BepInDependency("com.jotunn.jotunn", "2.30.0")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] internal sealed class TerrainTools : BaseUnityPlugin { internal const string Author = "Searica"; public const string PluginName = "AdvancedTerrainModifiers"; public const string PluginGUID = "Searica.Valheim.TerrainTools"; public const string PluginVersion = "1.4.8"; private static readonly string MainSection = ConfigManager.SetStringPriority("Global", 10); private static readonly string RadiusSection = ConfigManager.SetStringPriority("Radius", 8); private static readonly string HardnessSection = ConfigManager.SetStringPriority("Hardness", 6); private static readonly string ShovelSection = ConfigManager.SetStringPriority("Shovel", 4); private static readonly string HoeSection = ConfigManager.SetStringPriority("Hoe", 2); private static readonly string CultivatorSection = ConfigManager.SetStringPriority("Cultivator", 0); internal static bool UpdatePlugin = false; private static ConfigEntry<bool> hoverInfoEnabled; private static readonly Dictionary<string, ConfigEntry<bool>> ToolConfigEntries = new Dictionary<string, ConfigEntry<bool>>(); private static ConfigEntry<bool> enableRadiusModifier; private static ConfigEntry<KeyCode> radiusModKey; private static ConfigEntry<float> radiusScrollScale; private static ConfigEntry<float> maxRadius; private static ConfigEntry<bool> enableHardnessModifier; private static ConfigEntry<KeyCode> hardnessModKey; private static ConfigEntry<float> hardnessScrollScale; private static ConfigEntry<bool> enableShovel; internal static bool IsHoverInforEnabled => hoverInfoEnabled.Value; internal static bool IsEnableRadiusModifier => enableRadiusModifier.Value; internal static float MaxRadius => maxRadius.Value; internal static KeyCode RadiusKey => radiusModKey.Value; internal static float RadiusScrollScale => radiusScrollScale.Value; internal static bool IsEnableHardnessModifier => enableHardnessModifier.Value; internal static KeyCode HardnessKey => hardnessModKey.Value; internal static float HardnessScrollScale => hardnessScrollScale.Value; internal static bool IsShovelEnabled => enableShovel.Value; private static string GetSectionName(string pieceTable) { if (pieceTable == PieceTables.Hoe) { return HoeSection; } if (pieceTable == PieceTables.Cultivator) { return CultivatorSection; } if (pieceTable == "_ShovelPieceTable") { return ShovelSection; } return MainSection; } internal static bool IsToolEnabled(string toolName) { if (ToolConfigEntries.TryGetValue(toolName, out var value)) { return value?.Value ?? false; } return false; } public void Awake() { Log.Init(((BaseUnityPlugin)this).Logger); ConfigManager.Init("Searica.Valheim.TerrainTools", ((BaseUnityPlugin)this).Config); SetUpConfigEntries(); RegisterTranslations(); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.TerrainTools"); Game.isModded = true; PrefabManager.OnVanillaPrefabsAvailable += Shovel.CreateShovel; PieceManager.OnPiecesRegistered += InitManager.InitToolPieces; _ = GUIManager.Instance; ConfigManager.SetupWatcher(); ConfigManager.CheckForConfigManager(); ConfigManager.OnConfigFileReloaded += delegate { if (UpdatePlugin) { InitManager.UpdatePlugin(); UpdatePlugin = false; } }; ConfigManager.OnConfigWindowClosed += delegate { if (UpdatePlugin) { InitManager.UpdatePlugin(); } }; SynchronizationManager.OnConfigurationSynchronized += delegate { if (UpdatePlugin) { InitManager.UpdatePlugin(); UpdatePlugin = false; } }; } private void RegisterTranslations() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); string[] array = new string[2] { "English", "Russian" }; foreach (string text in array) { localization.AddJsonFile(text, AssetUtils.LoadTextFromResources("TerrainTools.Translations." + text + ".json", executingAssembly)); if (string.IsNullOrEmpty(directoryName)) { continue; } string text2 = Path.Combine(directoryName, "Translations", "TerrainTools", text, "translations.json"); try { if (File.Exists(text2)) { localization.AddFileByPath(text2, true); } } catch (Exception ex) { Log.LogWarning("Could not load external " + text + " translations: " + ex.Message); } } } private void Update() { RadiusModifier.Tick(Player.m_localPlayer); HardnessModifier.Tick(Player.m_localPlayer); } public void OnDestroy() { ConfigManager.Save(); } internal static void SetUpConfigEntries() { Log.Verbosity = ConfigManager.BindConfig(MainSection, "Verbosity", LogLevel.Low, "Low will log basic information about the mod. Medium will log information that is useful for troubleshooting. High will log a lot of information, do not set it to this without good reason as it will slow Down your game.", null, synced: false); hoverInfoEnabled = ConfigManager.BindConfig(MainSection, "HoverInfo", value: true, "Set to true/enabled to show terrain height when using square terrain tools."); enableRadiusModifier = ConfigManager.BindConfig(RadiusSection, ConfigManager.SetStringPriority("RadiusModifier", 1), value: true, "Set to true/enabled to allow modifying the radius of terrain tools using the scroll wheel. Note: Radius cannot be changed on square tools except terrain restoration."); radiusModKey = ConfigManager.BindConfig<KeyCode>(RadiusSection, "RadiusModKey", (KeyCode)308, "Modifier key that must be held down when using scroll wheel to change the radius of terrain tools.", null, synced: false); radiusScrollScale = ConfigManager.BindConfig(RadiusSection, "RadiusScrollScale", 0.1f, "Scroll wheel change scale, larger magnitude means the radius will change faster and negative sign will reverse the direction you need to scroll to increase the radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), synced: false); maxRadius = ConfigManager.BindConfig(RadiusSection, "MaxRadius", 10f, "Maximum radius of terrain tools.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 20f)); enableHardnessModifier = ConfigManager.BindConfig(HardnessSection, ConfigManager.SetStringPriority("HardnessModifier", 1), value: true, "Use the modifier key and scroll wheel to adjust round terrain-tool hardness and Precise Raise slopes."); hardnessModKey = ConfigManager.BindConfig<KeyCode>(HardnessSection, "HardnessModKey", (KeyCode)306, "Modifier key that must be held down when using scroll wheel to change the hardness of terrain tools.", null, synced: false); hardnessScrollScale = ConfigManager.BindConfig(HardnessSection, "HardnessScrollScale", 1f, "Scroll wheel change scale, larger magnitude means the hardness will change faster and negative sign will reverse the direction you need to scroll to increase the hardness.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), synced: false); enableShovel = ConfigManager.BindConfig(ShovelSection, ConfigManager.SetStringPriority("Shovel", 1), value: true, "Set to true/enabled to allow crafting the shovel. Setting to false/disabled will prevent crafting new shovels but will not affect existing shovels in the world."); enableShovel.SettingChanged += SetUpdatePlugin; foreach (string key in ToolConfigs.ToolConfigsMap.Keys) { ConfigEntry<bool> val = ConfigManager.BindConfig(GetSectionName(ToolConfigs.ToolConfigsMap[key].pieceTable), key, value: true, "Set to true/enabled to add this terrain tool. Set to false/disabled to remove it."); val.SettingChanged += SetUpdatePlugin; ToolConfigEntries.Add(key, val); } ConfigManager.Save(); } private static void SetUpdatePlugin(object obj, EventArgs e) { UpdatePlugin = true; } } internal enum LogLevel { Low, Medium, High } internal static class Log { private static ManualLogSource logSource; internal static ConfigEntry<LogLevel> Verbosity { get; set; } internal static LogLevel VerbosityLevel => Verbosity.Value; internal static void Init(ManualLogSource logSource) { Log.logSource = logSource; } internal static void LogDebug(object data) { logSource.LogDebug(data); } internal static void LogError(object data) { logSource.LogError(data); } internal static void LogFatal(object data) { logSource.LogFatal(data); } internal static void LogMessage(object data) { logSource.LogMessage(data); } internal static void LogWarning(object data) { logSource.LogWarning(data); } internal static void LogInfo(object data, LogLevel level = LogLevel.Low) { if (Verbosity == null || VerbosityLevel >= level) { logSource.LogInfo(data); } } internal static void LogGameObject(GameObject prefab, bool includeChildren = false) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown LogInfo("***** " + ((Object)prefab).name + " *****"); Component[] components = prefab.GetComponents<Component>(); for (int i = 0; i < components.Length; i++) { LogComponent(components[i]); } if (!includeChildren) { return; } LogInfo("***** " + ((Object)prefab).name + " (children) *****"); foreach (Transform item in prefab.transform) { Transform val = item; LogInfo(" - " + ((Object)((Component)val).gameObject).name); components = ((Component)val).gameObject.GetComponents<Component>(); for (int i = 0; i < components.Length; i++) { LogComponent(components[i]); } } } internal static void LogComponent(Component compo) { LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---"); PropertyInfo[] properties = ((object)compo).GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); foreach (PropertyInfo propertyInfo in properties) { LogInfo($" - {propertyInfo.Name} = {propertyInfo.GetValue(compo)}"); } FieldInfo[] fields = ((object)compo).GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); foreach (FieldInfo fieldInfo in fields) { LogInfo($" - {fieldInfo.Name} = {fieldInfo.GetValue(compo)}"); } } } } namespace TerrainTools.Visualization { public class HoverInfo { private readonly GameObject _gameObject; private readonly Transform _transform; private readonly TextMesh _textMesh; public string Text { get { return _textMesh.text; } set { _textMesh.text = value; } } public bool Enabled { get { return _gameObject.activeSelf; } set { _gameObject.SetActive(value); } } public Color Color { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return _textMesh.color; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) _textMesh.color = value; } } public HoverInfo(Transform parentTransform) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_004f: 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_007b: 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_0097: Unknown result type (might be due to invalid IL or missing references) _gameObject = new GameObject(); _gameObject.transform.parent = parentTransform; _transform = _gameObject.transform; _textMesh = _gameObject.AddComponent<TextMesh>(); ((Component)_textMesh).transform.localPosition = Vector3.zero; ((Component)_textMesh).transform.localScale = new Vector3(0.1f / parentTransform.localScale.x, 0.1f / parentTransform.localScale.y, 0.1f / parentTransform.localScale.z); _textMesh.anchor = (TextAnchor)4; _textMesh.alignment = (TextAlignment)1; _textMesh.fontSize = 16; } public void RotateToPlayer() { //IL_000c: 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_0030: 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_0046: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(((Component)GameCamera.m_instance).transform.position.x, _transform.position.y, ((Component)GameCamera.m_instance).transform.position.z); _transform.LookAt(val, Vector3.up); _transform.Rotate(90f, 180f, 0f); } } internal static class IconCache { private static Texture2D _remove; private static Texture2D _cross; private static Texture2D _undo; private static Texture2D _redo; private static Texture2D _box; private static Texture2D _pavedRoadSquare; private static Texture2D _pavedRoadPath; private static Texture2D _pavedRoadPathSquare; private static Texture2D _mudRoadSquare; private static Texture2D _mudRoadPathSquare; private static Texture2D _replantSquare; private static Texture2D _cultivateSquare; private static Texture2D _cultivatePath; private static Texture2D _cultivatePathSquare; private static Texture2D _raiseSquare; private static Texture2D _lower; private static Texture2D _shovel; internal static Texture2D Shovel { get { if ((Object)(object)_shovel == (Object)null) { _shovel = LoadTextureFromResources("ShovelIcon.png"); } return _shovel; } } internal static Texture2D Lower { get { if ((Object)(object)_lower == (Object)null) { _lower = LoadTextureFromResources("lower_v2.png"); } return _lower; } } internal static Texture2D CultivateSquare { get { if ((Object)(object)_cultivateSquare == (Object)null) { _cultivateSquare = LoadTextureFromResources("cultivate_v2_square.png"); } return _cultivateSquare; } } internal static Texture2D CultivatePathSquare { get { if ((Object)(object)_cultivatePathSquare == (Object)null) { _cultivatePathSquare = LoadTextureFromResources("cultivate_v2_path_square.png"); } return _cultivatePathSquare; } } internal static Texture2D CultivatePath { get { if ((Object)(object)_cultivatePath == (Object)null) { _cultivatePath = LoadTextureFromResources("cultivate_v2_path.png"); } return _cultivatePath; } } internal static Texture2D ReplantSquare { get { if ((Object)(object)_replantSquare == (Object)null) { _replantSquare = LoadTextureFromResources("replant_v2_square.png"); } return _replantSquare; } } internal static Texture2D RaiseSquare { get { if ((Object)(object)_raiseSquare == (Object)null) { _raiseSquare = LoadTextureFromResources("raise_v2_square.png"); } return _raiseSquare; } } internal static Texture2D MudRoadPathSquare { get { if ((Object)(object)_mudRoadPathSquare == (Object)null) { _mudRoadPathSquare = LoadTextureFromResources("path_v2_square.png"); } return _mudRoadPathSquare; } } internal static Texture2D MudRoadSquare { get { if ((Object)(object)_mudRoadSquare == (Object)null) { _mudRoadSquare = LoadTextureFromResources("mud_road_v2_square.png"); } return _mudRoadSquare; } } internal static Texture2D PavedRoadPath { get { if ((Object)(object)_pavedRoadPath == (Object)null) { _pavedRoadPath = LoadTextureFromResources("paved_road_v2_path.png"); } return _pavedRoadPath; } } internal static Texture2D PavedRoadPathSquare { get { if ((Object)(object)_pavedRoadPathSquare == (Object)null) { _pavedRoadPathSquare = LoadTextureFromResources("paved_road_v2_path_square.png"); } return _pavedRoadPathSquare; } } internal static Texture2D PavedRoadSquare { get { if ((Object)(object)_pavedRoadSquare == (Object)null) { _pavedRoadSquare = LoadTextureFromResources("paved_road_v2_square.png"); } return _pavedRoadSquare; } } internal static Texture2D Remove { get { if ((Object)(object)_remove == (Object)null) { _remove = LoadTextureFromResources("remove.png"); } return _remove; } } internal static Texture2D Cross { get { if ((Object)(object)_cross == (Object)null) { _cross = LoadTextureFromResources("cross.png"); } return _cross; } } internal static Texture2D Undo { get { if ((Object)(object)_undo == (Object)null) { _undo = LoadTextureFromResources("undo.png"); } return _undo; } } internal static Texture2D Redo { get { if ((Object)(object)_redo == (Object)null) { _redo = LoadTextureFromResources("redo.png"); } return _redo; } } internal static Texture2D Box { get { if ((Object)(object)_box == (Object)null) { _box = LoadTextureFromResources("box.png"); } return _box; } } internal static Sprite LoadEmbeddedTextureAsSprite(string fileName) { //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) Texture2D val = LoadTextureFromResources(fileName); if ((Object)(object)val == (Object)null) { return null; } Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 0.5f); float num = 100f; return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), val2, num); } internal static Texture2D LoadTextureFromResources(string fileName) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown string text = Path.GetExtension(fileName).ToLower(); if (text != ".png" && text != ".jpg") { Log.LogWarning("LoadTextureFromResources can only load png or jpg textures"); return null; } Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text2 = (from name in executingAssembly.GetManifestResourceNames() where name.EndsWith("." + fileName, StringComparison.OrdinalIgnoreCase) select name).FirstOrDefault(); if (text2 == null) { Log.LogWarning("Embedded texture not found: " + fileName); return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text2); if (stream == null) { Log.LogWarning("Could not open embedded texture: " + text2); return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val = new Texture2D(0, 0); object obj = ((Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule") ?? (from assembly in AppDomain.CurrentDomain.GetAssemblies() select assembly.GetType("UnityEngine.ImageConversion")).FirstOrDefault((Type type) => type != null))?.GetMethod("LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }))?.Invoke(null, new object[2] { val, memoryStream.ToArray() }); if (!(obj is bool) || !(bool)obj) { Log.LogWarning("Could not decode embedded texture: " + text2); return null; } return val; } } public class Overlay { private Particle[] particles = (Particle[])(object)new Particle[2]; private GameObject GameObject { get; } private Transform Transform { get; } public ParticleSystem ps { get; } public ParticleSystemRenderer psr { get; } public MainModule psm { get; } public bool Enabled { get { return GameObject.activeSelf; } set { GameObject.SetActive(value); } } public Vector3 Position { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Transform.position; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Transform.position = value; } } public Vector3 LocalPosition { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Transform.localPosition; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Transform.localPosition = value; } } public Quaternion Rotation { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Transform.rotation; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Transform.rotation = value; } } public Color Color { get { //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_001f: Unknown result type (might be due to invalid IL or missing references) int num = ps.GetParticles(particles, particles.Length); if (num <= 0) { return StartColor; } return Color32.op_Implicit(((Particle)(ref particles[Mathf.Min(1, num - 1)])).GetCurrentColor(ps)); } } public Color StartColor { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) MainModule val = psm; MinMaxGradient startColor = ((MainModule)(ref val)).startColor; return ((MinMaxGradient)(ref startColor)).color; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) MainModule val = psm; ((MainModule)(ref val)).startColor = MinMaxGradient.op_Implicit(value); } } public Vector3 LocalScale { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Transform.localScale; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Transform.localScale = value; } } public float StartSize { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) MainModule val = psm; MinMaxCurve startSize = ((MainModule)(ref val)).startSize; return ((MinMaxCurve)(ref startSize)).constant; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) MainModule val = psm; MinMaxCurve startSize = ((MainModule)(ref val)).startSize; if (!Mathf.Approximately(((MinMaxCurve)(ref startSize)).constant, value)) { MainModule main = ps.main; ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(value); if (particles.Length < ps.particleCount) { particles = (Particle[])(object)new Particle[ps.particleCount]; } int num = ps.GetParticles(particles, particles.Length); for (int i = 0; i < num; i++) { ((Particle)(ref particles[i])).startSize = value; } if (num > 0) { ps.SetParticles(particles, num); } } } } public float StartSpeed { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) MainModule val = psm; MinMaxCurve startSpeed = ((MainModule)(ref val)).startSpeed; return ((MinMaxCurve)(ref startSpeed)).constant; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) MainModule main = ps.main; ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(value); } } public float StartLifetime { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) MainModule val = psm; MinMaxCurve startLifetime = ((MainModule)(ref val)).startLifetime; return ((MinMaxCurve)(ref startLifetime)).constant; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) MainModule main = ps.main; ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(value); } } public bool SizeOverLifetimeEnabled { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime; return ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = value; } } public MinMaxCurve SizeOverLifetime { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime; return ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = value; } } public Overlay(Transform transform) { //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) Transform = transform; GameObject = ((Component)transform).gameObject; ps = ((Component)transform).GetComponentInChildren<ParticleSystem>(); psr = ((Component)transform).GetComponentInChildren<ParticleSystemRenderer>(); psm = ps.main; } } public abstract class OverlayVisualizer : MonoBehaviour { protected Overlay primary; protected Overlay secondary; protected Overlay tertiary; protected HoverInfo hoverInfo; private readonly List<Heightmap> heightmaps = new List<Heightmap>(); internal static readonly Vector3 VerticalOffset = new Vector3(0f, 0.075f, 0f); internal void Refresh() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (primary == null) { Transform val = ((Component)this).transform.Find("_GhostOnly"); Transform val2 = Object.Instantiate<Transform>(val, ((Component)this).transform); Transform transform = Object.Instantiate<Transform>(val2, ((Component)this).transform); primary = new Overlay(val); secondary = new Overlay(val2); tertiary = new Overlay(transform); hoverInfo = new HoverInfo(val2); tertiary.StartColor = Color.white; primary.Enabled = false; secondary.Enabled = false; tertiary.Enabled = false; Initialize(); } OnRefresh(); } protected abstract void Initialize(); protected abstract void OnRefresh(); protected void SpeedUp(Overlay overlay) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) AnimationCurve val = new AnimationCurve(); val.AddKey(0f, 0f); val.AddKey(0.5f, 1f); MinMaxCurve sizeOverLifetime = default(MinMaxCurve); ((MinMaxCurve)(ref sizeOverLifetime))..ctor(1f, val); overlay.StartLifetime = 2f; overlay.SizeOverLifetime = sizeOverLifetime; } protected void Freeze(Overlay overlay) { overlay.StartSpeed = 0f; overlay.SizeOverLifetimeEnabled = false; } protected void VisualizeTerraformingBounds(Overlay overlay) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) overlay.StartSize = 3f; ((Renderer)overlay.psr).material.mainTexture = (Texture)(object)IconCache.Box; overlay.LocalPosition = VerticalOffset; } protected void VisualizeIconInsideTerraformingBounds(Overlay overlay, Texture iconTexture) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) overlay.StartSize = 2.5f; ((Renderer)overlay.psr).material.mainTexture = iconTexture; overlay.LocalPosition = VerticalOffset; } protected void VisualizeRecoloringBounds(Overlay overlay) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) overlay.StartSize = 3f; ((Renderer)overlay.psr).material.mainTexture = (Texture)(object)IconCache.Box; overlay.LocalPosition = VerticalOffset; } protected void SnapToPaintGrid(Overlay core, Overlay feather) { //IL_0011: 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_003f: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00aa: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014c: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) heightmaps.Clear(); Heightmap.FindHeightmap(((Component)this).transform.position, 1f, heightmaps); if (heightmaps.Count == 0) { core.LocalPosition = VerticalOffset; feather.LocalPosition = VerticalOffset; return; } Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(float.PositiveInfinity, float.PositiveInfinity); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(float.NegativeInfinity, float.NegativeInfinity); float num = 0f; foreach (Heightmap heightmap in heightmaps) { if (PreciseTerrainModifier.TryGetPaintMaskWorldBounds(heightmap, ((Component)this).transform.position, 1, out var min, out var max)) { val = Vector2.Min(val, min); val2 = Vector2.Max(val2, max); num = Mathf.Max(num, heightmap.m_scale); } } if (float.IsPositiveInfinity(val.x)) { core.LocalPosition = VerticalOffset; feather.LocalPosition = VerticalOffset; } else { SetBounds(core, val - Vector2.one * num, val2 + Vector2.one * num); SetBounds(feather, val - Vector2.one * num * 2f, val2 + Vector2.one * num * 2f); } } private void SetBounds(Overlay overlay, Vector2 min, Vector2 max) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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_0007: 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_000e: 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_002f: 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_0042: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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) //IL_0083: Unknown result type (might be due to invalid IL or missing references) Vector2 val = max - min; float num = (overlay.StartSize = Mathf.Max(val.x, val.y)); overlay.LocalScale = new Vector3(val.x / num, 1f, val.y / num); overlay.Position = new Vector3((min.x + max.x) * 0.5f, ((Component)this).transform.position.y + VerticalOffset.y, (min.y + max.y) * 0.5f); } protected void VisualizeIconInsideRecoloringBounds(Overlay overlay, Texture iconTexture) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) overlay.StartSize = 2.5f; ((Renderer)overlay.psr).material.mainTexture = iconTexture; overlay.Position = ((Component)this).transform.position + VerticalOffset; } } public abstract class HoverInfoEnabled : OverlayVisualizer { protected override void Initialize() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) hoverInfo.Color = secondary.StartColor; } protected override void OnRefresh() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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) hoverInfo.Enabled = TerrainTools.IsHoverInforEnabled; if (hoverInfo.Enabled) { hoverInfo.RotateToPlayer(); Vector3 position = ((Component)this).transform.position; hoverInfo.Text = $"x: {position.x:0}, y: {position.y:0.000}, z: {position.z:0}"; } } } [HarmonyPatch(typeof(Piece), "SetInvalidPlacementHeightlight")] public static class OverlayVisualizationRedshiftHeigthlightBlocker { private static bool Prefix(Piece __instance) { return !Object.op_Implicit((Object)(object)((Component)__instance).GetComponentInChildren<OverlayVisualizer>()); } } public class LevelGroundOverlayVisualizer : HoverInfoEnabled { protected override void Initialize() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) base.Initialize(); Freeze(secondary); Freeze(tertiary); VisualizeRecoloringBounds(secondary); VisualizeRecoloringBounds(tertiary); tertiary.StartColor = new Color(1f, 1f, 1f, 0.3f); } protected override void OnRefresh() { SnapToPaintGrid(secondary, tertiary); base.OnRefresh(); primary.Enabled = false; secondary.Enabled = true; tertiary.Enabled = true; } } public class RaiseGroundOverlayVisualizer : HoverInfoEnabled { protected override void Initialize() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) base.Initialize(); Freeze(secondary); Freeze(tertiary); VisualizeTerraformingBounds(secondary); VisualizeTerraformingBounds(tertiary); secondary.LocalScale = Vector3.one; tertiary.LocalScale = Vector3.one; } protected override void OnRefresh() { //IL_0006: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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) Heightmap val = Heightmap.FindHeightmap(((Component)this).transform.position); float num = (Object.op_Implicit((Object)(object)val) ? val.m_scale : 1f); float num2 = PreciseRaiseMath.SlopePivot(HardnessModifier.CurrentRaisePower(((Component)this).GetComponent<TerrainOp>().m_settings.m_raisePower)); secondary.StartSize = Mathf.Max(0.1f, 2f * num2 * num); tertiary.StartSize = 4f * num; base.OnRefresh(); primary.Enabled = false; secondary.Enabled = true; GroundLevelSpinner.Refresh(); Vector3 localPosition = secondary.LocalPosition; localPosition.y = OverlayVisualizer.VerticalOffset.y + GroundLevelSpinner.Value; secondary.LocalPosition = localPosition; Vector3 val2 = secondary.Position - OverlayVisualizer.VerticalOffset; if (GroundLevelSpinner.Value > 0f) { float value = GroundLevelSpinner.Value; hoverInfo.Text = $"x: {val2.x:0}, y: {val2.y - value:0.000}, z: {val2.z:0}\n\nh: +{value:0.000}"; } else { hoverInfo.Text = $"x: {val2.x:0}, y: {val2.y:0.000}, z: {val2.z:0}"; } tertiary.Enabled = true; } } public class SquarePathOverlayVisualizer : HoverInfoEnabled { protected override void Initialize() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) base.Initialize(); Freeze(secondary); Freeze(tertiary); VisualizeRecoloringBounds(secondary); VisualizeRecoloringBounds(tertiary); tertiary.StartColor = new Color(1f, 1f, 1f, 0.3f); } protected override void OnRefresh() { SnapToPaintGrid(secondary, tertiary); base.OnRefresh(); primary.Enabled = false; secondary.Enabled = true; tertiary.Enabled = true; } } public class CultivateOverlayVisualizer : HoverInfoEnabled { protected override void Initialize() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) base.Initialize(); Freeze(secondary); Freeze(tertiary); VisualizeRecoloringBounds(secondary); VisualizeRecoloringBounds(tertiary); tertiary.StartColor = new Color(1f, 1f, 1f, 0.3f); } protected override void OnRefresh() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) SnapToPaintGrid(secondary, tertiary); base.OnRefresh(); primary.Enabled = false; secondary.Enabled = true; tertiary.Enabled = true; hoverInfo.Color = secondary.Color; } } public class SeedGrassOverlayVisualizer : HoverInfoEnabled { protected override void Initialize() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) base.Initialize(); Freeze(secondary); Freeze(tertiary); VisualizeRecoloringBounds(secondary); VisualizeRecoloringBounds(tertiary); tertiary.StartColor = new Color(1f, 1f, 1f, 0.3f); primary.StartSize = 4f; primary.LocalPosition = new Vector3(0f, 2.5f, 0f); } protected override void OnRefresh() { SnapToPaintGrid(secondary, tertiary); base.OnRefresh(); primary.Enabled = true; secondary.Enabled = true; tertiary.Enabled = true; } } public class RemoveModificationsOverlayVisualizer : OverlayVisualizer { internal void SetScale(Vector3 scale) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0028: Unknown result type (might be due to invalid IL or missing references) if (primary != null && !(scale == Vector3.zero)) { primary.LocalScale = scale; secondary.LocalScale = scale; } } protected override void Initialize() { Freeze(primary); SpeedUp(secondary); VisualizeTerraformingBounds(primary); VisualizeIconInsideTerraformingBounds(secondary, (Texture)(object)IconCache.Cross); primary.StartSize = 2f; secondary.StartSize = 1.5f; } protected override void OnRefresh() { primary.Enabled = true; secondary.Enabled = true; } } public abstract class UndoRedoModificationsOverlayVisualizer : OverlayVisualizer { protected override void Initialize() { Freeze(primary); Freeze(secondary); VisualizeRecoloringBounds(primary); VisualizeIconInsideRecoloringBounds(secondary, (Texture)(object)Icon()); } protected override void OnRefresh() { primary.Enabled = true; secondary.Enabled = true; } protected abstract Texture2D Icon(); } public class UndoModificationsOverlayVisualizer : UndoRedoModificationsOverlayVisualizer { protected override Texture2D Icon() { return IconCache.Undo; } } public class RedoModificationsOverlayVisualizer : UndoRedoModificationsOverlayVisualizer { protected override Texture2D Icon() { return IconCache.Redo; } } } namespace TerrainTools.Patches { [HarmonyPatch(typeof(GameCamera))] internal static class GameCameraPatch { [HarmonyTranspiler] [HarmonyPatch("UpdateCamera")] private static IEnumerable<CodeInstruction> UpdateCameraTranspiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = instructions.ToList(); MethodInfo target = AccessTools.Method(typeof(Player), "CanRotatePiece", (Type[])null, (Type[])null); List<(CodeInstruction, int)> list2 = (from item in list.Select((CodeInstruction instruction, int index) => (instruction: instruction, index: index)) where item.instruction.opcode == OpCodes.Callvirt && object.Equals(item.instruction.operand, target) select item).ToList(); if (list2.Count != 1) { Log.LogWarning($"GameCamera.UpdateCamera patch skipped: expected one CanRotatePiece call, found {list2.Count}"); return list; } CodeInstruction val = Transpilers.EmitDelegate<Func<Player, bool>>((Func<Player, bool>)UpdateCamera_BlockScroll_Delegate); val.labels.AddRange(list2[0].Item1.labels); val.blocks.AddRange(list2[0].Item1.blocks); list[list2[0].Item2] = val; return list; } private static bool UpdateCamera_BlockScroll_Delegate(Player localPlayer) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) Piece val = ((localPlayer != null) ? localPlayer.GetSelectedPiece() : null); if ((Object)(object)((val != null) ? ((Component)val).gameObject : null) != (Object)null && (Object.op_Implicit((Object)(object)((Component)val).gameObject.GetComponentInChildren<RaiseGroundOverlayVisualizer>()) || (TerrainTools.IsEnableRadiusModifier && Input.GetKey(TerrainTools.RadiusKey)) || (TerrainTools.IsEnableHardnessModifier && Input.GetKey(TerrainTools.HardnessKey)))) { return true; } return localPlayer.CanRotatePiece(); } } [HarmonyPatch(typeof(Heightmap), "RebuildRenderMesh")] internal static class HeightmapPaintGridPatch { [HarmonyPostfix] private static void Postfix(Heightmap __instance) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (__instance.m_isDistantLod || !Object.op_Implicit((Object)(object)__instance.m_renderMesh)) { return; } int num = __instance.m_width + 1; List<Vector2> s_tempUVs = Heightmap.s_tempUVs; if (num <= 1 || __instance.m_renderMesh.vertexCount != num * num || s_tempUVs.Count != num * num) { Log.LogWarning("Paint grid UV alignment skipped: unexpected Heightmap mesh dimensions."); return; } for (int i = 0; i < s_tempUVs.Count; i++) { s_tempUVs[i] = new Vector2(PaintGridMath.TexelCenterUv(i % num, __instance.m_width), PaintGridMath.TexelCenterUv(i / num, __instance.m_width)); } __instance.m_renderMesh.SetUVs(0, s_tempUVs); } } [HarmonyPatch] internal class PlayerPatch { [HarmonyPostfix] [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] private static void UpdatePlacementGhostPostfix(Player __instance) { //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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)__instance) || !((Character)__instance).InPlaceMode() || ((Character)__instance).IsDead() || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)__instance.m_placementGhost) || !__instance.m_placementGhost.activeInHierarchy) { return; } OverlayVisualizer component = __instance.m_placementGhost.GetComponent<OverlayVisualizer>(); if (!Object.op_Implicit((Object)(object)component)) { return; } Vector3 position = __instance.m_placementGhost.transform.position; Heightmap val = Heightmap.FindHeightmap(position); if (Object.op_Implicit((Object)(object)val)) { int num = default(int); int num2 = default(int); val.WorldToVertex(position, ref num, ref num2); position.x = ((Component)val).transform.position.x + (float)(num - val.m_width / 2) * val.m_scale; position.z = ((Component)val).transform.position.z + (float)(num2 - val.m_width / 2) * val.m_scale; __instance.m_placementGhost.transform.position = position; TerrainOp component2 = __instance.m_placementGhost.GetComponent<TerrainOp>(); if (Object.op_Implicit((Object)(object)component2) && !PreciseTerrainModifier.HasAreaAccess(component2, position, flash: false)) { __instance.m_placementStatus = (PlacementStatus)4; } component.Refresh(); RadiusModifier.RefreshGhostScale(__instance); } } } } namespace TerrainTools.Helpers { public static class GroundLevelSpinner { public const string MouseScrollWheel = "Mouse ScrollWheel"; public const float ScrollPrecision = 0.05f; public const float SuperiorScrollPrecisionMultiplier = 0.2f; public const float MaxSpinner = 1f; public const float MinSpinner = 0f; private static int lastRefreshFrame = -1; public static float Value { get; private set; } = 1f; public static void Refresh() { if (lastRefreshFrame != Time.frameCount) { lastRefreshFrame = Time.frameCount; float num = ScrollDelta(); if (num > 0f) { Up(num); } if (num < 0f) { Down(num); } } } private static float ScrollDelta() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (TerrainTools.IsEnableHardnessModifier && Input.GetKey(TerrainTools.HardnessKey)) { return 0f; } float num = Input.GetAxis("Mouse ScrollWheel"); if (num != 0f) { num = ((num > 0f) ? 0.05f : (-0.05f)); } return num; } private static void Up(float scrollDelta) { if (Value + scrollDelta > 1f) { Value = 1f; } else { Value = Mathf.Round((Value + scrollDelta) * 100f) / 100f; } } private static void Down(float scrollDelta) { if (Value + scrollDelta < 0f) { Value = 0f; } else { Value = Mathf.Round((Value + scrollDelta) * 100f) / 100f; } } } [HarmonyPatch] internal static class HardnessModifier { private static bool SmoothToolIsInUse; private static float lastModdedSmoothPwr; private static float lastTotalSmoothDelta; private const float MinSmoothPwr = 1f; private const float MaxSmoothPwr = 30f; private static bool RaiseToolIsInUse; private static TerrainOp activeRaiseTool; private static float lastModdedRaisePwr; private static float lastTotalRaiseDelta; private const float MinRaisePwr = 0.05f; private const float MaxRaisePwr = 1f; private const float DisplayThreshold = 0.9f; private static float lastDisplayedSmoothHardness; private static float lastDisplayedRaiseHardness; internal static void Tick(Player __instance) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } if (!((Character)__instance).InPlaceMode() || Hud.IsPieceSelectionVisible()) { if (SmoothToolIsInUse) { SmoothToolIsInUse = false; lastModdedSmoothPwr = 0f; lastTotalSmoothDelta = 0f; lastDisplayedSmoothHardness = -1f; } SelectRaiseTool(null); } else { Piece selectedPiece = __instance.GetSelectedPiece(); TerrainOp val = ((Object.op_Implicit((Object)(object)selectedPiece) && Object.op_Implicit((Object)(object)((Component)selectedPiece).gameObject)) ? ((Component)selectedPiece).gameObject.GetComponent<TerrainOp>() : null); SelectRaiseTool((Object.op_Implicit((Object)(object)val) && val.m_settings.m_raise) ? val : null); if (ShouldModifyHardness()) { SetPower(__instance, Input.mouseScrollDelta.y * TerrainTools.HardnessScrollScale); } } } internal static bool ShouldModifyHardness() { //IL_0007: 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) if (TerrainTools.IsEnableHardnessModifier && Input.GetKey(TerrainTools.HardnessKey)) { return Input.mouseScrollDelta.y != 0f; } return false; } internal static float CurrentRaisePower(float defaultPower) { if (!RaiseToolIsInUse) { return ModifyRaisePower(defaultPower, 0f); } return lastModdedRaisePwr; } private static void SelectRaiseTool(TerrainOp terrainOp) { if (!((Object)(object)activeRaiseTool == (Object)(object)terrainOp)) { activeRaiseTool = terrainOp; RaiseToolIsInUse = false; lastModdedRaisePwr = 0f; lastTotalRaiseDelta = 0f; lastDisplayedRaiseHardness = -1f; } } [HarmonyPrefix] [HarmonyPriority(600)] [HarmonyPatch(typeof(TerrainOp), "Awake")] private static void AwakePrefix(TerrainOp __instance) { if (!Object.op_Implicit((Object)(object)__instance) || !Object.op_Implicit((Object)(object)((Component)__instance).gameObject)) { return; } OverlayVisualizer component = ((Component)__instance).gameObject.GetComponent<OverlayVisualizer>(); if (!Object.op_Implicit((Object)(object)component) || component is RaiseGroundOverlayVisualizer) { if (lastTotalRaiseDelta != 0f || lastTotalSmoothDelta != 0f) { PreciseTerrainModifier.EnsureRuntimeSettings(__instance, isReset: false, (Object)(object)component != (Object)null); } if (__instance.m_settings.m_raise) { __instance.m_settings.m_raisePower = ModifyRaisePower(__instance.m_settings.m_raisePower, lastTotalRaiseDelta); Log.LogInfo($"Applying raise Power {__instance.m_settings.m_raisePower}", LogLevel.Medium); } if (__instance.m_settings.m_smooth) { __instance.m_settings.m_smoothPower = ModifySmoothPower(__instance.m_settings.m_smoothPower, lastTotalSmoothDelta); Log.LogInfo($"Applying smooth Power {__instance.m_settings.m_smoothPower}", LogLevel.Medium); } } } private static void SetPower(Player player, float delta) { Piece selectedPiece = player.GetSelectedPiece(); if (!Object.op_Implicit((Object)(object)selectedPiece) || !Object.op_Implicit((Object)(object)((Component)selectedPiece).gameObject)) { return; } OverlayVisualizer component = ((Component)selectedPiece).gameObject.GetComponent<OverlayVisualizer>(); if (Object.op_Implicit((Object)(object)component) && !(component is RaiseGroundOverlayVisualizer)) { return; } TerrainOp component2 = ((Component)selectedPiece).gameObject.GetComponent<TerrainOp>(); if (!Object.op_Implicit((Object)(object)component2)) { return; } SetSmoothPower(component2, delta); SetRaisePower(component2, delta); List<string> list = new List<string>(); if (SmoothToolIsInUse) { float smoothPowerDisplayValue = GetSmoothPowerDisplayValue(lastModdedSmoothPwr); if (Mathf.Abs(smoothPowerDisplayValue - lastDisplayedSmoothHardness) > 0.9f) { lastDisplayedSmoothHardness = Mathf.Round(smoothPowerDisplayValue); list.Add(string.Format("{0} {1:0}%", Localization.instance.Localize("$atmc_smoothing_hardness"), smoothPowerDisplayValue)); } } if (RaiseToolIsInUse) { float raisePowerDisplayValue = GetRaisePowerDisplayValue(lastModdedRaisePwr); if (Mathf.Abs(raisePowerDisplayValue - lastDisplayedRaiseHardness) > 0.9f) { lastDisplayedRaiseHardness = Mathf.Round(raisePowerDisplayValue); list.Add(string.Format("{0} {1:0}%", Localization.instance.Localize("$atmc_raise_hardness"), raisePowerDisplayValue)); } } if (SmoothToolIsInUse || RaiseToolIsInUse) { Piece val = (Object.op_Implicit((Object)(object)player.m_placementGhost) ? player.m_placementGhost.GetComponent<Piece>() : null); Sprite val2 = (Object.op_Implicit((Object)(object)val) ? val.m_icon : null); if ((Object)(object)val2 != (Object)null && list.Count > 0) { ((Character)player).Message((MessageType)2, string.Join("\n", list.ToArray()), 0, val2, false); } } } private static void SetSmoothPower(TerrainOp terrainOp, float delta) { if (terrainOp.m_settings.m_smooth) { Log.LogInfo($"Adjusting Smooth Power by {delta}", LogLevel.High); float num = (SmoothToolIsInUse ? lastModdedSmoothPwr : terrainOp.m_settings.m_smoothPower); SmoothToolIsInUse = true; lastModdedSmoothPwr = ModifySmoothPower(num, delta); lastTotalSmoothDelta += lastModdedSmoothPwr - num; Log.LogInfo($"Total smooth power delta {lastTotalSmoothDelta}", LogLevel.High); } } private static void SetRaisePower(TerrainOp terrainOp, float delta) { if (terrainOp.m_settings.m_raise) { SelectRaiseTool(terrainOp); delta = ConvertSmoothDeltaToRaiseDelta(delta); Log.LogInfo($"Adjusting Raise Power by {delta}", LogLevel.High); float num = (RaiseToolIsInUse ? lastModdedRaisePwr : terrainOp.m_settings.m_raisePower); RaiseToolIsInUse = true; lastModdedRaisePwr = ModifyRaisePower(num, delta); lastTotalRaiseDelta += lastModdedRaisePwr - num; Log.LogInfo($"Total raise power delta {lastTotalRaiseDelta}", LogLevel.High); } } private static float ConvertSmoothDeltaToRaiseDelta(float delta) { float num = delta / 29f; return -1f * num * 0.95f; } private static float GetSmoothPowerDisplayValue(float power) { return (power - 1f) / 29f * 100f; } private static float GetRaisePowerDisplayValue(float power) { return (1f - power) / 0.95f * 100f; } private static float ModifySmoothPower(float power, float delta) { return Mathf.Clamp(power + delta, 1f, 30f); } private static float ModifyRaisePower(float power, float delta) { return Mathf.Clamp(power + delta, 0.05f, 1f); } } internal static class InitManager { private static bool HasInitialized = false; private static bool HasLoggedTerrainOpFallback = false; internal static readonly Dictionary<string, GameObject> ToolRefs = new Dictionary<string, GameObject>(); private static readonly Dictionary<string, List<int>> InsertionIndexes = new Dictionary<string, List<int>>(); internal static bool IsCustomTool(GameObject gameObject) { if (Object.op_Implicit((Object)(object)gameObject)) { return ToolConfigs.ToolConfigsMap.ContainsKey(((Object)gameObject).name.Replace("(Clone)", "")); } return false; } internal static void InitToolPieces() { if (HasInitialized) { RefreshTerrainOpRegistrations(); return; } FixVanillaToolDescriptions(); foreach (string key in ToolConfigs.ToolConfigsMap.Keys) { try { ToolDB toolDB = ToolConfigs.ToolConfigsMap[key]; toolDB.prefab = MakeToolPiece(toolDB); } catch (Exception arg) { Log.LogWarning($"Failed to create {key}: {arg}"); } } HasInitialized = true; UpdateTools(); } internal static void RefreshTerrainOpRegistrations() { foreach (ToolDB value in ToolConfigs.ToolConfigsMap.Values) { if (Object.op_Implicit((Object)(object)value.prefab)) { EnsureTerrainOpRegistered(value.prefab); } } } [HarmonyPostfix] [HarmonyPatch(typeof(ObjectDB), "UpdateRegisters")] private static void ObjectDBUpdateRegistersPostfix() { if (HasInitialized) { RefreshTerrainOpRegistrations(); } } internal static void FixVanillaToolDescriptions() { SetDescription("mud_road_v2", "$atmc_vanilla_level_desc"); SetDescription("raise_v2", "$atmc_vanilla_raise_desc"); SetDescription("path_v2", "$atmc_vanilla_path_desc"); SetDescription("paved_road_v2", "$atmc_vanilla_paved_desc"); SetDescription("cultivate_v2", "$atmc_vanilla_cultivate_desc"); SetDescription("replant_v2", "$atmc_vanilla_replant_desc"); } private static void SetDescription(string prefabName, string description) { GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName); Piece val = ((prefab != null) ? prefab.GetComponent<Piece>() : null); if ((Object)(object)val != (Object)null) { val.m_description = description; } else { Log.LogWarning("Could not set description for: " + prefabName); } } internal static void UpdatePlugin() { UpdateTools(); UpdateShovelRecipe(); ConfigManager.Save(); TerrainTools.UpdatePlugin = false; } private static void UpdateTools() { if (!HasInitialized) { return; } ForceUnequipTerrainTools(); foreach (ToolDB value in ToolConfigs.ToolConfigsMap.Values) { RemovePieceInPieceTable(value); } foreach (string key in ToolConfigs.ToolConfigsMap.Keys) { if (TerrainTools.IsToolEnabled(key)) { ToolDB toolDB = ToolConfigs.ToolConfigsMap[key]; if (!Object.op_Implicit((Object)(object)toolDB.prefab)) { Log.LogWarning("Skipping unavailable terrain tool: " + key); } else { RegisterPieceInPieceTable(toolDB.prefab, toolDB.pieceTable, toolDB.insertIndex); } } } } internal static void UpdatePieceTables() { foreach (string key in ToolConfigs.ToolConfigsMap.Keys) { try { ToolDB toolDB = ToolConfigs.ToolConfigsMap[key]; toolDB.prefab = MakeToolPiece(toolDB); RegisterPieceInPieceTable(toolDB.prefab, toolDB.pieceTable, toolDB.insertIndex); } catch (Exception arg) { Log.LogWarning($"Failed to create {key}: {arg}"); } } } private static void UpdateShovelRecipe() { if (Shovel.TryGetShovel(out var shovel)) { shovel.Recipe.Recipe.m_enabled = TerrainTools.IsShovelEnabled; } } private static void ForceUnequipTerrainTools() { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return; } ItemData rightItem = ((Humanoid)Player.m_localPlayer).GetRightItem(); if (rightItem != null) { if (rightItem.m_shared.m_name == "$item_cultivator") { Log.LogWarning("AdvancedTerrainModifiers updated through config change, unequipping cultivator"); ((Humanoid)Player.m_localPlayer).HideHandItems(false, true); } if (rightItem.m_shared.m_name == "$item_hoe") { Log.LogWarning("AdvancedTerrainModifiers updated through config change, unequipping hoe"); ((Humanoid)Player.m_localPlayer).HideHandItems(false, true); } } } internal static GameObject MakeToolPiece(ToolDB toolDB) { //IL_0052: 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_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) GameObject val = PrefabManager.Instance.CreateClonedPrefab(toolDB.name, toolDB.basePrefab); if ((Object)(object)val == (Object)null) { return null; } Piece component = val.GetComponent<Piece>(); component.m_icon = Sprite.Create(toolDB.icon, new Rect(0f, 0f, (float)((Texture)toolDB.icon).width, (float)((Texture)toolDB.icon).height), Vector2.zero); component.m_name = toolDB.pieceName; component.m_description = toolDB.pieceDesc; if (toolDB.requirements != null) { component.m_resources = toolDB.requirements; } PreciseTerrainModifier.RuntimeSettings runtimeSettings = PreciseTerrainModifier.EnsureRuntimeSettings(val.GetComponent<TerrainOp>(), toolDB.overlayType == typeof(RemoveModificationsOverlayVisualizer), toolDB.overlayType != null); ((Settings)runtimeSettings).m_level = UpdateValueIfNeeded(((Settings)runtimeSettings).m_level, toolDB.level); ((Settings)runtimeSettings).m_levelRadius = UpdateValueIfNeeded(((Settings)runtimeSettings).m_levelRadius, toolDB.levelRadius); ((Settings)runtimeSettings).m_raise = UpdateValueIfNeeded(((Settings)runtimeSettings).m_raise, toolDB.raise); ((Settings)runtimeSettings).m_raiseRadius = UpdateValueIfNeeded(((Settings)runtimeSettings).m_raiseRadius, toolDB.raiseRadius); ((Settings)runtimeSettings).m_raisePower = UpdateValueIfNeeded(((Settings)runtimeSettings).m_raisePower, toolDB.raisePower); ((Settings)runtimeSettings).m_raiseDelta = UpdateValueIfNeeded(((Settings)runtimeSettings).m_raiseDelta, toolDB.raiseDelta); ((Settings)runtimeSettings).m_smooth = UpdateValueIfNeeded(((Settings)runtimeSettings).m_smooth, toolDB.smooth); ((Settings)runtimeSettings).m_smoothRadius = UpdateValueIfNeeded(((Settings)runtimeSettings).m_smoothRadius, toolDB.smoothRadius); ((Settings)runtimeSettings).m_smoothPower = UpdateValueIfNeeded(((Settings)runtimeSettings).m_smoothPower, toolDB.smoothPower); ((Settings)runtimeSettings).m_paintCleared = UpdateValueIfNeeded(((Settings)runtimeSettings).m_paintCleared, toolDB.clearPaint); ((Settings)runtimeSettings).m_paintRadius = UpdateValueIfNeeded(((Settings)runtimeSettings).m_paintRadius, toolDB.paintRadius); if (toolDB.overlayType != null) { val.AddComponent(toolDB.overlayType); } if (toolDB.invertGhost) { Transform val2 = val.transform.Find("_GhostOnly"); if ((Object)(object)val2 != (Object)null) { val2.localRotation = Quaternion.Euler(270f, 0f, 0f); val2.localPosition += new Vector3(0f, 2f, 0f); } } return val; } private static T UpdateValueIfNeeded<T>(T source, T? newValue) where T : struct { if (!newValue.HasValue) { return source; } return newValue.Value; } private static T UpdateValueIfNeeded<T>(T source, T newValue) { if (newValue == null) { return source; } return newValue; } private static void RegisterPieceInPieceTable(GameObject prefab, string pieceTable, int position = -1) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { throw new Exception("Prefab " + ((Object)prefab).name + " has no Piece component attached"); } PieceTable pieceTable2 = PieceManager.Instance.GetPieceTable(pieceTable); if ((Object)(object)pieceTable2 == (Object)null) { throw new Exception("Could not find PieceTable " + pieceTable); } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); if ((Object)(object)ZNetScene.instance != (Object)null && !ZNetScene.instance.m_namedPrefabs.ContainsKey(stableHashCode)) { PrefabManager.Instance.RegisterToZNetScene(prefab); } EnsureTerrainOpRegistered(prefab); if (pieceTable2.m_pieces.Contains(prefab)) { Log.LogDebug("Already added piece " + ((Object)prefab).name); return; } if (!InsertionIndexes.ContainsKey(pieceTable)) { InsertionIndexes[pieceTable] = new List<int>(); } int num = 0; if (position >= 0) { num = position + InsertionIndexes[pieceTable].Where((int x) => x <= position).Count(); } else if (num >= pieceTable2.m_pieces.Count && pieceTable2.m_pieces.Count != 0) { Log.LogWarning("Piece insertion index is out of bounds"); } if (position >= 0 && num < pieceTable2.m_pieces.Count) { pieceTable2.m_pieces.Insert(num, prefab); InsertionIndexes[pieceTable].Add(position); } else { pieceTable2.m_pieces.Add(prefab); InsertionIndexes[pieceTable].Add(pieceTable2.m_pieces.Count - 1); } Log.LogDebug("Added piece " + ((Object)prefab).name + " | Token: " + PieceExtension.TokenName(component)); } internal static void EnsureTerrainOpRegistered(GameObject prefab) { ObjectDB instance = ObjectDB.instance; TerrainOp val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<TerrainOp>() : null); if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)val)) { return; } int prefabHash = instance.GetPrefabHash(prefab); if (instance.m_terrainOpsByHash.TryGetValue(prefabHash, out var value)) { if ((Object)(object)value != (Object)(object)val) { Log.LogWarning($"TerrainOp prefab hash collision for {((Object)prefab).name} ({prefabHash}); keeping the registered prefab"); } return; } if (!instance.m_terrainOps.Contains(val)) { instance.m_terrainOps.Add(val); } instance.m_terrainOpsByHash.Add(prefabHash, val); if (!HasLoggedTerrainOpFallback) { HasLoggedTerrainOpFallback = true; Log.LogInfo("Installed Jotunn did not register custom TerrainOps; using the AdvancedTerrainModifiers fallback"); } Log.LogDebug("Registered TerrainOp " + ((Object)prefab).name + " in ObjectDB"); } private static void RemovePieceInPieceTable(ToolDB toolDB) { GameObject prefab = toolDB.prefab; if (!Object.op_Implicit((Object)(object)prefab)) { return; } PieceTable pieceTable = PieceManager.Instance.GetPieceTable(toolDB.pieceTable); if ((Object)(object)pieceTable == (Object)null) { throw new Exception("Could not find PieceTable " + toolDB.pieceTable); } int num = pieceTable.m_pieces.IndexOf(prefab); if (num < 0) { return; } pieceTable.m_pieces.Remove(prefab); Log.LogDebug("Removed piece " + ((Object)prefab).name); List<int> list = InsertionIndexes[toolDB.pieceTable]; if (!list.Contains(num)) { return; } list.Remove(num); for (int i = 0; i < list.Count; i++) { if (list[i] > num) { list[i]--; } } } } internal static class PaintGridMath { internal static float TexelCenterUv(int index, int terrainWidth) { return ((float)index + 0.5f) / ((float)terrainWidth + 1f); } internal static void GetAxisIndices(int terrainWidth, int centerIndex, int radius, out int first, out int last) { first = Math.Max(0, centerIndex - radius); last = Math.Min(terrainWidth, centerIndex + radius); } internal static bool TryGetAxisBounds(int terrainWidth, float vertexScale, float zoneCenter, int firstPaintedTexel, int lastPaintedTexel, out float min, out float max) { if (firstPaintedTexel > lastPaintedTexel) { min = 0f; max = 0f; return false; } float num = (float)terrainWidth * vertexScale * 0.5f; float num2 = zoneCenter - num; min = num2 + (float)firstPaintedTexel * vertexScale; max = num2 + (float)lastPaintedTexel * vertexScale; return true; } } internal static class PreciseRaiseMath { internal const int ModifiedRadius = 1; internal const int InfluenceRadius = 2; internal const float MinPower = 0.05f; internal const float MaxPower = 1f; internal static bool TryGetTargetHeight(float tileHeight, float refHeight, float delta, float weight, out float targetHeight) { targetHeight = refHeight + delta; if (delta < 0f && targetHeight > tileHeight) { return false; } if (delta >= 0f) { if (targetHeight < tileHeight) { return false; } if (targetHeight > tileHeight + delta) { targetHeight = tileHeight + delta; } } if (weight < 1f) { targetHeight = tileHeight + (targetHeight - tileHeight) * weight; } return true; } internal static float Weight(int dx, int dz, float power) { int num = Math.Max(Math.Abs(dx), Math.Abs(dz)); if (num >= 2) { return 0f; } float num2 = SlopePivot(power); if ((float)num <= num2) { return 1f; } return (float)(2 - num) / (2f - num2); } internal static float SlopePivot(float power) { power = (float.IsNaN(power) ? 1f : Math.Max(0.05f, Math.Min(1f, power))); float num = (1f - power) / 0.95f; return 1f * num; } } [HarmonyPatch] public static class PreciseTerrainModifier { internal sealed class RuntimeSettings : Settings { internal bool IsReset; internal bool HasOverlay; } public const int FixedRadius = 1; public const int FixedPaintRadius = 1; private const int SettingsPayloadMagic = 1096043859; private const int SettingsPayloadVersion = 1; private const float MinRadius = 0.5f; private const float MaxSmoothPower = 30f; internal static RuntimeSettings EnsureRuntimeSettings(TerrainOp terrainOp, bool isReset = false, bool hasOverlay = false) { if (terrainOp.m_settings is RuntimeSettings runtimeSettings) { runtimeSettings.IsReset |= isReset; runtimeSettings.HasOverlay |= hasOverlay; return runtimeSettings; } return (RuntimeSettings)(object)(terrainOp.m_settings = (Settings)(object)CopySettings(terrainOp.m_settings, isReset, hasOverlay)); } public static bool IsPrecisionModifier(float radius) { return radius == float.NegativeInfinity; } [HarmonyPrefix] [HarmonyPatch(typeof(ClutterSystem), "ResetGrass")] private static void ResetGrassPrefix(ClutterSystem __instance, Vector3 center, ref float radius) { if (IsPrecisionModifier(radius)) { radius = 1f; } } [HarmonyPrefix] [HarmonyPatch(typeof(TerrainComp), "ApplyOperation")] private static bool ApplyOperationPrefix(TerrainComp __instance, TerrainOp modifier) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)modifier) || !Object.op_Implicit((Object)(object)((Component)modifier).gameObject)) { return true; } OverlayVisualizer componentInChildren = ((Component)modifier).gameObject.GetComponentInChildren<OverlayVisualizer>(); RuntimeSettings runtimeSettings = modifier.m_settings as RuntimeSettings; if (runtimeSettings == null && (Object.op_Implicit((Object)(object)componentInChildren) || InitManager.IsCustomTool(((Component)modifier).gameObject))) { runtimeSettings = EnsureRuntimeSettings(modifier, componentInChildren is RemoveModificationsOverlayVisualizer, (Object)(object)componentInChildren != (Object)null); } if (runtimeSettings == null) { return true; } if (!HasAreaAccess(modifier, ((Component)modifier).transform.position, flash: false)) { Log.LogWarning("Blocked a terrain operation whose brush intersects a protected area"); return false; } if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.IsValid() && !__instance.m_nview.IsOwner()) { __instance.m_nview.ClaimOwnership(); } if (runtimeSettings.HasOverlay) { if (((Settings)runtimeSettings).m_smooth) { ((Settings)runtimeSettings).m_smoothRadius = float.NegativeInfinity; } if (((Settings)runtimeSettings).m_raise && ((Settings)runtimeSettings).m_raiseDelta >= 0f) { ((Settings)runtimeSettings).m_raiseRadius = float.NegativeInfinity; ((Settings)runtimeSettings).m_raiseDelta = GroundLevelSpinner.Value; } if (((Settings)runtimeSettings).m_paintCleared) { ((Settings)runtimeSettings).m_paintRadius = float.NegativeInfinity; } } return true; } internal static bool HasAreaAccess(TerrainOp modifier, Vector3 position, bool flash) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)modifier)) { return true; } float num = modifier.GetRadius(); if (!IsFinite(num) || num < 0f) { return false; } RuntimeSettings runtimeSettings = modifier.m_settings as RuntimeSettings; if (modifier.m_settings.m_square || (runtimeSettings != null && runtimeSettings.HasOverlay) || (runtimeSettings != null && runtimeSettings.IsReset)) { num *= 1.414214f; } return PrivateArea.CheckAccess(position, num, flash, true); } [HarmonyPostfix] [HarmonyPatch(typeof(TerrainOp), "GetRadius")] private static void GetRadiusPostfix(TerrainOp __instance, ref float __result) { if (Object.op_Implicit((Object)(object)__instance)) { OverlayVisualizer component = ((Component)__instance).gameObject.GetComponent<OverlayVisualizer>(); if (component is RemoveModificationsOverlayVisualizer) { __result = Mathf.Max(__result, __instance.m_settings.m_levelRadius + 1f); } else if (component is RaiseGroundOverlayVisualizer) { __result = Mathf.Max(__result, 2f); } else if (Object.op_Implicit((Object)(object)component) && __instance.m_settings.m_paintCleared) { __result = Mathf.Max(__result, 1f); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Settings), "GetRadius")] private static void GetSettingsRadiusPostfix(Settings __instance, ref float __result) { if (__instance.m_raise && IsPrecisionModifier(__instance.m_raiseRadius)) { __result = Mathf.Max(__result, 2f); } if ((__instance.m_smooth && IsPrecisionModifier(__instance.m_smoothRadius)) || (__instance.m_paintCleared && IsPrecisionModifier(__instance.m_paintRadius))) { __result = Mathf.Max(__result, 1f); } } private static void RemoveLegacyTerrainModifiers(Vector3 position, float radius) { //IL_0006: 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_00a5: 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) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) List<TerrainModifier> list = new List<TerrainModifier>(); TerrainModifier.GetModifiers(position, radius + 1f, list, (TerrainModifier)null); foreach (TerrainModifier item in list) { float num = (Object.op_Implicit((Object)(object)item) ? item.GetRadius() : 0f); if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.m_nview) && item.m_nview.IsValid() && item.m_playerModifiction && !Object.op_Implicit((Object)(object)((Component)item).GetComponentInParent<Piece>()) && !Object.op_Implicit((Object)(object)((Component)item).GetComponentInParent<WearNTear>()) && !(Mathf.Abs(((Component)item).transform.position.x - position.x) + num > radius) && !(Mathf.Abs(((Component)item).transform.position.z - position.z) + num > radius) && (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || PrivateArea.CheckAccess(((Component)item).transform.position, num, false, true))) { item.m_nview.ClaimOwnership(); if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { ZNetScene.instance.Destroy(((Component)item).gameObject); } } } } [HarmonyPostfix] [HarmonyPatch(typeof(Settings), "Serialize")] private static void SerializeSettingsPostfix(Settings __instance, ZPackage pkg) { if (__instance is RuntimeSettings runtimeSettings && pkg != null) { pkg.Write(1096043859); pkg.Write(1); pkg.Write(((Settings)runtimeSettings).m_levelRadius); pkg.Write(((Settings)runtimeSettings).m_raiseRadius); pkg.Write(((Settings)runtimeSettings).m_raisePower); pkg.Write(((Settings)runtimeSettings).m_raiseDelta); pkg.Write(((Settings)runtimeSettings).m_smoothRadius); pkg.Write(((Settings)runtimeSettings).m_smoothPower); pkg.Write(((Settings)runtimeSettings).m_paintRadius); } } [HarmonyPostfix] [HarmonyPatch(typeof(Settings), "Deserialize")] private static void DeserializeSettingsPostfix(ZPackage pkg, ref Settings __result) { if (__result == null || pkg == null || pkg.Size() - pkg.GetPos() < 4) { return; } int pos = pkg.GetPos(); if (pkg.ReadInt() != 1096043859) { pkg.SetPos(pos); return; } if (pkg.Size() - pos < 36 || pkg.ReadInt() != 1) { Log.LogWarning("Rejected incomplete or unsupported terrain-operation settings"); __result = null; return; } RuntimeSettings obj = __result as RuntimeSettings; bool isReset = obj?.IsReset ?? false; bool hasOverlay = obj?.HasOverlay ?? false; RuntimeSettings runtimeSettings = CopySettings(__result, isReset, hasOverlay); ((Settings)runtimeSettings).m_levelRadius = pkg.ReadSingle(); ((Settings)runtimeSettings).m_raiseRadius = pkg.ReadSingle(); ((Settings)runtimeSettings).m_raisePower = pkg.ReadSingle(); ((Settings)runtimeSettings).m_raiseDelta = pkg.ReadSingle(); ((Settings)runtimeSettings).m_smoothRadius = pkg.ReadSingle(); ((Settings)runtimeSettings).m_smoothPower = pkg.ReadSingle(); ((Settings)runtimeSettings).m_paintRadius = pkg.ReadSingle(); if (!IsValid(runtimeSettings)) { Log.LogWarning("Rejected invalid network terrain-operation settings"); __result = null; } else { __result = (Settings)(object)runtimeSettings; } } private static RuntimeSettings CopySettings(Settings source, bool isReset, bool hasOverlay) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) return new RuntimeSettings { IsReset = isReset, HasOverlay = hasOverlay, m_levelOffset = source.m_levelOffset, m_level = source.m_level, m_levelRadius = source.m_levelRadius, m_square = source.m_square, m_raise = source.m_raise, m_raiseRadius = source.m_raiseRadius, m_raisePower = source.m_raisePower, m_raiseDelta = source.m_raiseDelta, m_smooth = source.m_smooth, m_smoothRadius = source.m_smoothRadius, m_smoothPower = source.m_smoothPower, m_paintCleared = source.m_paintCleared, m_paintHeightCheck = source.m_paintHeightCheck, m_paintType = source.m_paintType, m_paintRadius = source.m_paintRadius, m_paintStrength = source.m_paintStrength, m_paintExp = source.m_paintExp, m_paintCurve = source.m_paintCurve, m_rotation = source.m_rotation, m_sides = source.m_sides, m_addMedianMax = source.m_addMedianMax, m_centerMultiplicationFactor = source.m_centerMultiplicationFactor, m_pointMultiplicationFactor = source.m_pointMultiplicationFactor, m_halfOffset = source.m_halfOffset }; } private static bool IsValid(RuntimeSettings settings) { if (!IsRadius(((Settings)settings).m_levelRadius, settings.IsReset ? 1f : 0.5f)) { return false; } if (((Settings)settings).m_raise && !IsPrecisionRadius(((Settings)settings).m_raiseRadius, settings.HasOverlay)) { return false; } if (((Settings)settings).m_smooth && !IsPrecisionRadius(((Settings)settings).m_smoothRadius, settings.HasOverlay)) { return false; } if (((Settings)settings).m_paintCleared && !IsPrecisionRadius(((Settings)settings).m_paintRadius, settings.HasOverlay)) { return false; } if (((Settings)settings).m_raise && (!IsFinite(((Settings)settings).m_raisePower) || ((Settings)settings).m_raisePower < 0.05f || ((Settings)settings).m_raisePower > 1f)) { return false; } if (((Settings)settings).m_raise && (!IsFinite(((Settings)settings).m_raiseDelta) || ((Settings)settings).m_raiseDelta < -1f || ((Settings)settings).m_raiseDelta > 1f)) { return false; } if (((Settings)settings).m_smooth && (!IsFinite(((Settings)settings).m_smoothPower) || ((Settings)settings).m_smoothPower < 1f || ((Settings)settings).m_smoothPower > 30f)) { return false; } return true; } private static bool IsPrecisionRadius(float value, bool allowPrecision) { if (!allowPrecision || !IsPrecisionModifier(value)) { return IsRadius(value, 0.5f); } return true; } private static bool IsRadius(float value, float minimum) { if (IsFinite(value) && value >= minimum) { return value <= TerrainTools.MaxRadius; } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(TerrainComp), "InternalDoOperation")] private static bool InternalDoOperationPrefix(TerrainComp __instance, Vector3 pos, Settings modifier) { //IL_002e: 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_003f: Unknown result type (might be due to invalid IL or missing references) if (modifier is RuntimeSettings { IsReset: not false }) { int num = Mathf.Clamp(Mathf.RoundToInt(modifier.m_levelRadius), 1, Mathf.CeilToInt(TerrainTools.MaxRadius)); RemoveLegacyTerrainModifiers(pos, num); RemoveTerrainModifications(__instance, pos, num); PreciseRecolorTerrain(__instance, pos, (PaintType)3, heightCheck: false, num); } return true; } [HarmonyPostfix] [HarmonyPatch(typeof(TerrainComp), "InternalDoOperation")] private static void InternalDoOperationPostfix(TerrainComp __instance) { if (IsPrecisionModifier(__instance.m_lastOpRadius)) { __instance.m_lastOpRadius = 1f; } } [HarmonyPrefix] [HarmonyPatch(typeof(TerrainComp), "SmoothTerrain")] private static bool PreciseSmoothTerrian(TerrainComp __instance, Vector3 worldPos, float radius) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (!IsPrecisionModifier(radius)) { return true; } Log.LogInfo("PreciseSmoothTerrain", LogLevel.Medium); int num = __instance.m_width + 1; int num2 = default(int); int num3 = default(int); __instance.m_hmap.WorldToVertex(worldPos, ref num2, ref num3); float num4 = worldPos.y - ((Component)__instance).transform.position.y; Log.LogInfo($"worldPos: {worldPos}, xPos: {num2}, yPos: {num3}, referenceH: {num4}", LogLevel.Medium); FindExtrema(num2, num, out var xMin, out var xMax); FindExtrema(num3, num, out var xMin2, out var xMax2); for (int i = xMin; i <= xMax; i++) { for (int j = xMin2; j <= xMax2; j++) { int num5 = j * num + i; float height = __instance.m_hmap.GetHeight(i, j); float num6 = num4 - height; float num7 = __instance.m_smoothDelta[num5]; __instance.m_smoothDelta[num5] = Mathf.Clamp(num7 + num6, -1f, 1f); __instance.m_modifiedHeight[num5] = true; Log.LogInfo($"tilePos: ({i}, {j}), tileH: {height}, deltaH: {num6}, prevSmoothDelta: {num7}, newSmoothDelta {__instance.m_smoothDelta[num5]}", LogLevel.Medium); } } Log.LogInfo("[SUCCESS] Smooth Terrain Modification", LogLevel.Medium); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(TerrainComp), "RaiseTerrain")] private static bool RaiseTerrainPrefix(TerrainComp __instance, Vector3 worldPos, float radius, float delta, float power) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (!IsPrecisionModifier(radius)) { return true; } Log.LogInfo("[INIT] Raise Terrain Modification", LogLevel.Medium); int num = __instance.m_width + 1; int num2 = default(int); int num3 = default(int); __instance.m_hmap.WorldToVertex(worldPos, ref num2, ref num3); float num4 = worldPos.y - ((Component)__instance).transform.position.y; Log.LogInfo($"worldPos: {worldPos}, xPos: {num2}, yPos: {num3}, delta: {delta}, refHeight: {num4}", LogLevel.Medium); FindExtrema(num2, num, 1, out var xMin, out var xMax); FindExtrema(num3, num, 1, out var xMin2, out var xMax2); for (int i = xMin; i <= xMax; i++) { for (int j = xMin2; j <= xMax2; j++) { float height = __instance.m_hmap.GetHeight(i, j); float weight = PreciseRaiseMath.Weight(i - num2, j - num3, power); if (PreciseRaiseMath.TryGetTargetHeight(height, num4, delta, weight, out var targetHeight)) { int num5 = j * num + i; float num6 = targetHeight - height + __instance.m_smoothDelta[num5]; __instance.m_smoothDelta[num5] = 0f; __instance.m_levelDelta[num5] += num6; __instance.m_levelDelta[num5] = Mathf.Clamp(__instance.m_levelDelta[num5], -8f, 8f); __instance.m_modifiedHeight[num5] = true; } } } Log.LogInfo("[SUCCESS] Raise Terrain Modification", LogLevel.Medium); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(TerrainComp), "PaintCleared")] private static bool PaintClearedPrefix(TerrainComp __instance, Vector3 worldPos, Settings settings) { //IL_0010: 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) if (!IsPrecisionModifier(settings.m_paintRadius)) { return true; } PreciseRecolorTerrain(__instance, worldPos, settings.m_paintType, settings.m_paintHeightCheck); return false; } public static void RemoveTerrainModifications(TerrainComp comp, Vector3 worldPos, int radius = 1) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) Log.LogInfo("[INIT] Remove Terrain Modifications", LogLevel.Medium); int num = comp.m_width + 1; int num2 = default(int); int num3 = default(int); comp.m_hmap.WorldToVertex(worldPos, ref num2, ref num3); Log.LogInfo($"worldPos: {worldPos}, vertexPos: ({num2}, {num3})", LogLevel.Medium); FindExtrema(num2, num, radius, out var xMin, out var xMax); FindExtrema(num3, num, radius, out var xMin2, out var xMax2); Log.LogInfo($"Reset chunk {((Component)comp).transform.position}: radius={radius}, vertices=({xMin}..{xMax}, {xMin2}..{xMax2}), " + $"edge={xMin == 0 || xMin2 == 0 || xMax == num - 1 || xMax2 == num - 1}"); for (int i = xMin; i <= xMax; i++) { for (int j = xMin2; j <= xMax2; j++) { int num4 = j * num + i; comp.m_levelDelta[num4] = 0f; comp.m_smoothDelta[num4] = 0f; comp.m_modifiedHeight[num4] = false; Log.LogInfo($"tilePos: ({i}, {j}), tileIndex: {num4}", LogLevel.Medium); } } Log.LogInfo("[SUCCESS] Remove Terrain Modifications", LogLevel.Medium); } public static void PreciseRecolorTerrain(TerrainComp comp, Vector3 worldPos, PaintType paintType, bool heightCheck = false, int radius = 1) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) Log.LogInfo("[INIT] PreciseRecolorTerrain", LogLevel.Medium); Color val = ResolveColor(paintType); GetPaintMaskBounds(comp.m_hmap, worldPos, radius, out var xStart, out var xMax, out var yStart, out var yMax); int num = comp.m_width + 1; for (int i = xStart; i <= xMax; i++) { for (int j = yStart; j <= yMax; j++) { val.a = comp.m_hmap.GetPaintMask(i, j).a; int num2 = j * num + i; comp.m_paintMask[num2] = val; comp.m_modifiedPaint[num2] = true; Log.LogInfo($"tilePos: ({i}, {j}), tileIndex: {num2}, tileColor: {val}", LogLevel.Medium); } } Log.LogInfo("[SUCCESS] Color Terrain Modification", LogLevel.Medium); } public static void GetPaintMaskBounds(Heightmap heightmap, Vector3 worldPos, int radius, out int xStart, out int xMax, out int yStart, out int yMax) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) int centerIndex = default(int); int centerIndex2 = default(int); heightmap.WorldToVertex(worldPos, ref centerIndex, ref centerIndex2); PaintGridMath.GetAxisIndices(heightmap.m_width, centerIndex, radius, out xStart, out xMax); PaintGridMath.GetAxisIndices(heightmap.m_width, centerIndex2, radius, out yStart, out yMax); } public static bool TryGetPaintMaskWorldBounds(Heightmap heightmap, Vector3 worldPos, int radius, out Vector2 min, out Vector2 max) { //IL_0001: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid