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 BuildExtend v0.9.3
plugins/BuildExtend.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; using Valheim.SettingsGui; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BuildExtend { public static class Api { public const int Version = 1; public static string ModeLabel => Plugin.ModeTab(Plugin.Hammer.Value); public static string ModeTooltip => HelpButton.ModeTip(); public static string HelpTooltip => HelpButton.HelpTip; public static void ShowHelp() { HelpButton.Show(); } public static void NextMode() { Plugin.NextMode(1); } } internal static class Planet { private static bool looked; private static PropertyInfo active; private static Func<Vector3, Vector3> up; private static MethodInfo ground; private static MethodInfo raise; private static MethodInfo level; internal static bool CanRaise { get { Look(); return raise != null; } } internal static bool CanLevel { get { Look(); return level != null; } } internal static bool On { get { Look(); try { return active != null && up != null && (bool)active.GetValue(null); } catch { return false; } } } private static void Look() { if (looked) { return; } looked = true; try { Type type = (from a in AppDomain.CurrentDomain.GetAssemblies() select a.GetType("PlanetPrototype.PlanetApi", throwOnError: false)).FirstOrDefault((Type t) => t != null); if (type == null) { return; } PropertyInfo property = type.GetProperty("ApiVersion", BindingFlags.Static | BindingFlags.Public); if (property == null || (int)property.GetValue(null) < 2) { Plugin.Warn("PlanetApi is older than v2: building uses world up"); return; } active = type.GetProperty("Active", BindingFlags.Static | BindingFlags.Public); MethodInfo method = type.GetMethod("Up", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Vector3) }, null); if (method != null) { up = (Func<Vector3, Vector3>)Delegate.CreateDelegate(typeof(Func<Vector3, Vector3>), method); } ground = type.GetMethod("GroundPoint", BindingFlags.Static | BindingFlags.Public); Type[] types = new Type[6] { typeof(Vector3), typeof(Vector3), typeof(float), typeof(float), typeof(float), typeof(bool) }; raise = type.GetMethod("RaiseArea", BindingFlags.Static | BindingFlags.Public, null, types, null); level = type.GetMethod("LevelArea", BindingFlags.Static | BindingFlags.Public, null, types, null); Plugin.Log("PlanetApi found: local up from the planet; the hoe's area raise " + ((raise != null) ? "through RaiseArea" : "not there (no RaiseArea)") + ", area levelling " + ((level != null) ? "through LevelArea" : "not there (no LevelArea)")); } catch (Exception ex) { Plugin.Warn("PlanetApi: " + ex.Message); active = null; up = null; ground = null; raise = (level = null); } } internal static float RaiseArea(Ground.Area a, bool apply) { return Area(raise, "RaiseArea", a, apply); } internal static float LevelArea(Ground.Area a, bool apply) { return Area(level, "LevelArea", a, apply); } private static float Area(MethodInfo method, string name, Ground.Area a, bool apply) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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) if (method == null) { return 0f; } try { Vector3 val = a.Anchor + a.Fwd * ((a.A0 + a.A1) * 0.5f); return (float)method.Invoke(null, new object[6] { val, a.Fwd, (a.A1 - a.A0) * 0.5f, a.Half, a.Top, apply }); } catch (Exception ex) { Plugin.Warn("PlanetApi." + name + ": " + (ex.InnerException ?? ex).Message); return 0f; } } internal static Vector3 Up(Vector3 point) { //IL_0030: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_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_0036: Unknown result type (might be due to invalid IL or missing references) if (On) { try { Vector3 val = up(point); if (((Vector3)(ref val)).sqrMagnitude > 0.5f) { return ((Vector3)(ref val)).normalized; } } catch { } } return Vector3.up; } internal static bool Depth(Vector3 point, out float depth) { //IL_007a: 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) //IL_0023: 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) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) depth = 0f; if (On && ground != null) { try { object[] array = new object[3] { point, null, null }; if (!(bool)ground.Invoke(null, array)) { return false; } depth = Vector3.Dot((Vector3)array[1] - point, Up(point)); return true; } catch { return false; } } if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } float groundHeight = ZoneSystem.instance.GetGroundHeight(point); depth = groundHeight - point.y; return true; } } internal static class Chests { internal enum Gate { Ready, Wait, Refused } private static bool looked; private static MethodInfo reserve; private static MethodInfo requirements; private static MethodInfo gate; private static PropertyInfo pending; internal static bool Present { get { Look(); if (!(reserve != null)) { return gate != null; } return true; } } private static void Look() { if (looked) { return; } looked = true; try { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ValheimUnified"); if (assembly == null) { return; } reserve = assembly.GetType("ValheimUnified.BuildResources", throwOnError: false)?.GetMethod("Reserve", BindingFlags.Static | BindingFlags.Public, null, new Type[4] { typeof(Player), typeof(Requirement[]), typeof(int), typeof(Action) }, null); Type type = assembly.GetType("ValheimUnified.Resources", throwOnError: false); BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; pending = type?.GetProperty("Pending", bindingAttr); if (reserve != null) { Plugin.Log("ValheimUnified: chests through BuildResources.Reserve"); return; } requirements = type?.GetMethod("Requirements", bindingAttr, null, new Type[5] { typeof(Player), typeof(Requirement[]), typeof(int), typeof(int), typeof(bool) }, null); gate = type?.GetMethods(bindingAttr).FirstOrDefault((MethodInfo m) => m.Name == "Gate" && m.GetParameters().Length == 3); if (requirements != null && gate != null) { Plugin.Log("ValheimUnified: chests through its resource gate"); return; } requirements = (gate = null); Plugin.Warn("ValheimUnified found, but not its chest gate: building spends what the inventory has"); } catch (Exception ex) { Plugin.Warn("ValheimUnified: " + ex.Message); reserve = (requirements = (gate = null)); } } internal static Gate Reserve(Player player, Piece piece, int count) { Look(); try { if (reserve != null) { if ((bool)reserve.Invoke(null, new object[4] { player, piece.m_resources, count, null })) { return Gate.Ready; } } else { if (gate == null) { return Gate.Ready; } object obj = requirements.Invoke(null, new object[5] { player, piece.m_resources, 0, count, false }); if (obj is ICollection { Count: 0 }) { return Gate.Ready; } if ((bool)gate.Invoke(null, new object[3] { player, obj, null })) { return Gate.Ready; } } if (pending == null) { return Gate.Wait; } return ((bool)pending.GetValue(null)) ? Gate.Wait : Gate.Refused; } catch (Exception ex) { Plugin.Warn("ValheimUnified chests: " + (ex.InnerException ?? ex).Message); return Gate.Refused; } } } internal enum Verdict : byte { Unknown, Ok, Invalid, Exists, Swap } internal static class Checks { private static readonly Dictionary<Piece, string> refusals = new Dictionary<Piece, string>(); private static readonly List<Transform> snaps = new List<Transform>(); internal static string Refuse(Piece p) { if ((Object)(object)p == (Object)null) { return ""; } if (refusals.TryGetValue(p, out var value)) { return value; } string text = null; if (p.m_repairPiece || p.m_removePiece || p.m_groundPiece || p.m_groundOnly || p.m_cultivatedGroundOnly || p.m_vegetationGroundOnly || p.m_waterPiece || p.m_onlyInTeleportArea || p.m_requireDeepSnow || (Object)(object)p.m_mustConnectTo != (Object)null || Object.op_Implicit((Object)(object)((Component)p).GetComponent<TerrainModifier>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<TerrainOp>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<Plant>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<PrivateArea>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<StationExtension>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<Ship>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<Vagon>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<ItemDrop>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<Feast>())) { text = Plugin.T("Эту деталь нельзя протянуть", "This piece cannot be stretched"); } if (refusals.Count > 512) { refusals.Clear(); } refusals[p] = text; return text; } internal static Bounds LocalBounds(Transform root) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: 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_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) bool any = false; Bounds box = default(Bounds); Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (val.isTrigger) { continue; } Collider val2 = val; BoxCollider val3 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null); if (val3 == null) { MeshCollider val4 = (MeshCollider)(object)((val2 is MeshCollider) ? val2 : null); if (val4 == null) { SphereCollider val5 = (SphereCollider)(object)((val2 is SphereCollider) ? val2 : null); if (val5 == null) { CapsuleCollider val6 = (CapsuleCollider)(object)((val2 is CapsuleCollider) ? val2 : null); if (val6 != null) { Vector3 val7 = Vector3.one * val6.radius * 2f; ((Vector3)(ref val7))[val6.direction] = Mathf.Max(val6.height, val6.radius * 2f); Add(((Component)val6).transform, new Bounds(val6.center, val7)); } } else { Add(((Component)val5).transform, new Bounds(val5.center, Vector3.one * val5.radius * 2f)); } } else if ((Object)(object)val4.sharedMesh != (Object)null) { Add(((Component)val4).transform, val4.sharedMesh.bounds); } } else { Add(((Component)val3).transform, new Bounds(val3.center, val3.size)); } } if (!any) { MeshFilter[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<MeshFilter>(true); foreach (MeshFilter val8 in componentsInChildren2) { if ((Object)(object)val8.sharedMesh != (Object)null) { Add(((Component)val8).transform, val8.sharedMesh.bounds); } } } return box; void Add(Transform t, Bounds b) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) for (int j = 0; j < 8; j++) { Vector3 val9 = ((Bounds)(ref b)).center + Vector3.Scale(((Bounds)(ref b)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1)))); Vector3 val10 = root.InverseTransformPoint(t.TransformPoint(val9)); if (!any) { box = new Bounds(val10, Vector3.zero); any = true; } else { ((Bounds)(ref box)).Encapsulate(val10); } } } } internal static Shape ShapeOf(Piece instance, Bounds bounds) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) snaps.Clear(); instance.GetSnapPoints(snaps); Transform transform = ((Component)instance).transform; List<Vec> list = new List<Vec>(snaps.Count); foreach (Transform snap in snaps) { list.Add(V(transform.InverseTransformPoint(snap.position))); } return Lattice.FromPiece(list, V(((Bounds)(ref bounds)).min), V(((Bounds)(ref bounds)).max), Plugin.Beams.Value == BeamSpacing.Touching); } internal static Vec V(Vector3 v) { //IL_0000: 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_000c: Unknown result type (might be due to invalid IL or missing references) return new Vec(v.x, v.y, v.z); } internal static Vector3 V(Vec v) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(v.X, v.Y, v.Z); } internal static Verdict Cell(Piece prefab, Vector3 pos, Vector3 stationAt, bool noStation) { //IL_0000: 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) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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) if (Location.IsInsideNoBuildLocation(pos)) { return Verdict.Invalid; } if (!PrivateArea.CheckAccess(pos, 0f, false, false)) { return Verdict.Invalid; } if ((Object)(object)prefab.m_craftingStation != (Object)null && !noStation && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27) && (Object)(object)CraftingStation.HaveBuildStationInRange(prefab.m_craftingStation.m_name, stationAt) == (Object)null) { return Verdict.Invalid; } if ((int)prefab.m_onlyInBiome != 0 && (Heightmap.FindBiome(pos) & prefab.m_onlyInBiome) == 0) { return Verdict.Invalid; } return Verdict.Ok; } } [HarmonyPatch(typeof(BuildUi), "Awake")] internal static class HelpButton { private sealed class Live : MonoBehaviour { internal Action Refresh; private void Update() { Refresh?.Invoke(); } } private const float Width = 48f; private const float Gap = 6f; internal static string HelpTip => Plugin.T("Массовая стройка: как пользоваться", "Mass building: how to use"); internal static string Topic => Plugin.T("Массовая стройка", "Mass building"); private static void Postfix(BuildUi __instance) { try { Add(__instance); } catch (Exception ex) { Plugin.Warn("help button not added: " + ex.Message); } } private static void Add(BuildUi ui) { RectTransform tabContainer = ui.m_tabContainer; if ((Object)(object)tabContainer == (Object)null || ((Transform)tabContainer).childCount == 0) { return; } GameObject gameObject = ((Component)((Transform)tabContainer).GetChild(((Transform)tabContainer).childCount - 1)).gameObject; HorizontalOrVerticalLayoutGroup component = ((Component)tabContainer).GetComponent<HorizontalOrVerticalLayoutGroup>(); float padding = (((Object)(object)component != (Object)null) ? ((LayoutGroup)component).padding.right : 0); if ((Object)(object)component != (Object)null) { RectOffset padding2 = ((LayoutGroup)component).padding; padding2.right += 108; } Tab(tabContainer, gameObject, "BuildExtend help", "?", HelpTip, padding, 0, Show); GameObject val = Tab(tabContainer, gameObject, "BuildExtend switch", "xN", "", padding, 1, delegate { Plugin.NextMode(1); }); if ((Object)(object)val != (Object)null) { TMP_Text text = val.GetComponentInChildren<TMP_Text>(true); UITooltip tip = val.GetComponent<UITooltip>(); val.AddComponent<Live>().Refresh = delegate { HammerMode value = Plugin.Hammer.Value; if ((Object)(object)text != (Object)null) { text.text = Plugin.ModeTab(value); } if ((Object)(object)tip != (Object)null) { tip.m_text = ModeTip(); } }; } LayoutRebuilder.MarkLayoutForRebuild(tabContainer); Plugin.Debug($"help button: tab row {((Object)tabContainer).name}, {((Transform)tabContainer).childCount} tabs"); } internal static string ModeTip() { HammerMode value = Plugin.Hammer.Value; return Plugin.T("Режим молота: ", "Hammer mode: ") + Plugin.ModeName(value) + Plugin.T(". Нажмите — следующий: ", ". Click for the next: ") + Plugin.ModeName((HammerMode)((int)(value + 1) % 3)) + Plugin.T(". В игре — ", ". In game: ") + Stretch.ModeKey() + Plugin.T("колесо.", "wheel."); } private static GameObject Tab(RectTransform tabs, GameObject source, string name, string label, string tooltip, float padding, int slot, Action click) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(source, (Transform)(object)tabs); ((Object)val).name = name; val.transform.SetAsLastSibling(); (val.GetComponent<LayoutElement>() ?? val.AddComponent<LayoutElement>()).ignoreLayout = true; RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = new Vector2(1f, 0f); val2.anchorMax = new Vector2(1f, 1f); val2.pivot = new Vector2(1f, 0.5f); val2.sizeDelta = new Vector2(48f, 0f); val2.anchoredPosition = new Vector2(0f - padding - (float)slot * 54f, 0f); TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text obj in componentsInChildren) { obj.text = label; obj.fontStyle = (FontStyles)(obj.fontStyle | 1); } Transform val3 = val.transform.Find("Selected"); if ((Object)(object)val3 != (Object)null) { ((Component)val3).gameObject.SetActive(false); } UITooltip component = val.GetComponent<UITooltip>(); if ((Object)(object)component != (Object)null) { component.m_text = tooltip; } Button component2 = val.GetComponent<Button>(); if ((Object)(object)component2 == (Object)null) { Object.Destroy((Object)(object)val); return null; } component2.onClick = new ButtonClickedEvent(); ((UnityEvent)component2.onClick).AddListener((UnityAction)delegate { try { click(); } catch (Exception ex) { Plugin.Warn("build menu tab: " + ex.Message); } }); return val; } internal static void Show() { try { if ((Object)(object)Hud.instance != (Object)null) { Hud.instance.m_buildUi.Close(); } InventoryGui instance = InventoryGui.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null)) { instance.Show((Container)null, 1); instance.OnOpenTexts(); TextsDialog textsDialog = instance.m_textsDialog; TextInfo val = textsDialog.m_texts.Find((TextInfo t) => t.m_topic == Topic); if (val != null) { textsDialog.ShowText(val); } } } catch (Exception ex) { Plugin.Warn("help: " + ex.Message); } } internal static void AddEntry(TextsDialog __instance) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown try { if (Plugin.Enabled.Value) { __instance.m_texts.Insert(Math.Min(1, __instance.m_texts.Count), new TextInfo(Topic, Text())); } } catch (Exception ex) { Plugin.Warn("compendium entry: " + ex.Message); } } private static string Key(string k) { return Plugin.Hint(k); } private static string Head(string h) { return "<color=#FFB75B><b>" + h + "</b></color>"; } private static string Text() { //IL_0005: 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_001b: Invalid comparison between Unknown and I4 //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) string k = (((int)Plugin.UndoModifier.Value == 0) ? "" : (((int)Plugin.UndoModifier.Value == 306 || (int)Plugin.UndoModifier.Value == 305) ? "Ctrl+" : (((object)Plugin.UndoModifier.Value/*cast due to .constrained prefix*/).ToString() + "+"))) + ((object)Plugin.UndoKey.Value/*cast due to .constrained prefix*/).ToString(); if (!Plugin.Russian) { return Head("Stretch building") + "\n" + Key("hold LMB") + " on the ghost and look around — the piece follows the aim as a grid. Let go to build. A short click places one piece as usual.\nTranslucent silhouettes and yellow arrows at the ghost show where it can go: walls aside and up, floors aside and forward, roofs and stairs along the ridge and down the slope, diagonal beams along themselves.\n\n" + Head("Hammer modes") + "\n" + Key("Shift+wheel") + " (while nothing is stretched) or the " + Key("x1 / xN / xF") + " tab in the build menu:\n- " + Key("x1") + " normal building — exactly as in the game, one piece at a time, for precise building;\n- " + Key("xN") + " stretching — silhouettes and arrows, hold LMB and drag;\n- " + Key("xF") + " shapes — the remembered shape follows the ghost, a click builds it whole; " + Key("E") + " — another shape; hold LMB and look — resize (remembered).\n\n" + Head("While held") + "\n" + Key("E") + " — shape: plane, box (walls round a rectangle, for roofs a gable roof), cylinder (a round tower, for floors a round floor), arch of beams, dome.\n" + Key("wheel") + " or " + Key("Shift+wheel") + " — floors (rows) of a box or tower. " + Key("Ctrl+wheel") + " — gaps: every 2nd, every 3rd, checkerboard.\n" + Key("RMB") + " or " + Key("Esc") + " — cancel.\nThe whole stretch is one sheet from the first piece: its height and tilt, pieces edge to edge holding each other up. Everything is placed except in others' wards, no-build places and out of the workbench's reach from where the stretch started.\n\n" + Head("Iron hoe: level to height") + "\nThe iron hoe is made at the forge from a level 3 hoe and iron. Besides the usual \"Level ground\" and \"Raise ground\" it has \"Level to height\": " + Key("hold LMB") + " and look ahead — a level rectangle along the look, " + Key("wheel") + " — width, " + Key("Ctrl+wheel") + " — height over the press point (0 by default). A click — a strip as wide as the frame.\nEverything in the rectangle goes to that height: cut above, filled below, square, no rounding. Cutting is free, filling costs stone by the volume, as the game's raise does; short of it, as much is done from the press point as is paid for.\n\n" + Head("Removing and undo") + "\n" + Key("hold MMB") + " on a placed piece and look — a removal zone from that point to the aim: " + Key("wall") + " (the wall's plane), " + Key("floor") + " (the floor's plane) or " + Key("box") + "; " + Key("E") + " — next zone. Pieces in the zone glow red, release to remove; resources to the backpack. A short click removes one piece, as in the game. Stations, beds, portals and wards are left alone. Own pieces only by default.\n" + Key(k) + " — undo the last stretch: its pieces come down, what it cost comes back.\n\n" + Head("Colours") + "\n<color=#99CCFF>pale blue</color> — full strength; <color=#66FF66>green</color> → <color=#FF8000>orange</color> — weaker, orange falls;\n<color=#FF4040>red</color> — not possible or not enough materials; <color=#B366FF>violet</color> — replaces a standing piece (doors and windows along a wall).\n\n" + Head("Resources") + "\nThe build panel shows what all the segments need, how many are paid for and what is short. Nearby chests count if a chest mod adds them. As many are built as can be paid for.\n\n" + Head("Settings") + "\nSettings → Graphics, section \"Stretch building — BuildExtend\": shape, gaps, strength, replacing, own-only removal, segment limit, speed, stamina, beams."; } return Head("Стройка протяжкой") + "\n" + Key("удерживать ЛКМ") + " на призраке и вести взгляд — деталь тянется сеткой за прицелом. Отпустить — построить. Короткий щелчок ставит одну деталь, как обычно.\nПрозрачные силуэты и жёлтые стрелки у призрака показывают, куда деталь можно тянуть: стены — вбок и вверх, полы — вбок и вперёд, крыши и лестницы — вдоль конька и по скату, диагональные балки — вдоль себя.\n\n" + Head("Режимы молота") + "\n" + Key("Shift+колесо") + " (пока ничего не тянется) или вкладка " + Key("x1 / xN / xF") + " в меню стройки:\n- " + Key("x1") + " обычная стройка — ровно как в игре, по одной детали, для точной стройки;\n- " + Key("xN") + " протяжка — силуэты и стрелки, зажать ЛКМ и тянуть;\n- " + Key("xF") + " фигуры — фигура запомненного размера идёт за призраком, щелчок ЛКМ строит её целиком; " + Key("E") + " — другая фигура; зажать ЛКМ и повести — изменить размер (он запоминается).\n\n" + Head("Пока кнопка зажата") + "\n" + Key("E") + " — форма: плоскость, коробка (стены по краю прямоугольника, для крыш — двускатная крыша), цилиндр (круглая башня, для полов — круглый пол), арка из балок, купол.\n" + Key("колесо") + " или " + Key("Shift+колесо") + " — этажи (ряды) коробки и башни. " + Key("Ctrl+колесо") + " — пропуски: через одну, через две, шахматкой.\n" + Key("ПКМ") + " или " + Key("Esc") + " — отмена.\nВся протяжка — одно полотно от первой детали: её высота и наклон, детали стык в стык держат друг друга. Ставится всё, кроме чужих владений, мест без стройки и мест вне досягаемости верстака от начала протяжки.\n\n" + Head("Железная мотыга: выравнивание по высоте") + "\nЖелезная мотыга делается в кузнице из обычной мотыги 3 уровня и железа. Кроме обычных «Выровнять землю» и «Поднять землю» у неё есть «Выровнять по высоте»: " + Key("удерживать ЛКМ") + " и вести взгляд вперёд — ровный прямоугольник по взгляду, " + Key("колесо") + " — ширина, " + Key("Ctrl+колесо") + " — высота над точкой нажатия (по умолчанию 0). Щелчок — полоса шириной в рамку.\nВсё в прямоугольнике встаёт на эту высоту: выше срезается, ниже подсыпается, без скруглений. Срез бесплатно, подсыпка — камень по объёму, как за обычный подъём; не хватает — делается сколько оплачено от точки нажатия.\n\n" + Head("Снос и отмена") + "\n" + Key("удерживать СКМ") + " на поставленной детали и вести взгляд — зона сноса от этой точки до прицела: " + Key("стена") + " (плоскость стены), " + Key("пол") + " (плоскость пола) или " + Key("куб") + "; " + Key("E") + " — сменить зону. Детали в зоне подсвечены красным, отпустить — снести; ресурсы — в рюкзак. Короткий щелчок — одна деталь, как в игре. Верстаки, кровати, порталы и обереги зона не трогает. По умолчанию только свои детали.\n" + Key(k) + " — отменить последнюю протяжку: детали снимаются, потраченное возвращается.\n\n" + Head("Цвета") + "\n<color=#99CCFF>голубой</color> — полная прочность; <color=#66FF66>зелёный</color> → <color=#FF8000>оранжевый</color> — слабее, оранжевый рухнет;\n<color=#FF4040>красный</color> — строить нельзя или не хватает материалов; <color=#B366FF>фиолетовый</color> — заменит стоящую деталь (двери и окна по стене).\n\n" + Head("Ресурсы") + "\nВ панели стройки — сколько нужно на все сегменты, на сколько хватает и чего не хватает. Материалы из ближних сундуков учитываются, если их добавляет мод на сундуки. Строится столько, на сколько хватает.\n\n" + Head("Настройки") + "\nНастройки → Графика, раздел «Протяжная стройка — BuildExtend»: форма, пропуски, прочность, замена, снос только своих, предел сегментов, скорость, выносливость, балки."; } } [HarmonyPatch(typeof(TextsDialog), "UpdateTextsList")] internal static class HelpEntry { private static void Postfix(TextsDialog __instance) { HelpButton.AddEntry(__instance); } } internal static class Hoe { private enum Kind { Raise, Level } private const float MaxLength = 32f; private const float MaxWidth = 32f; private const float MaxHeight = 8f; private static bool busy; private static bool wheeled; private static Kind kind; private static Player player; private static Piece piece; private static TerrainOp op; private static Vector3 anchor; private static Vector3 up; private static Vector3 fwd; private static Vector3 side; private static float length; private static float paidLength; private static Ground.Fill fill; private static Ground.Fill paidFill; private static int ops; private static int paid; private static bool dirty; private static bool free; private static float nextMeasure; private static Piece probe; internal static bool Busy => busy; internal static Piece Piece => piece; internal static int Ops => Math.Max(1, ops); private static TerrainOp OpOf(Piece p, out Kind k) { k = Kind.Raise; TerrainOp val = (IronHoe.IsAreaPiece(p) ? ((Component)p).GetComponent<TerrainOp>() : null); if ((Object)(object)val == (Object)null) { return null; } Settings settings = val.m_settings; if ((settings.m_raise && settings.m_raiseDelta > 0f) || settings.m_level) { k = Kind.Level; return val; } return null; } internal static string Refuse(Player p, Piece selected) { if (!Plugin.Enabled.Value || !Plugin.HoeArea.Value || (Object)(object)OpOf(selected, out var k) == (Object)null) { return ""; } if (!IronHoe.Is(((Humanoid)p).GetRightItem())) { if (Plugin.IronHoeOn.Value) { if (k != Kind.Level) { return Plugin.T("насыпать областью умеет железная мотыга (кузница: мотыга 3 уровня и железо)", "the iron hoe raises an area (forge: a level 3 hoe and iron)"); } return Plugin.T("выравнивать областью умеет железная мотыга (кузница: мотыга 3 уровня и железо)", "the iron hoe levels an area (forge: a level 3 hoe and iron)"); } return ""; } if (Planet.On) { bool canRaise; if (k != Kind.Level) { canRaise = Planet.CanRaise; } else { if (!Planet.CanLevel) { goto IL_0094; } canRaise = Planet.CanRaise; } if (!canRaise) { goto IL_0094; } } return null; IL_0094: return Plugin.T("на планете это областью ждёт новой PlanetPrototype", "on the planet this needs a newer PlanetPrototype"); } internal static bool Start(Player p) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00cb: Unknown result type (might be due to invalid IL or missing references) Piece selectedPiece = p.GetSelectedPiece(); GameObject placementGhost = p.m_placementGhost; if (Refuse(p, selectedPiece) != null || (Object)(object)placementGhost == (Object)null || !placementGhost.activeInHierarchy || (int)p.m_placementStatus != 0) { return false; } player = p; piece = selectedPiece; op = OpOf(selectedPiece, out kind); anchor = placementGhost.transform.position; up = Planet.Up(anchor); fwd = Vector3.ProjectOnPlane(((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.forward : ((Component)p).transform.forward, up); if (((Vector3)(ref fwd)).sqrMagnitude < 0.0001f) { fwd = Vector3.ProjectOnPlane(((Component)p).transform.forward, up); } ((Vector3)(ref fwd)).Normalize(); Vector3 val = Vector3.Cross(up, fwd); side = ((Vector3)(ref val)).normalized; length = 0f; wheeled = false; busy = true; dirty = true; nextMeasure = 0f; Measure(); return true; } internal static bool Update(Player p, bool takeInput) { if ((Object)(object)p != (Object)(object)player || !((Character)p).InPlaceMode() || ((Character)p).IsDead() || (Object)(object)p.GetSelectedPiece() != (Object)(object)piece || Refuse(p, piece) != null) { Reset(); return true; } if (takeInput && Stretch.CancelPressed()) { Reset(); return false; } if (!Stretch.PlaceHeld) { return Release(p); } if (!takeInput) { return false; } float mouseScrollWheel = ZInput.GetMouseScrollWheel(); int num = ((mouseScrollWheel > 0f) ? 1 : ((mouseScrollWheel < 0f) ? (-1) : (ZInput.GetButtonDown("JoyDPadUp") ? 1 : (ZInput.GetButtonDown("JoyDPadDown") ? (-1) : 0)))); bool flag = ZInput.GetKey((KeyCode)306, false) || ZInput.GetKey((KeyCode)305, false) || ZInput.GetButton("JoyAltKeys"); if (num != 0) { wheeled = true; dirty = true; if (flag) { Plugin.HoeHeight.Value = Mathf.Clamp(Mathf.Round((Plugin.HoeHeight.Value + (float)num * 0.25f) * 4f) / 4f, -8f, 8f); } else if (!flag) { Plugin.HoeWidth.Value = Mathf.Clamp(Mathf.Round(Plugin.HoeWidth.Value) + (float)num, 1f, 32f); } } Follow(); Measure(); return false; } private static void Follow() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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) //IL_0052: 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) //IL_0058: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)GameCamera.instance == (Object)null) { return; } Transform transform = ((Component)GameCamera.instance).transform; Vector3 position = transform.position; Vector3 forward = transform.forward; float num = 64f; float num2 = Vector3.Dot(forward, up); float num3 = ((Mathf.Abs(num2) > 0.001f) ? (Vector3.Dot(anchor - position, up) / num2) : (-1f)); RaycastHit val = default(RaycastHit); Vector3 val2; if (Physics.Raycast(position, forward, ref val, num, player.m_placeRayMask, (QueryTriggerInteraction)1) && (num3 < 0f || ((RaycastHit)(ref val)).distance < num3)) { val2 = ((RaycastHit)(ref val)).point; } else { if (!(num3 > 0f)) { return; } val2 = position + forward * Mathf.Min(num3, num); } float num4 = Mathf.Clamp(Vector3.Dot(val2 - anchor, fwd), -32f, 32f); float num5 = ((Mathf.Abs(num4 - length) < 0.65f) ? length : Mathf.Round(num4)); if (num5 != length) { length = num5; dirty = true; } } private static Ground.Area Area(float len) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) return new Ground.Area { Anchor = anchor, Up = up, Fwd = fwd, A0 = Mathf.Min(0f, len) - 0.5f, A1 = Mathf.Max(0f, len) + 0.5f, Half = Plugin.HoeWidth.Value * 0.5f, Top = Plugin.HoeHeight.Value, Level = (kind == Kind.Level), Op = StringExtensionMethods.GetStableHashCode(IronHoe.Source(piece) ?? Utils.GetPrefabName(((Component)piece).gameObject)) }; } private static void Measure(bool now = false) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) if ((!now && !dirty && Time.unscaledTime < nextMeasure) || (!now && Time.unscaledTime < nextMeasure - 0.15f)) { return; } nextMeasure = Time.unscaledTime + 0.25f; dirty = false; Ground.Area a = Area(length); Hoe.fill = Measure(a); ops = Cost(a, Hoe.fill); free = ops == 0 || player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey()) || ZoneSystem.instance.GetGlobalKey((GlobalKeys)24); paid = (free ? ops : Lattice.Affordable(Enough, ops)); paidLength = length; paidFill = Hoe.fill; if (paid >= ops) { return; } int num = 0; int num2 = (int)Mathf.Abs(length); Ground.Fill f = default(Ground.Fill); while (num < num2) { int num3 = num + (num2 - num + 1) / 2; Ground.Area a2 = Area(Mathf.Sign(length) * (float)num3); Ground.Fill fill = Measure(a2); if (Cost(a2, fill) <= paid) { num = num3; f = fill; } else { num2 = num3 - 1; } } if (num == 0) { Ground.Area a3 = Area(0f); f = Measure(a3); if (Cost(a3, f) > paid) { f = default(Ground.Fill); } } paidLength = Mathf.Sign(length) * (float)num; paidFill = f; } private static Ground.Fill Measure(Ground.Area a) { if (!Planet.On) { return Ground.Measure(a); } float num = Planet.RaiseArea(a, apply: false); if (!a.Level) { return new Ground.Fill { Up = num }; } return new Ground.Fill { Up = num, Down = Mathf.Max(0f, Planet.LevelArea(a, apply: false) - num) }; } private static int Cost(Ground.Area a, Ground.Fill f) { Settings settings = op.m_settings; if (!settings.m_raise) { if (!piece.m_resources.Any((Requirement q) => (Object)(object)q.m_resItem != (Object)null && q.GetAmount(0) > 0) || f.Moved <= 0.005f) { return 0; } float num = Mathf.Max(0.5f, settings.m_levelRadius); float num2 = (settings.m_square ? (4f * num * num) : ((float)Math.PI * num * num)); return Mathf.CeilToInt((a.A1 - a.A0) * 2f * a.Half / num2 - 0.001f); } float num3 = Mathf.Max(0.5f, settings.m_raiseRadius); float num4 = (settings.m_square ? (4f * num3 * num3) : ((float)Math.PI * num3 * num3 * ((settings.m_raisePower > 0f) ? (2f / ((settings.m_raisePower + 1f) * (settings.m_raisePower + 2f))) : 1f))); float num5 = Mathf.Max(0.1f, num4 * settings.m_raiseDelta); if (!(f.Up <= 0.005f)) { return Mathf.CeilToInt(f.Up / num5 - 0.001f); } return 0; } private static bool Enough(int k) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if ((Object)(object)probe == (Object)null) { GameObject val = new GameObject("BuildExtend hoe probe"); val.SetActive(false); Object.DontDestroyOnLoad((Object)val); probe = val.AddComponent<Piece>(); probe.m_dlc = ""; } Requirement[] resources = piece.m_resources; probe.m_resources = ((IEnumerable<Requirement>)resources).Select((Func<Requirement, Requirement>)((Requirement q) => new Requirement { m_resItem = q.m_resItem, m_amount = (int)Math.Min(2147483647L, (long)q.GetAmount(0) * (long)k) })).ToArray(); probe.m_craftingStation = null; probe.m_name = piece.m_name; return player.HaveRequirements(probe, (RequirementMode)0); } private static bool Release(Player p) { //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) Measure(now: true); if (paidFill.Moved <= 0.005f) { ((Character)p).Message((MessageType)2, (ops > 0 && paid < ops) ? "$msg_missingrequirement" : ((kind == Kind.Level) ? Plugin.T("Здесь уже ровно", "Already level here") : Plugin.T("Здесь нечего насыпать", "Nothing to raise here")), 0, (Sprite)null, false); Reset(); return false; } Ground.Area a = Area(paidLength); int num = ((!free) ? Cost(a, paidFill) : 0); if (num > 0 && Chests.Present && Chests.Reserve(p, piece, num) != Chests.Gate.Ready) { ((Character)p).Message((MessageType)2, Plugin.T("Материалы из сундуков ещё не переданы — повторите", "The chests' materials are not handed over yet - try again"), 0, (Sprite)null, false); Reset(); return false; } ItemData rightItem = ((Humanoid)p).GetRightItem(); float buildStamina = p.GetBuildStamina(); if (!((Character)p).HaveStamina(buildStamina)) { Hud.instance.StaminaBarEmptyFlash(); Reset(); return false; } ((Character)p).UseStamina(buildStamina); if (rightItem != null && rightItem.m_shared.m_useDurability) { rightItem.m_durability -= p.GetPlaceDurability(rightItem) * Game.m_durabilityRate; } if (num > 0) { p.ConsumeResources(piece.m_resources, 0, -1, num); } if (Planet.On) { if (a.Level && Planet.CanLevel) { Planet.LevelArea(a, apply: true); } else { Planet.RaiseArea(a, apply: true); } } else { Ground.Apply(a); } Vector3 val = anchor + fwd * ((a.A0 + a.A1) * 0.5f); piece.m_placeEffect.Create(val, Quaternion.identity, (Transform)null, 1f, -1, ((Character)p).GetZDOID()); op.m_onPlacedEffect.Create(val, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); p.m_lastToolUseTime = Time.time; string text = Plugin.T("Выровнено по высоте " + Size(a), "Levelled to height " + Size(a)) + ((paidFill.Up > 0.005f) ? Plugin.T($", подсыпано {paidFill.Up:0.#} м³", $", {paidFill.Up:0.#} m³ filled") : ""); ((Character)p).Message((MessageType)1, text + ((paid < ops) ? Plugin.T(": на остальное не хватило материалов", ": not enough materials for the rest") : ""), 0, (Sprite)null, false); Reset(); return false; } private static string Size(Ground.Area a) { return string.Format("{0:0.#} × {1:0.#} {2}", a.A1 - a.A0, 2f * a.Half, Plugin.T("м", "m")); } internal static void Reset() { busy = false; player = null; piece = null; op = null; } internal static void Draw() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) if (busy) { Ground.Area area = Area(length); bool num = paid < ops; Color faceColor = (num ? new Color(1f, 0.3f, 0.2f, 0.14f) : new Color(0.85f, 0.7f, 0.35f, 0.14f)); Color edgeColor = (num ? new Color(1f, 0.45f, 0.35f, 0.9f) : new Color(1f, 0.85f, 0.4f, 0.9f)); float num2 = ((kind == Kind.Level) ? (area.Top - 0.05f) : (Mathf.Min(fill.Low, area.Top) - 0.05f)); float num3 = ((kind == Kind.Level) ? (area.Top + 0.05f) : area.Top); Overlay.Box(anchor, fwd, side, up, new Vector3(area.A0, 0f - area.Half, num2), new Vector3(area.A1, area.Half, num3), faceColor, edgeColor); } } internal static string Description() { Ground.Area a = Area(length); string text = Plugin.T("м³", "m³"); string text2 = ((kind == Kind.Level) ? (Plugin.T("Отпустите ЛКМ — выровнять по высоте: ", "Release LMB to level to height: ") + Size(a) + string.Format(", {0}{1:0.##} {2}", (a.Top >= 0f) ? "+" : "", a.Top, Plugin.T("м", "m")) + Plugin.T($" · срезать {fill.Down:0.#} {text}, подсыпать {fill.Up:0.#} {text}", $" · cut {fill.Down:0.#} {text}, fill {fill.Up:0.#} {text}")) : (Plugin.T("Отпустите ЛКМ — насыпать: ", "Release LMB to raise: ") + Size(a) + string.Format(", +{0:0.##} {1} · {2:0.#} {3}", Plugin.HoeHeight.Value, Plugin.T("м", "m"), fill.Up, text))); if (fill.Moved <= 0.005f) { text2 = text2 + " · " + ((kind == Kind.Level) ? Plugin.T("здесь уже ровно", "already level") : Plugin.T("здесь уже выше", "already higher here")); } else if (paid < ops) { text2 = text2 + " · <color=red>" + Plugin.T($"хватит на {Math.Abs(paidLength) + 1f:0} м", $"enough for {Math.Abs(paidLength) + 1f:0} m") + "</color>"; } text2 = text2 + "\n" + Plugin.Hint(Plugin.T("колесо", "wheel")) + " " + Plugin.T("ширина", "width") + " "; text2 = text2 + Plugin.Hint(Plugin.T("Ctrl+колесо", "Ctrl+wheel")) + " " + Plugin.T("высота", "height") + " "; return text2 + Plugin.Hint(Plugin.T("ПКМ", "RMB")) + " " + Plugin.T("отмена", "cancel"); } } internal static class Ground { internal struct Area { public Vector3 Anchor; public Vector3 Up; public Vector3 Fwd; public float A0; public float A1; public float Half; public float Top; public bool Level; public int Op; } internal struct Fill { public float Up; public float Down; public float Low; internal float Moved => Up + Down; } private sealed class Pending { internal long Id; internal TerrainComp Comp; internal Area Area; internal float Since; } private const string Rpc = "BuildExtend_RaiseArea"; private const string Done = "BuildExtend_RaiseDone"; private const int Format = 2; private const float MaxDelta = 8f; private static readonly List<Heightmap> maps = new List<Heightmap>(); private static readonly List<Pending> pending = new List<Pending>(); private static ZRoutedRpc registered; private static Vector3 Side(Area a) { //IL_0000: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.Cross(Vector3.up, a.Fwd); return ((Vector3)(ref val)).normalized; } private static Vector3 Center(Area a) { //IL_0001: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) return a.Anchor + a.Fwd * ((a.A0 + a.A1) * 0.5f); } private static float Radius(Area a) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) Vector2 val = new Vector2((a.A1 - a.A0) * 0.5f, a.Half); return ((Vector2)(ref val)).magnitude + 1.5f; } private static bool Inside(Area a, Vector3 p) { //IL_0000: 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_000c: 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_001a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = p - a.Anchor; float num = Vector3.Dot(val, a.Fwd); float num2 = Vector3.Dot(val, Side(a)); if (num >= a.A0 - 0.01f && num <= a.A1 + 0.01f) { return Mathf.Abs(num2) <= a.Half + 0.01f; } return false; } private static IEnumerable<(int x, int y, Vector3 world)> Vertices(Heightmap h, Area a) { int n = h.m_width + 1; int half = h.m_width / 2; float s = h.m_scale; float num = Radius(a); Vector3 origin = ((Component)h).transform.position; int cx = default(int); int cy = default(int); h.WorldToVertex(Center(a), ref cx, ref cy); int reach = Mathf.CeilToInt(num / s); for (int y = Math.Max(0, cy - reach); y <= Math.Min(n - 1, cy + reach); y++) { for (int x = Math.Max(0, cx - reach); x <= Math.Min(n - 1, cx + reach); x++) { Vector3 val = origin + new Vector3((float)(x - half) * s, 0f, (float)(y - half) * s); if (Inside(a, val)) { yield return (x: x, y: y, world: val); } } } } private static float Target(Area a, TerrainComp comp, int index, float height) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) float num = a.Anchor.y + a.Top; if ((Object)(object)comp != (Object)null && comp.m_initialized && comp.m_levelDelta != null && index < comp.m_levelDelta.Length) { float num2 = height - (comp.m_levelDelta[index] + comp.m_smoothDelta[index]); num = Mathf.Clamp(num, num2 - 8f, num2 + 8f); } if (!a.Level) { return Mathf.Max(height, num); } return num; } private static void Maps(Area a) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) maps.Clear(); Heightmap.FindHeightmap(Center(a), Radius(a), maps); maps.RemoveAll((Heightmap h) => (Object)(object)h == (Object)null || h.IsDistantLod || h.m_heights == null || h.m_heights.Count == 0); } internal static Fill Measure(Area a) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) Fill result = default(Fill); Maps(a); HashSet<long> hashSet = new HashSet<long>(); bool flag = false; foreach (Heightmap map in maps) { TerrainComp comp = TerrainComp.FindTerrainCompiler(((Component)map).transform.position); int num = map.m_width + 1; float num2 = map.m_scale * map.m_scale; foreach (var (num3, num4, val) in Vertices(map, a)) { if (hashSet.Add(((long)Mathf.RoundToInt(val.x * 4f) << 32) ^ (uint)Mathf.RoundToInt(val.z * 4f))) { float num5 = ((Component)map).transform.position.y + map.GetHeight(num3, num4); float num6 = num5 - a.Anchor.y; if (!flag || num6 < result.Low) { result.Low = num6; flag = true; } float num7 = Target(a, comp, num4 * num + num3, num5) - num5; if (num7 > 0f) { result.Up += num7 * num2; } else { result.Down -= num7 * num2; } } } } return result; } private static void Register() { if (ZRoutedRpc.instance != null && registered != ZRoutedRpc.instance) { registered = ZRoutedRpc.instance; registered.Register<long, ZDOID>("BuildExtend_RaiseDone", (Action<long, long, ZDOID>)OnDone); } } internal static void Apply(Area a) { //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_009f: 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) Register(); Maps(a); long num = ((long)Random.Range(int.MinValue, int.MaxValue) << 32) ^ Time.frameCount; foreach (Heightmap map in maps) { TerrainComp andCreateTerrainCompiler = map.GetAndCreateTerrainCompiler(); if (!((Object)(object)andCreateTerrainCompiler == (Object)null) && !((Object)(object)andCreateTerrainCompiler.m_nview == (Object)null) && andCreateTerrainCompiler.m_nview.IsValid()) { if (andCreateTerrainCompiler.m_nview.IsOwner()) { Change(andCreateTerrainCompiler, a); continue; } ZPackage val = new ZPackage(); val.Write(2); val.Write(num); val.Write(a.Anchor); val.Write(a.Fwd); val.Write(a.A0); val.Write(a.A1); val.Write(a.Half); val.Write(a.Top); val.Write(a.Level); val.Write(a.Op); andCreateTerrainCompiler.m_nview.InvokeRPC("BuildExtend_RaiseArea", new object[1] { val }); pending.Add(new Pending { Id = num, Comp = andCreateTerrainCompiler, Area = a, Since = Time.unscaledTime }); } } if ((Object)(object)ClutterSystem.instance != (Object)null) { ClutterSystem.instance.ResetGrass(Center(a), Radius(a)); } } internal static void Tick() { for (int num = Ground.pending.Count - 1; num >= 0; num--) { Pending pending = Ground.pending[num]; if ((Object)(object)pending.Comp == (Object)null || (Object)(object)pending.Comp.m_nview == (Object)null || !pending.Comp.m_nview.IsValid()) { Ground.pending.RemoveAt(num); } else if (!(Time.unscaledTime - pending.Since < 3f)) { Ground.pending.RemoveAt(num); Plugin.Warn("area raise: the ground's owner did not answer (no BuildExtend there?), changing it here"); pending.Comp.m_nview.ClaimOwnership(); Change(pending.Comp, pending.Area); } } } private static void OnDone(long sender, long id, ZDOID zdo) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) pending.RemoveAll((Pending p) => p.Id == id && ((Object)(object)p.Comp == (Object)null || (Object)(object)p.Comp.m_nview == (Object)null || !p.Comp.m_nview.IsValid() || p.Comp.m_nview.GetZDO().m_uid == zdo)); } internal static void Listen(TerrainComp comp) { if (!((Object)(object)comp.m_nview == (Object)null)) { comp.m_nview.Register<ZPackage>("BuildExtend_RaiseArea", (Action<long, ZPackage>)delegate(long sender, ZPackage pkg) { OnChange(comp, sender, pkg); }); } } private static void OnChange(TerrainComp comp, long sender, ZPackage pkg) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)comp == (Object)null || !comp.m_nview.IsValid() || !comp.m_nview.IsOwner()) { return; } int num = pkg.ReadInt(); if (num >= 1 && num <= 2) { long num2 = pkg.ReadLong(); Area a = new Area { Anchor = pkg.ReadVector3(), Up = Vector3.up, Fwd = pkg.ReadVector3(), A0 = pkg.ReadSingle(), A1 = pkg.ReadSingle(), Half = pkg.ReadSingle(), Top = pkg.ReadSingle() }; if (num >= 2) { a.Level = pkg.ReadBool(); a.Op = pkg.ReadInt(); } Change(comp, a); Register(); if (ZRoutedRpc.instance != null && sender != ZNet.GetUID()) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "BuildExtend_RaiseDone", new object[2] { num2, comp.m_nview.GetZDO().m_uid }); } } } private static void Change(TerrainComp comp, Area a) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)comp == (Object)null || !comp.m_initialized || (Object)(object)comp.m_hmap == (Object)null || comp.m_hmap.m_heights == null) { return; } Heightmap hmap = comp.m_hmap; int num = comp.m_width + 1; float y = ((Component)comp).transform.position.y; bool flag = false; foreach (var item3 in Vertices(hmap, a)) { int item = item3.x; int item2 = item3.y; int num2 = item2 * num + item; if (num2 >= 0 && num2 < comp.m_levelDelta.Length) { float num3 = y + hmap.GetHeight(item, item2); float num4 = Target(a, comp, num2, num3) - num3; if (!(Mathf.Abs(num4) <= 0.001f)) { comp.m_levelDelta[num2] = Mathf.Clamp(comp.m_levelDelta[num2] + num4 + comp.m_smoothDelta[num2], -8f, 8f); comp.m_smoothDelta[num2] = 0f; comp.m_modifiedHeight[num2] = true; flag = true; } } } bool flag2 = a.Level && Paint(comp, a); if (flag || flag2) { comp.Save(false); hmap.Poke(1, false); if ((Object)(object)ClutterSystem.instance != (Object)null) { ClutterSystem.instance.ResetGrass(Center(a), Radius(a)); } } } private static bool Paint(TerrainComp comp, Area a) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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) //IL_00bc: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_0107: 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_0115: Unknown result type (might be due to invalid IL or missing references) TerrainOp val = default(TerrainOp); if (a.Op == 0 || (Object)(object)ObjectDB.instance == (Object)null || !ObjectDB.instance.TryGetTerrainOp(a.Op, ref val) || (Object)(object)val == (Object)null) { return false; } Settings settings = val.m_settings; if (!settings.m_paintCleared) { return false; } float num = Mathf.Max(0.5f, settings.m_paintRadius); Vector3 val2 = Side(a); float y = a.Anchor.y + a.Top; int num2 = Mathf.Max(1, Mathf.CeilToInt((a.A1 - a.A0) / num)); int num3 = Mathf.Max(1, Mathf.CeilToInt(2f * a.Half / num)); for (int i = 0; i <= num2; i++) { for (int j = 0; j <= num3; j++) { Vector3 val3 = a.Anchor + a.Fwd * Mathf.Lerp(a.A0, a.A1, (float)i / (float)num2) + val2 * Mathf.Lerp(0f - a.Half, a.Half, (float)j / (float)num3); val3.y = y; comp.PaintCleared(val3, Vector3.zero, settings); } } return true; } } [HarmonyPatch] internal static class Hooks { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyPatch(typeof(Player), "UpdatePlacement")] private static bool Placement(Player __instance, bool takeInput) { try { return Stretch.BeforePlacement(__instance, takeInput); } catch (Exception ex) { Plugin.Warn("placement: " + ex); Stretch.Cancel(); return true; } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] private static void Ghost(Player __instance) { if ((Stretch.HidesGhost || Hoe.Busy) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { if ((Object)(object)__instance.m_placementGhost != (Object)null) { __instance.m_placementGhost.SetActive(false); } if ((Object)(object)__instance.m_placementMarkerInstance != (Object)null) { __instance.m_placementMarkerInstance.SetActive(false); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Hud), "SetupPieceInfo")] private static void PieceInfo(Hud __instance, Piece piece) { //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Invalid comparison between Unknown and I4 //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Invalid comparison between Unknown and I4 //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Invalid comparison between Unknown and I4 //IL_045b: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)piece == (Object)null || (Object)(object)localPlayer == (Object)null) { return; } if (Hoe.Busy) { if (!((Object)(object)piece != (Object)(object)Hoe.Piece)) { for (int i = 0; i < piece.m_resources.Length && i < __instance.m_requirementItems.Length; i++) { InventoryGui.SetupRequirement(__instance.m_requirementItems[i].transform, piece.m_resources[i], localPlayer, false, 0, Hoe.Ops); } TMP_Text buildSelection = __instance.m_buildSelection; buildSelection.text += $" ×{Hoe.Ops}"; __instance.m_pieceDescription.text = Hoe.Description(); } return; } if (Plugin.KeyHint.Value && (Object)(object)piece == (Object)(object)localPlayer.GetSelectedPiece()) { string text = Hoe.Refuse(localPlayer, piece); if (text == null) { TMP_Text pieceDescription = __instance.m_pieceDescription; pieceDescription.text = pieceDescription.text + "\n" + Plugin.Hint(Plugin.T("удерживать ЛКМ и вести", "hold LMB and look")) + " " + Plugin.T("выровнять по высоте", "level to height"); return; } if (text != "") { TMP_Text pieceDescription2 = __instance.m_pieceDescription; pieceDescription2.text = pieceDescription2.text + "\n" + text; return; } } if (Stretch.Removing) { __instance.m_pieceDescription.text = Stretch.Description(); } else if (Stretch.ShowsPanel) { if (!((Object)(object)piece != (Object)(object)Stretch.Prefab)) { int num = Math.Max(1, Stretch.Segments); bool flag = (int)piece.FreeBuildKey() == 25; for (int j = 0; j < piece.m_resources.Length && j < __instance.m_requirementItems.Length; j++) { InventoryGui.SetupRequirement(__instance.m_requirementItems[j].transform, piece.m_resources[j], localPlayer, flag, 0, num); } TMP_Text buildSelection2 = __instance.m_buildSelection; buildSelection2.text += $" ×{Stretch.Segments}"; __instance.m_pieceDescription.text = Stretch.Description(); } } else if (Plugin.Enabled.Value && Plugin.KeyHint.Value && !((Object)(object)piece != (Object)(object)localPlayer.GetSelectedPiece()) && !((Object)(object)((Component)piece).GetComponent<TerrainOp>() != (Object)null) && !((Object)(object)((Component)piece).GetComponent<TerrainModifier>() != (Object)null)) { string text2 = " " + Plugin.Hint(Stretch.ModeKey() + Plugin.T("колесо", "wheel")) + " " + Plugin.T("режим", "mode"); if (Plugin.Hammer.Value == HammerMode.Normal) { TMP_Text pieceDescription = __instance.m_pieceDescription; pieceDescription.text = pieceDescription.text + "\n" + Plugin.Hint(Stretch.ModeKey() + Plugin.T("колесо", "wheel")) + " " + Plugin.T("режим молота: обычная стройка (x1)", "hammer mode: normal building (x1)"); } else if (Checks.Refuse(piece) == null) { TMP_Text pieceDescription = __instance.m_pieceDescription; pieceDescription.text = pieceDescription.text + "\n" + Plugin.Hint(Plugin.T("удерживать ЛКМ", "hold LMB")) + " " + Plugin.T("протянуть", "stretch") + (Plugin.StretchRemoval.Value ? (" " + Plugin.Hint(Plugin.T("удерживать СКМ и вести", "hold MMB and look")) + " " + Plugin.T("снести зону", "remove a zone")) : "") + " " + Plugin.Hint((((int)Plugin.UndoModifier.Value == 306 || (int)Plugin.UndoModifier.Value == 305) ? "Ctrl+" : (((int)Plugin.UndoModifier.Value == 0) ? "" : (((object)Plugin.UndoModifier.Value/*cast due to .constrained prefix*/).ToString() + "+"))) + ((object)Plugin.UndoKey.Value/*cast due to .constrained prefix*/).ToString()) + " " + Plugin.T("отменить", "undo") + text2; } } } catch (Exception ex) { Plugin.Warn("build panel: " + ex.Message); } } [HarmonyPostfix] [HarmonyPatch(typeof(TerrainComp), "Awake")] private static void TerrainListen(TerrainComp __instance) { try { Ground.Listen(__instance); } catch (Exception ex) { Plugin.Warn("terrain: " + ex.Message); } } [HarmonyPrefix] [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] private static void CameraBefore(GameCamera __instance, out float __state) { __state = __instance.m_distance; } [HarmonyPostfix] [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] private static void CameraAfter(GameCamera __instance, float __state) { if (Hoe.Busy) { __instance.m_distance = __state; } } [HarmonyPrefix] [HarmonyPatch(typeof(Menu), "Update")] private static void Escape(Menu __instance) { if (Stretch.EatEscape()) { __instance.m_hiddenFrames = 0; } } } [HarmonyPatch] internal static class IronHoe { internal const string Name = "BuildExtend_HoeIron"; private const string Token = "be_hoe_iron"; private static GameObject prefab; private const string LevelName = "BuildExtend_LevelHeight"; private static readonly Dictionary<string, string> sources = new Dictionary<string, string>(); private static readonly List<Requirement[]> ours = new List<Requirement[]>(); internal static bool Made => (Object)(object)prefab != (Object)null; internal static bool Is(ItemData item) { if (item != null && (Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name == "BuildExtend_HoeIron"; } return false; } private static GameObject Make(GameObject hoe) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00a3: Expected O, but got Unknown if ((Object)(object)prefab != (Object)null) { return prefab; } if ((Object)(object)hoe == (Object)null) { return null; } GameObject val = new GameObject("BuildExtend prefabs"); val.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val); GameObject val2 = Object.Instantiate<GameObject>(hoe, val.transform); ((Object)val2).name = "BuildExtend_HoeIron"; ItemDrop component = val2.GetComponent<ItemDrop>(); SharedData val3 = component.m_itemData.m_shared; if (val3 == hoe.GetComponent<ItemDrop>().m_itemData.m_shared) { ItemData itemData = component.m_itemData; SharedData val4 = (SharedData)typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(val3, null); val3 = val4; itemData.m_shared = val4; } val3.m_name = "$be_hoe_iron"; val3.m_description = "$be_hoe_iron_description"; val3.m_maxQuality = 1; SharedData obj = val3; obj.m_maxDurability *= 1.5f; Material val5 = null; Renderer[] componentsInChildren = val2.GetComponentsInChildren<Renderer>(true); foreach (Renderer val6 in componentsInChildren) { Material[] sharedMaterials = val6.sharedMaterials; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null) && ((Object)sharedMaterials[j]).name.StartsWith("stone", StringComparison.OrdinalIgnoreCase)) { sharedMaterials[j] = val5 ?? (val5 = Metal(sharedMaterials[j])); flag = true; } } if (flag) { val6.sharedMaterials = sharedMaterials; } } Pieces(val.transform, val3); prefab = val2; return prefab; } private static Material Metal(Material stone) { //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_0012: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: 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) Material val = new Material(stone) { name = "BuildExtend iron head" }; Texture2D val2 = new Texture2D(32, 32, (TextureFormat)4, true) { name = "BuildExtend iron", wrapMode = (TextureWrapMode)0, filterMode = (FilterMode)1 }; Random random = new Random(1337); float[] array = new float[32]; for (int i = 0; i < 32; i++) { array[i] = (float)random.NextDouble() * 0.12f - 0.06f; } Color[] array2 = (Color[])(object)new Color[1024]; for (int j = 0; j < 32; j++) { for (int k = 0; k < 32; k++) { float num = 0.62f + array[j] + (float)random.NextDouble() * 0.05f - 0.025f; if (random.NextDouble() < 0.02) { num -= 0.18f; } array2[j * 32 + k] = new Color(num * 0.96f, num * 0.98f, num, 1f); } } val2.SetPixels(array2); val2.Apply(true, true); if (val.HasProperty("_MainTex")) { val.SetTexture("_MainTex", (Texture)(object)val2); } if (val.HasProperty("_Color")) { val.SetColor("_Color", new Color(0.78f, 0.8f, 0.84f, 1f)); } if (val.HasProperty("_Metallic")) { val.SetFloat("_Metallic", 0.85f); } if (val.HasProperty("_Glossiness")) { val.SetFloat("_Glossiness", 0.6f); } if (val.HasProperty("_MetalGloss")) { val.SetFloat("_MetalGloss", 0.6f); } return val; } internal static bool IsAreaPiece(Piece p) { if ((Object)(object)p != (Object)null) { return sources.ContainsKey(Utils.GetPrefabName(((Component)p).gameObject)); } return false; } internal static string Source(Piece p) { if (!((Object)(object)p != (Object)null) || !sources.TryGetValue(Utils.GetPrefabName(((Component)p).gameObject), out var value)) { return null; } return value; } private static void Pieces(Transform holder, SharedData shared) { PieceTable table = shared.m_buildPieces; PieceTable own; if (!((Object)(object)table == (Object)null)) { own = Object.Instantiate<GameObject>(((Component)table).gameObject, holder).GetComponent<PieceTable>(); ((Object)own).name = "BuildExtend_HoeIronPieces"; own.m_pieces = new List<GameObject>(table.m_pieces); GameObject obj = Find((Settings s) => s.m_raise && s.m_raiseDelta > 0f, "raise"); if ((Object)(object)obj == (Object)null) { Plugin.Warn("iron hoe: no raise piece in the hoe's table, no \"Level to height\""); } Kin(obj, "BuildExtend_LevelHeight", "be_level_height"); shared.m_buildPieces = own; } GameObject Find(Func<Settings, bool> fits, string hint) { List<GameObject> source = table.m_pieces.Where(delegate(GameObject g) { if ((Object)(object)g != (Object)null) { TerrainOp component = g.GetComponent<TerrainOp>(); if (component != null) { return fits(component.m_settings); } } return false; }).ToList(); return ((IEnumerable<GameObject>)source).FirstOrDefault((Func<GameObject, bool>)((GameObject g) => ((Object)g).name.IndexOf(hint, StringComparison.OrdinalIgnoreCase) >= 0)) ?? source.FirstOrDefault(); } void Kin(GameObject source, string name, string token) { if (!((Object)(object)source == (Object)null)) { GameObject val = Object.Instantiate<GameObject>(source, holder); ((Object)val).name = name; Piece component = val.GetComponent<Piece>(); component.m_name = "$" + token; component.m_description = "$" + token + "_description"; component.m_icon = AreaIcon(component.m_icon); own.m_pieces.Insert(own.m_pieces.IndexOf(source) + 1, val); sources[name] = ((Object)source).name; Plugin.Log("iron hoe: \"" + name + "\" after \"" + ((Object)source).name + "\""); } } } private static Sprite AreaIcon(Sprite icon) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00a9: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)icon == (Object)null || (Object)(object)icon.texture == (Object)null) { return icon; } RenderTexture val = null; RenderTexture active = RenderTexture.active; try { Rect textureRect = icon.textureRect; int num = Mathf.RoundToInt(((Rect)(ref textureRect)).width); int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).height); if (num < 8 || num2 < 8) { return icon; } val = RenderTexture.GetTemporary(((Texture)icon.texture).width, ((Texture)icon.texture).height, 0, (RenderTextureFormat)0); Graphics.Blit((Texture)(object)icon.texture, val); RenderTexture.active = val; Texture2D val2 = new Texture2D(num, num2, (TextureFormat)4, false) { name = "BuildExtend area icon", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; val2.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0); Color val3 = default(Color); ((Color)(ref val3))..ctor(1f, 0.8f, 0.2f, 1f); int num3 = Mathf.Max(2, num / 24); int num4 = Mathf.Max(1, num / 16); for (int i = num4; i < num2 - num4; i++) { for (int j = num4; j < num - num4; j++) { bool num5 = j < num4 + num3 || j >= num - num4 - num3 || i < num4 + num3 || i >= num2 - num4 - num3; bool flag = (j < num4 + num / 5 || j >= num - num4 - num / 5) && (i < num4 + num2 / 5 || i >= num2 - num4 - num2 / 5); bool flag2 = (j + i) / Mathf.Max(1, num / 8) % 2 == 0; if (num5 && (flag || flag2)) { val2.SetPixel(j, i, val3); } } } val2.Apply(); return Sprite.Create(val2, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f), icon.pixelsPerUnit); } catch (Exception ex) { Plugin.Warn("iron hoe icon: " + ex.Message); return icon; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { RenderTexture.ReleaseTemporary(val); } } } internal static void Words() { Localization instance = Localization.instance; if (instance != null) { Dictionary<string, string> value = Traverse.Create((object)instance).Field("m_translations").GetValue<Dictionary<string, string>>(); if (value != null) { value["be_hoe_iron"] = Plugin.T("Железная мотыга", "Iron hoe"); value["be_hoe_iron_description"] = Plugin.T("Мотыга с железным наконечником. Делается в кузнице из мотыги 3 уровня и железа. Кроме обычных «Выровнять землю» и «Поднять землю» умеет «Выровнять по высоте»: зажать ЛКМ и вести взгляд вперёд, колесо — ширина, Ctrl+колесо — высота.", "A hoe with an iron head, made at the forge from a level 3 hoe and iron. Besides the usual \"Level ground\" and \"Raise ground\" it has \"Level to height\": hold LMB and look ahead, wheel - width, Ctrl+wheel - height."); value["be_level_height"] = Plugin.T("Выровнять по высоте", "Level to height"); value["be_level_height_description"] = Plugin.T("Зажать ЛКМ и вести взгляд вперёд — прямоугольник по взгляду; колесо — ширина, Ctrl+колесо — высота (от точки нажатия). Всё внутри встаёт ровно на эту высоту: выше срезается, ниже подсыпается, края прямые. Срез бесплатно, подсыпка — камень по объёму. Щелчок — полоса шириной в рамку.", "Hold LMB and look ahead - a rectangle along the look; wheel - width, Ctrl+wheel - height (from the press point). Everything inside goes to that height: cut above, filled below, straight edges. Cutting is free, filling costs stone by the volume. A click - a strip as wide as the frame."); } } } [HarmonyPrefix] [HarmonyPatch(typeof(ZNetScene), "Awake")] private static void Scene(ZNetScene __instance) { try { if (Plugin.IronHoeOn.Value) { GameObject val = Make(((IEnumerable<GameObject>)__instance.m_prefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject p) => (Object)(object)p != (Object)null && ((Object)p).name == "Hoe"))); if ((Object)(object)val != (Object)null && !__instance.m_prefabs.Contains(val)) { __instance.m_prefabs.Add(val); } } } catch (Exception ex) { Plugin.Warn("iron hoe (scene): " + ex.Message); } } [HarmonyPostfix] [HarmonyPatch(typeof(ObjectDB), "Awake")] private static void Items(ObjectDB __instance) { Add(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static void ItemsCopied(ObjectDB __instance) { Add(__instance); } private static void Add(ObjectDB db) { //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Expected O, but got Unknown try { if (!Plugin.IronHoeOn.Value) { return; } GameObject itemPrefab = db.GetItemPrefab("Hoe"); GameObject itemPrefab2 = db.GetItemPrefab("Iron"); ItemDrop val = ((itemPrefab2 != null) ? itemPrefab2.GetComponent<ItemDrop>() : null); GameObject val2 = Make(itemPrefab); if ((Object)(object)val2 == (Object)null || (Object)(object)val == (Object)null) { return; } Words(); if (!db.m_items.Contains(val2)) { db.m_items.Add(val2); db.UpdateRegisters(); } ItemDrop drop = val2.GetComponent<ItemDrop>(); if (!db.m_recipes.Any((Recipe r) => (Object)(object)r != (Object)null && (Object)(object)r.m_item == (Object)(object)drop)) { CraftingStation val3 = db.m_recipes.Select((Recipe r) => (!((Object)(object)r != (Object)null)) ? null : r.m_craftingStation).FirstOrDefault((Func<CraftingStation, bool>)((CraftingStation s) => (Object)(object)s != (Object)null && s.m_name == "$piece_forge")); Recipe val4 = ScriptableObject.CreateInstance<Recipe>(); ((Object)val4).name = "Recipe_BuildExtend_HoeIron"; val4.m_item = drop; val4.m_amount = 1; val4.m_enabled = true; val4.m_craftingStation = val3; val4.m_repairStation = val3; val4.m_minStationLevel = 1; val4.m_resources = (Requirement[])(object)new Requirement[2] { new Requirement { m_resItem = itemPrefab.GetComponent<ItemDrop>(), m_amount = 1, m_recover = true }, new Requirement { m_resItem = val, m_amount = Math.Max(1, Plugin.IronHoeIron.Value), m_recover = true } }; db.m_recipes.Add(val4); ours.Add(val4.m_resources); } } catch (Exception ex) { Plugin.Warn("iron hoe: " + ex.Message); } } private static bool IsOurs(Recipe r) { if ((Object)(object)r != (Object)null && r.m_resources != null) { return ours.Contains(r.m_resources); } return false; } private static bool Full(ItemData i, string hoeName) { if (i != null && i.m_shared.m_name == hoeName) { return i.m_quality >= i.m_shared.m_maxQuality; } return false; } internal static int MaxLevel(ObjectDB db) { int? obj; if (db == null) { obj = null; } else { GameObject itemPrefab = db.GetItemPrefab("Hoe"); obj = ((itemPrefab == null) ? ((int?)null) : itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_maxQuality); } return obj ?? 3; } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "HaveRequirementItems")] private static void Enough(Player __instance, Recipe piece, int amount, ref bool __result) { try { if (__result && IsOurs(piece)) { string hoeName = piece.m_resources[0].m_resItem.m_itemData.m_shared.m_name; if (((Humanoid)__instance).GetInventory().GetAllItems().Count((ItemData i) => Full(i, hoeName)) < Math.Max(1, amount)) { __result = false; } } } catch (Exception ex) { Plugin.Warn("iron hoe recipe: " + ex.Message); } } [HarmonyPrefix] [HarmonyPatch(typeof(Player), "ConsumeResources")] private static bool Take(Player __instance, Requirement[] requirements, int multiplier) { try { if (requirements == null || !ours.Contains(requirements)) { return true; } Inventory inventory = ((Humanoid)__instance).GetInventory(); string hoeName = requirements[0].m_resItem.m_itemData.m_shared.m_name; for (int i = 0; i < Math.Max(1, multiplier); i++) { ItemData val = ((IEnumerable<ItemData>)inventory.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i2) => Full(i2, hoeName))); if (val == null) { break; } inventory.RemoveItem(val); } for (int num = 1; num < requirements.Length; num++) { Requirement val2 = requirements[num]; int num2 = val2.GetAmount(1) * Math.Max(1, multiplier); if ((Object)(object)val2.m_resItem != (Object)null && num2 > 0) { inventory.RemoveItem(val2.m_resItem.m_itemData.m_shared.m_name, num2, -1, true); } } return false; } catch (Exception ex) { Plugin.Warn("iron hoe recipe: " + ex.Message); return true; } } } [HarmonyPatch] internal static class IronHoeLanguage { private static MethodBase TargetMethod() { return AccessTools.GetDeclaredMethods(typeof(Localization)).FirstOrDefault((MethodInfo m) => m.Name == "SetupLanguage"); } private static bool Prepare() { return TargetMethod() != null; } private static void Postfix() { try { if (IronHoe.Made) { IronHoe.Words(); } } catch (Exception ex) { Plugin.Warn("iron hoe words: " + ex.Message); } } } internal struct Vec { public float X; public float Y; public float Z; public float Length => (float)Math.Sqrt(Dot(this, this)); public float this[int axis] => axis switch { 1 => Y, 0 => X, _ => Z, }; public Vec(float x, float y, float z) { X = x; Y = y; Z = z; } public static Vec operator +(Vec a, Vec b) { return new Vec(a.X + b.X, a.Y + b.Y, a.Z + b.Z); } public static Vec operator -(Vec a, Vec b) { return new Vec(a.X - b.X, a.Y - b.Y, a.Z - b.Z); } public static Vec operator *(Vec a, float k) { return new Vec(a.X * k, a.Y * k, a.Z * k); } public static float Dot(Vec a, Vec b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } public static Vec Cross(Vec a, Vec b) { return new Vec(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X); } public static Vec Axis(int axis, float length) { return new Vec((axis == 0) ? length : 0f, (axis == 1) ? length : 0f, (axis == 2) ? length : 0f); } public override string ToString() { return $"({X:0.##}, {Y:0.##}, {Z:0.##})"; } } internal enum ShapeKind { None, Line, Plane } internal sealed class Shape { public ShapeKind Kind; public Vec U; public Vec V; public Vec W; public bool Cube; public bool Beam; public bool Pole; public override string ToString() { if (Kind != ShapeKind.None) { Vec u; if (Kind != ShapeKind.Line) { string obj = (Cube ? "cube " : "plane "); u = U; string text = u.ToString(); u = V; return obj + text + " × " + u.ToString(); } u = U; return "line " + u.ToString(); } return "none"; } } internal static class Lattice { internal struct Cell { public int I; public int J; public Vec Pos; public Vec Dir; public Vec Up; } private const float Min = 0.05f; internal static Shape FromPiece(IList<Vec> snaps, Vec boundsMin, Vec boundsMax, bool beamsTouching = false) { Vec vec = boundsMax - boundsMin; if (snaps != null && snaps.Count >= 2) { Shape shape = FromSnaps(snaps); if (shape.Beam && beamsTouching) { if (!shape.Pole) { if (vec.Y > 0.05f) { shape.V = Vec.Axis(1, vec.Y); } } else if (vec.X > 0.05f) { shape.U = Vec.Axis(0, vec.X); } } if (shape.Kind != ShapeKind.None) { return shape; } } bool flag = vec.X > 0.05f; bool flag2 = vec.Z > 0.05f; if (flag && flag2) { return new Shape { Kind = ShapeKind.Plane, U = Vec.Axis(0, vec.X), V = Vec.Axis(2, vec.Z) }; } if (flag) { return new Shape { Kind = Sh