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 HandDrawnMap v0.4.1
Hand_Drawn_Map.dll
Decompiled 5 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Hand_Drawn_Map")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Local hand-drawn cartography canvas for Valheim.")] [assembly: AssemblyFileVersion("0.4.1.0")] [assembly: AssemblyInformationalVersion("0.4.1+c3bc977be77a30366a7e8eac4310f866bcdb5f9d")] [assembly: AssemblyProduct("Hand_Drawn_Map")] [assembly: AssemblyTitle("Hand_Drawn_Map")] [assembly: AssemblyVersion("0.4.1.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 Hand_Drawn_Map { public sealed class BrushGraphic : MaskableGraphic { protected override void OnPopulateMesh(VertexHelper mesh) { //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_009a: 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_00ab: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_014e: 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_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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) //IL_0166: Unknown result type (might be due to invalid IL or missing references) mesh.Clear(); Rect rect = ((Graphic)this).rectTransform.rect; float num = ((Rect)(ref rect)).width * 0.5f; float num2 = Mathf.Max(0f, num - 1f); Vector2 val = default(Vector2); Vector2 val2 = default(Vector2); Color color = default(Color); for (int i = 0; i < 48; i++) { float num3 = (float)i * MathF.PI * 2f / 48f; float num4 = (float)(i + 1) * MathF.PI * 2f / 48f; ((Vector2)(ref val))..ctor(Mathf.Cos(num3), Mathf.Sin(num3)); ((Vector2)(ref val2))..ctor(Mathf.Cos(num4), Mathf.Sin(num4)); int currentVertCount = mesh.currentVertCount; Add(mesh, Vector2.zero, ((Graphic)this).color); Add(mesh, val * num2, ((Graphic)this).color); Add(mesh, val2 * num2, ((Graphic)this).color); mesh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2); ((Color)(ref color))..ctor(((Graphic)this).color.r, ((Graphic)this).color.g, ((Graphic)this).color.b, Mathf.Min(1f, ((Graphic)this).color.a * 3f)); currentVertCount = mesh.currentVertCount; Add(mesh, val * num2, color); Add(mesh, val * num, color); Add(mesh, val2 * num, color); Add(mesh, val2 * num2, color); mesh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2); mesh.AddTriangle(currentVertCount, currentVertCount + 2, currentVertCount + 3); } } private static void Add(VertexHelper mesh, Vector2 position, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_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_0015: 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) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) UIVertex simpleVert = UIVertex.simpleVert; simpleVert.position = Vector2.op_Implicit(position); simpleVert.color = Color32.op_Implicit(color); simpleVert.uv0 = Vector4.op_Implicit(Vector2.zero); mesh.AddVert(simpleVert); } } internal sealed class CanvasWindow : IDisposable { private enum Tool { Pencil, Eraser, Annotate } private readonly MapPlugin plugin; private readonly GameObject root; private readonly Canvas canvas; private readonly RectTransform panel; private readonly RectTransform viewport; private readonly Text status; private readonly Text pencilLabel; private readonly Text eraserLabel; private readonly Text annotateLabel; private readonly Text scaleLabel; private readonly RectTransform scaleBar; private readonly RectTransform scaleEnd; private readonly BrushGraphic brush; private readonly Image locationMarker; private Image nativeMarkerImage; private readonly Vector3[] nativeCorners = (Vector3[])(object)new Vector3[4]; private readonly bool readOnly; private readonly List<ChartGraphic> batches = new List<ChartGraphic>(); internal readonly List<InkSegment> Segments = new List<InkSegment>(); private bool invalid = true; private Tool tool; private bool activeTemporary; private Guid gesture; private bool gestureSubmitted; private bool unsentPoints; private float nextStrokeSend; private float nextFadeRefresh; private bool panning; private bool erasing; private ChartStroke activeStroke; private ChartPoint lastBrush; private Vector2 lastPointer; private float eraseRadius; private Vector2 lastSize; private float lastProjection; private readonly Font font; private string notice; internal bool IsOpen { get { if ((Object)(object)root != (Object)null) { return root.activeSelf; } return false; } } internal bool InGesture { get { if (activeStroke == null && !erasing) { return panning; } return true; } } private ChartDocument Document => plugin.Document; private float Extent => (float)Minimap.instance.m_textureSize * Minimap.instance.m_pixelSize; private float WorldPerPixel { get { //IL_0011: 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_001f: Unknown result type (might be due to invalid IL or missing references) RectTransform rectTransform = ((Graphic)Minimap.instance.m_mapImageLarge).rectTransform; Rect rect = rectTransform.rect; float num = ((Rect)(ref rect)).height * Mathf.Abs(((Transform)rectTransform).lossyScale.y); if (num < 1f) { num = Screen.height; } return Extent * Document.Zoom * canvas.scaleFactor / num; } } internal CanvasWindow(MapPlugin plugin, bool readOnly) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_044d: Unknown result type (might be due to invalid IL or missing references) //IL_045c: Unknown result type (might be due to invalid IL or missing references) //IL_0487: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Unknown result type (might be due to invalid IL or missing references) //IL_05a3: Unknown result type (might be due to invalid IL or missing references) //IL_05b9: Unknown result type (might be due to invalid IL or missing references) //IL_05cf: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05f8: Unknown result type (might be due to invalid IL or missing references) //IL_05fd: Unknown result type (might be due to invalid IL or missing references) //IL_0619: Unknown result type (might be due to invalid IL or missing references) //IL_062e: Unknown result type (might be due to invalid IL or missing references) //IL_064d: Unknown result type (might be due to invalid IL or missing references) //IL_0662: Unknown result type (might be due to invalid IL or missing references) //IL_0685: Unknown result type (might be due to invalid IL or missing references) //IL_068f: Expected O, but got Unknown CanvasWindow canvasWindow = this; this.plugin = plugin; this.readOnly = readOnly; font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf"); root = new GameObject("HandDrawnMap", new Type[4] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster) }); Object.DontDestroyOnLoad((Object)(object)root); canvas = root.GetComponent<Canvas>(); canvas.renderMode = (RenderMode)0; canvas.sortingOrder = 100; CanvasScaler component = root.GetComponent<CanvasScaler>(); component.uiScaleMode = (ScaleMode)1; component.referenceResolution = new Vector2(1920f, 1080f); component.screenMatchMode = (ScreenMatchMode)0; component.matchWidthOrHeight = 0.5f; panel = Rect("MapPanel", root.transform); panel.anchorMin = Vector2.zero; panel.anchorMax = Vector2.one; AddImage(panel, new Color(0.12f, 0.1f, 0.08f)); RectTransform val = Rect("Toolbar", (Transform)(object)panel); val.anchorMin = new Vector2(0f, 1f); val.anchorMax = Vector2.one; val.pivot = new Vector2(0.5f, 1f); val.sizeDelta = new Vector2(0f, 96f); Text val2 = Label(val, "HAND DRAWN MAP", new Vector2(20f, -26f), new Vector2(270f, 44f), 23); RectTransform rectTransform = ((Graphic)val2).rectTransform; RectTransform rectTransform2 = ((Graphic)val2).rectTransform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0f, 1f); rectTransform2.anchorMax = val3; rectTransform.anchorMin = val3; pencilLabel = Button(val, "Pencil", 300f, delegate { canvasWindow.SelectTool(Tool.Pencil); }); eraserLabel = Button(val, "Eraser", 430f, delegate { canvasWindow.SelectTool(Tool.Eraser); }); annotateLabel = Button(val, "Annotate", 560f, delegate { canvasWindow.SelectTool(Tool.Annotate); }); Button(val, "Close", 690f, plugin.CloseMap); Text val4 = Label(val, "Clear", new Vector2(850f, -27f), new Vector2(65f, 38f), 20); RectTransform rectTransform3 = ((Graphic)val4).rectTransform; RectTransform rectTransform4 = ((Graphic)val4).rectTransform; ((Vector2)(ref val3))..ctor(0f, 1f); rectTransform4.anchorMax = val3; rectTransform3.anchorMin = val3; Button(val, "Guides", 920f, ClearGuides); Button(val, "Annotations", 1050f, ClearAnnotations, 150f); Button(val, "Resync", 1230f, delegate { plugin.Shared.RequestResync(); }); scaleLabel = Label(val, "", new Vector2(300f, -59f), new Vector2(200f, 24f), 17); RectTransform rectTransform5 = ((Graphic)scaleLabel).rectTransform; RectTransform rectTransform6 = ((Graphic)scaleLabel).rectTransform; ((Vector2)(ref val3))..ctor(0f, 1f); rectTransform6.anchorMax = val3; rectTransform5.anchorMin = val3; scaleBar = ScalePart(val, new Vector2(300f, -82f), new Vector2(180f, 2f)); ScalePart(val, new Vector2(300f, -85f), new Vector2(2f, 8f)); scaleEnd = ScalePart(val, new Vector2(478f, -85f), new Vector2(2f, 8f)); viewport = Rect("Parchment", (Transform)(object)panel); viewport.anchorMin = Vector2.zero; viewport.anchorMax = Vector2.one; viewport.offsetMin = new Vector2(12f, 44f); viewport.offsetMax = new Vector2(-12f, -100f); AddImage(viewport, new Color(0.86f, 0.81f, 0.68f)); ((Component)viewport).gameObject.AddComponent<RectMask2D>(); RectTransform val5 = Rect("PlayerLocation", (Transform)(object)viewport); locationMarker = ((Component)val5).gameObject.AddComponent<Image>(); ((Graphic)locationMarker).raycastTarget = false; locationMarker.preserveAspect = true; ((Component)val5).gameObject.SetActive(false); RectTransform val6 = Rect("BrushFootprint", (Transform)(object)viewport); brush = ((Component)val6).gameObject.AddComponent<BrushGraphic>(); ((Graphic)brush).raycastTarget = false; ((Component)brush).gameObject.SetActive(false); RectTransform val7 = Rect("Status", (Transform)(object)panel); val7.anchorMin = Vector2.zero; val7.anchorMax = new Vector2(1f, 0f); val7.pivot = new Vector2(0.5f, 0f); val7.sizeDelta = new Vector2(-24f, 40f); status = Label(val7, "", Vector2.zero, Vector2.zero, 18); ((Graphic)status).rectTransform.anchorMin = Vector2.zero; ((Graphic)status).rectTransform.anchorMax = Vector2.one; ((Graphic)status).rectTransform.offsetMin = new Vector2(8f, 0f); ((Graphic)status).rectTransform.offsetMax = Vector2.zero; UpdateTools(); root.SetActive(false); Canvas.willRenderCanvases += new WillRenderCanvases(UpdateLocationMarker); } internal void SetOpen(bool open) { FinishGesture(); root.SetActive(open); if (open) { RaiseCanvas(); Canvas.ForceUpdateCanvases(); MatchNativeBounds(); Canvas.ForceUpdateCanvases(); invalid = true; } else { ((Component)brush).gameObject.SetActive(false); ((Component)locationMarker).gameObject.SetActive(false); } } internal void Tick() { //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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: 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_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0181: 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) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) if (ZInput.GetKeyDown((KeyCode)27, true)) { plugin.CloseMap(); return; } ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); MatchNativeBounds(); if (!readOnly && plugin.Shared.CanEdit && Input.GetKeyDown((KeyCode)122) && (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305))) { FinishGesture(); notice = (plugin.Shared.Undo() ? null : plugin.Shared.Status); } Vector2 val = Vector2.op_Implicit(ZInput.pointerPosition); bool flag = RectTransformUtility.RectangleContainsScreenPoint(viewport, val, (Camera)null); Vector2 val2 = default(Vector2); RectTransformUtility.ScreenPointToLocalPointInRectangle(viewport, val, (Camera)null, ref val2); ChartPoint world = ToWorld(val2); if (flag && !InGesture) { float mouseScrollWheel = ZInput.GetMouseScrollWheel(); if (mouseScrollWheel != 0f) { Zoom(Mathf.Clamp(mouseScrollWheel, -0.05f, 0.05f) * 2f, val2); } } if (flag && !InGesture && ZInput.GetMouseButtonDown(2)) { panning = true; lastPointer = val2; } if (panning) { if (!ZInput.GetMouseButton(2)) { panning = false; } else { Vector2 val3 = val2 - lastPointer; Document.Center -= new ChartPoint(val3.x, val3.y) * WorldPerPixel; ClampCenter(); lastPointer = val2; Changed(); } } if (flag && !InGesture && !readOnly && plugin.Shared.CanEdit && ZInput.GetMouseButtonDown(0)) { gesture = Guid.NewGuid(); gestureSubmitted = false; if (tool == Tool.Eraser) { erasing = true; lastBrush = world; eraseRadius = plugin.EraserPixels.Value * WorldPerPixel; EraseTo(world, initial: true); } else { StartStroke(world); } } if ((plugin.Shared.Annotations.Count > 0 || plugin.Guides.Count > 0) && Time.unscaledTime >= nextFadeRefresh) { invalid = true; nextFadeRefresh = Time.unscaledTime + 0.05f; } if (activeStroke != null || erasing) { if (!ZInput.GetMouseButton(0) || !flag || !plugin.Shared.CanEdit) { FinishGesture(); } else if (erasing) { EraseTo(world); } else { AppendPoint(world); } } if (activeStroke != null && Time.unscaledTime >= nextStrokeSend) { FlushStroke(); } Rect rect = viewport.rect; if (((Rect)(ref rect)).size != lastSize || !Mathf.Approximately(lastProjection, WorldPerPixel)) { invalid = true; } if (invalid) { Rebuild(); } UpdateScale(); UpdateBrush(val2, flag); string text = "Right-click: survey with compass"; status.text = (readOnly ? "Chart could not be loaded. Saving and editing are disabled; check the log and restore the .bak file." : (notice ?? $"LMB: {tool} | Middle drag: pan | Wheel: zoom | Ctrl+Z: undo own edits | {plugin.MapKey.Value} / Esc: close | {text} | {plugin.Shared.Status}")); } private void StartStroke(ChartPoint world) { activeTemporary = tool == Tool.Annotate; activeStroke = new ChartStroke(plugin.PencilPixels.Value * WorldPerPixel); notice = null; activeStroke.Points.Add(world); unsentPoints = true; nextStrokeSend = Time.unscaledTime + 0.05f; invalid = true; } private void AppendPoint(ChartPoint world) { if (!((world - activeStroke.Points[activeStroke.Points.Count - 1]).LengthSquared < WorldPerPixel * WorldPerPixel)) { if (activeStroke.Points.Count >= 128) { FlushStroke(); } if (activeStroke != null) { activeStroke.Points.Add(world); unsentPoints = true; invalid = true; } } } private void EraseTo(ChartPoint world, bool initial = false) { if (initial || !((world - lastBrush).LengthSquared < 1E-06f)) { gestureSubmitted |= plugin.Shared.Erase(gesture, lastBrush, world, eraseRadius); invalid = true; lastBrush = world; } } private void FlushStroke() { nextStrokeSend = Time.unscaledTime + 0.05f; if (activeStroke == null || !unsentPoints) { return; } ChartPoint item = activeStroke.Points[activeStroke.Points.Count - 1]; if (plugin.Shared.Draw(gesture, activeStroke.Points.ToArray(), activeStroke.Width, activeTemporary)) { gestureSubmitted = true; activeStroke.Points.Clear(); activeStroke.Points.Add(item); } else { if (!activeTemporary) { plugin.Shared.PreserveDraft(gesture, activeStroke.Points.ToArray(), activeStroke.Width); } notice = plugin.Shared.Status; activeStroke = null; } unsentPoints = false; invalid = true; } private void FinishGesture() { FlushStroke(); if (gestureSubmitted && plugin.Shared.CanEdit) { plugin.Shared.End(gesture); } gestureSubmitted = false; gesture = Guid.Empty; activeStroke = null; unsentPoints = false; erasing = false; panning = false; invalid = true; } internal void FinishSharedGesture() { FinishGesture(); } internal void Invalidate() { invalid = true; } private void Changed() { plugin.Dirty = true; invalid = true; } private void Zoom(float step, Vector2 local) { //IL_0001: 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) ChartPoint chartPoint = ToWorld(local); Document.Zoom = Mathf.Clamp(Document.Zoom * (1f - step), Minimap.instance.m_minZoom, Minimap.instance.m_maxZoom); Document.Center += chartPoint - ToWorld(local); ClampCenter(); Changed(); } private void ClampCenter() { float num = Extent * 0.5f; Document.Center = new ChartPoint(Mathf.Clamp(Document.Center.X, 0f - num, num), Mathf.Clamp(Document.Center.Z, 0f - num, num)); } private ChartPoint ToWorld(Vector2 point) { //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) return ChartGeometry.ToWorld(new ChartPoint(point.x, point.y), Document.Center, WorldPerPixel); } private ChartPoint ToScreen(ChartPoint point) { return ChartGeometry.ToScreen(point, Document.Center, WorldPerPixel); } private void Rebuild() { //IL_0012: 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_001a: 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_0065: 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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) Segments.Clear(); Rect rect = viewport.rect; lastSize = ((Rect)(ref rect)).size; lastProjection = WorldPerPixel; Color val = default(Color); ((Color)(ref val))..ctor(0.18f, 0.15f, 0.12f); foreach (ChartStroke stroke in Document.Strokes) { RenderStroke(stroke, val); } foreach (TemporaryInk annotation in plugin.Shared.Annotations) { RenderStroke(annotation.Stroke, new Color(0.38f, 0.22f, 0.12f, annotation.Opacity * 0.8f)); } if (activeStroke != null) { RenderStroke(activeStroke, (Color)(activeTemporary ? new Color(0.38f, 0.22f, 0.12f, 0.8f) : val)); } foreach (SurveyGuide guide in plugin.Guides) { float num = Mathf.Clamp01((guide.Expires - Time.unscaledTime) / Mathf.Min(30f, guide.Expires - guide.Created)); ChartPoint chartPoint = guide.Origin + guide.Direction * ChartPoint.Dot(Document.Center - guide.Origin, guide.Direction); float num2 = ((Vector2)(ref lastSize)).magnitude * lastProjection; AddSegment(chartPoint - guide.Direction * num2, chartPoint + guide.Direction * num2, 1.5f, new Color(0.16f, 0.35f, 0.48f, num * 0.65f)); } int num3 = Mathf.Max(1, (Segments.Count + 6000 - 1) / 6000); while (batches.Count < num3) { RectTransform obj = Rect("Ink", (Transform)(object)viewport); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; Vector2 offsetMin = (obj.offsetMax = Vector2.zero); obj.offsetMin = offsetMin; ChartGraphic chartGraphic = ((Component)obj).gameObject.AddComponent<ChartGraphic>(); ((Graphic)chartGraphic).raycastTarget = false; chartGraphic.Window = this; chartGraphic.Batch = batches.Count; batches.Add(chartGraphic); } for (int i = 0; i < batches.Count; i++) { ((Component)batches[i]).gameObject.SetActive(i < num3); if (i < num3) { ((Graphic)batches[i]).SetVerticesDirty(); } } ((Component)locationMarker).transform.SetAsLastSibling(); ((Component)brush).transform.SetAsLastSibling(); invalid = false; } private void RenderStroke(ChartStroke stroke, Color color) { //IL_0034: 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) if (stroke.Points.Count == 1) { AddSegment(stroke.Points[0], stroke.Points[0], stroke.Width / lastProjection, color); } for (int i = 1; i < stroke.Points.Count; i++) { AddSegment(stroke.Points[i - 1], stroke.Points[i], stroke.Width / lastProjection, color); } } private void AddSegment(ChartPoint a, ChartPoint b, float width, Color color) { //IL_0056: 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_0077: Unknown result type (might be due to invalid IL or missing references) a = ToScreen(a); b = ToScreen(b); if (ChartGeometry.ClipLine(ref a, ref b, lastSize.x * 0.5f + width, lastSize.y * 0.5f + width)) { Segments.Add(new InkSegment(new Vector2(a.X, a.Z), new Vector2(b.X, b.Z), Mathf.Max(0.5f, width), color)); } } private void UpdateTools() { //IL_002b: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_005c: Unknown result type (might be due to invalid IL or missing references) Color val = default(Color); ((Color)(ref val))..ctor(1f, 0.75f, 0.3f); ((Graphic)pencilLabel).color = ((tool == Tool.Pencil) ? val : Color.white); ((Graphic)eraserLabel).color = ((tool == Tool.Eraser) ? val : Color.white); ((Graphic)annotateLabel).color = ((tool == Tool.Annotate) ? val : Color.white); } private void SelectTool(Tool selected) { FinishGesture(); tool = selected; notice = null; UpdateTools(); } private void ClearGuides() { plugin.Guides.Clear(); notice = null; invalid = true; } private void ClearAnnotations() { FinishGesture(); plugin.Shared.ClearAnnotations(); notice = null; invalid = true; } private void UpdateScale() { //IL_0026: 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) float num = MetricScale.Length(WorldPerPixel, 180f); float num2 = num / WorldPerPixel; scaleBar.sizeDelta = new Vector2(num2, 2f); scaleEnd.anchoredPosition = new Vector2(300f + num2 - 2f, -85f); scaleLabel.text = MetricScale.Label(num); } private void UpdateBrush(Vector2 local, bool inside) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) ((Component)brush).gameObject.SetActive(inside && !panning && !readOnly && plugin.Shared.CanEdit); if (inside) { float num = ((tool != Tool.Eraser) ? (((activeStroke != null) ? (activeStroke.Width / WorldPerPixel) : plugin.PencilPixels.Value) * 0.5f) : (erasing ? (eraseRadius / WorldPerPixel) : plugin.EraserPixels.Value)); ((Graphic)brush).rectTransform.anchoredPosition = local; ((Graphic)brush).rectTransform.sizeDelta = Vector2.one * Mathf.Max(1f, num * 2f); Color color = ((tool == Tool.Eraser) ? new Color(0.65f, 0.15f, 0.12f) : new Color(0.12f, 0.22f, 0.3f)); color.a = plugin.BrushOpacity.Value; ((Graphic)brush).color = color; } } private void UpdateLocationMarker() { //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_009a: 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_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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0155: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0185: 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_01ca: 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_01ee: Unknown result type (might be due to invalid IL or missing references) if (!IsOpen) { return; } Player localPlayer = Player.m_localPlayer; if (!plugin.ShowMyLocation.Value || (Object)(object)localPlayer == (Object)null || (Object)(object)Minimap.instance == (Object)null) { ((Component)locationMarker).gameObject.SetActive(false); return; } if ((Object)(object)nativeMarkerImage == (Object)null) { nativeMarkerImage = ((Component)Minimap.instance.m_largeMarker).GetComponentInChildren<Image>(true); } if ((Object)(object)nativeMarkerImage == (Object)null) { ((Component)locationMarker).gameObject.SetActive(false); return; } Vector3 position = ((Component)localPlayer).transform.position; ChartPoint chartPoint = ToScreen(new ChartPoint(position.x, position.z)); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(chartPoint.X, chartPoint.Z); Rect rect = viewport.rect; if (!((Rect)(ref rect)).Contains(val)) { ((Component)locationMarker).gameObject.SetActive(false); return; } locationMarker.sprite = nativeMarkerImage.overrideSprite; ((Graphic)locationMarker).color = ((Graphic)nativeMarkerImage).color; RectTransform rectTransform = ((Graphic)nativeMarkerImage).rectTransform; RectTransform rectTransform2 = ((Graphic)locationMarker).rectTransform; rect = rectTransform.rect; float num = ((Rect)(ref rect)).width * Mathf.Abs(((Transform)rectTransform).lossyScale.x); rect = rectTransform.rect; rectTransform2.sizeDelta = new Vector2(num, ((Rect)(ref rect)).height * Mathf.Abs(((Transform)rectTransform).lossyScale.y)) / canvas.scaleFactor; ((Graphic)locationMarker).rectTransform.anchoredPosition = val; Camera mainCamera = Utils.GetMainCamera(); float num2 = (((Object)(object)mainCamera != (Object)null) ? ((Component)mainCamera).transform.eulerAngles.y : ((Component)localPlayer).transform.eulerAngles.y); ((Transform)((Graphic)locationMarker).rectTransform).localRotation = Quaternion.Euler(0f, 0f, 0f - num2); ((Component)locationMarker).gameObject.SetActive(true); } private void RaiseCanvas() { //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) int sortingLayerID = canvas.sortingLayerID; int num = 100; int num2 = SortingLayer.GetLayerValueFromID(sortingLayerID); Canvas[] array = Resources.FindObjectsOfTypeAll<Canvas>(); foreach (Canvas val in array) { if ((Object)(object)val == (Object)(object)canvas || !((Behaviour)val).isActiveAndEnabled) { continue; } Scene scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { int layerValueFromID = SortingLayer.GetLayerValueFromID(val.sortingLayerID); if (layerValueFromID > num2) { sortingLayerID = val.sortingLayerID; num2 = layerValueFromID; num = val.sortingOrder; } else if (layerValueFromID == num2) { num = Mathf.Max(num, val.sortingOrder); } } } canvas.sortingLayerID = sortingLayerID; canvas.overrideSorting = true; canvas.sortingOrder = Mathf.Min(32767, num + 1); } private void MatchNativeBounds() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_004d: 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_005a: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_008f: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) RectTransform rectTransform = ((Graphic)Minimap.instance.m_mapImageLarge).rectTransform; rectTransform.GetWorldCorners(nativeCorners); Canvas componentInParent = ((Component)rectTransform).GetComponentInParent<Canvas>(); Camera obj = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null); Vector2 val = RectTransformUtility.WorldToScreenPoint(obj, nativeCorners[0]); Vector2 val2 = RectTransformUtility.WorldToScreenPoint(obj, nativeCorners[2]); RectTransform val3 = (RectTransform)root.transform; Vector2 val4 = default(Vector2); RectTransformUtility.ScreenPointToLocalPointInRectangle(val3, val, (Camera)null, ref val4); Vector2 val5 = default(Vector2); RectTransformUtility.ScreenPointToLocalPointInRectangle(val3, val2, (Camera)null, ref val5); Vector2 val6 = val4; Rect rect = val3.rect; Vector2 val7 = val6 - ((Rect)(ref rect)).min; Vector2 val8 = val5; rect = val3.rect; Vector2 val9 = val8 - ((Rect)(ref rect)).max; if (val2.x - val.x < (float)Screen.width * 0.25f || val2.y - val.y < (float)Screen.height * 0.25f) { ((Vector2)(ref val7))..ctor(100f, 100f); ((Vector2)(ref val9))..ctor(-100f, -100f); } if (panel.offsetMin != val7 || panel.offsetMax != val9) { panel.offsetMin = val7; panel.offsetMax = val9; invalid = true; } } private static RectTransform ScalePart(RectTransform parent, Vector2 position, Vector2 size) { //IL_001e: 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_0036: 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_0053: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = Rect("Scale", (Transform)(object)parent); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0f, 1f); obj.anchorMax = val; obj.anchorMin = val; obj.pivot = Vector2.zero; obj.anchoredPosition = position; obj.sizeDelta = size; AddImage(obj, new Color(0.9f, 0.86f, 0.75f)); ((Graphic)((Component)obj).GetComponent<Image>()).raycastTarget = false; return obj; } private static RectTransform Rect(string name, Transform parent) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) RectTransform component = new GameObject(name, new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>(); ((Transform)component).SetParent(parent, false); return component; } private static void AddImage(RectTransform rect, Color color) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) ((Graphic)((Component)rect).gameObject.AddComponent<Image>()).color = color; } private Text Label(RectTransform parent, string text, Vector2 position, Vector2 size, int fontSize) { //IL_001e: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = Rect("Label", (Transform)(object)parent); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0f, 0.5f); obj.anchorMax = val; obj.anchorMin = val; obj.pivot = new Vector2(0f, 0.5f); obj.anchoredPosition = position; obj.sizeDelta = size; Text obj2 = ((Component)obj).gameObject.AddComponent<Text>(); obj2.font = font; obj2.fontSize = fontSize; ((Graphic)obj2).color = Color.white; obj2.text = text; obj2.alignment = (TextAnchor)3; ((Graphic)obj2).raycastTarget = false; return obj2; } private Text Button(RectTransform parent, string caption, float x, Action action, float width = 120f) { //IL_0029: 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_0040: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_00b4: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Rect(caption, (Transform)(object)parent); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0f, 1f); val.anchorMax = val2; val.anchorMin = val2; val.pivot = new Vector2(0f, 1f); val.anchoredPosition = new Vector2(x, -8f); val.sizeDelta = new Vector2(width, 38f); AddImage(val, new Color(0.25f, 0.21f, 0.16f)); Button obj = ((Component)val).gameObject.AddComponent<Button>(); ((Selectable)obj).targetGraphic = (Graphic)(object)((Component)val).GetComponent<Image>(); ((UnityEvent)obj.onClick).AddListener((UnityAction)delegate { action(); }); return Label(val, caption, new Vector2(12f, 0f), new Vector2(width - 24f, 38f), 20); } public void Dispose() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Canvas.willRenderCanvases -= new WillRenderCanvases(UpdateLocationMarker); if ((Object)(object)root != (Object)null) { Object.Destroy((Object)(object)root); } } } public readonly struct ChartPoint { public readonly float X; public readonly float Z; public float LengthSquared => X * X + Z * Z; public ChartPoint(float x, float z) { X = x; Z = z; } public static ChartPoint operator +(ChartPoint a, ChartPoint b) { return new ChartPoint(a.X + b.X, a.Z + b.Z); } public static ChartPoint operator -(ChartPoint a, ChartPoint b) { return new ChartPoint(a.X - b.X, a.Z - b.Z); } public static ChartPoint operator *(ChartPoint a, float b) { return new ChartPoint(a.X * b, a.Z * b); } public static float Dot(ChartPoint a, ChartPoint b) { return a.X * b.X + a.Z * b.Z; } public static ChartPoint Lerp(ChartPoint a, ChartPoint b, float t) { return a + (b - a) * t; } } public sealed class ChartStroke { public float Width; public readonly List<ChartPoint> Points = new List<ChartPoint>(); public ChartStroke(float width) { Width = width; } } public sealed class ChartDocument { public const int MaxPoints = 200000; public const int MaxStrokes = 20000; public const int MaxStrokePoints = 4096; public readonly List<ChartStroke> Strokes = new List<ChartStroke>(); public ChartPoint Center; public float Zoom = 0.1f; public int PointCount; public bool Erase(ChartPoint from, ChartPoint to, float radius) { List<ChartStroke> list = new List<ChartStroke>(); bool flag = false; foreach (ChartStroke stroke in Strokes) { bool changed; List<ChartStroke> collection = ChartGeometry.Erase(stroke, from, to, radius, out changed); flag = flag || changed; list.AddRange(collection); } int num = 0; foreach (ChartStroke item in list) { num += item.Points.Count; } if (!flag || list.Count > 20000 || num > 200000) { return false; } Strokes.Clear(); Strokes.AddRange(list); PointCount = num; return true; } } public static class ChartGeometry { public static ChartPoint ToWorld(ChartPoint screen, ChartPoint center, float worldPerPixel) { return center + screen * worldPerPixel; } public static ChartPoint ToScreen(ChartPoint world, ChartPoint center, float worldPerPixel) { return (world - center) * (1f / worldPerPixel); } public static float DistanceSquared(ChartPoint point, ChartPoint a, ChartPoint b) { ChartPoint b2 = b - a; float t = ((b2.LengthSquared < 1E-12f) ? 0f : Clamp(ChartPoint.Dot(point - a, b2) / b2.LengthSquared, 0f, 1f)); return (point - ChartPoint.Lerp(a, b, t)).LengthSquared; } public static List<ChartStroke> Erase(ChartStroke stroke, ChartPoint from, ChartPoint to, float radius, out bool changed) { changed = false; float num = radius + stroke.Width * 0.5f; float num2 = num * num; List<ChartStroke> list = new List<ChartStroke>(); if (stroke.Points.Count == 1) { changed = DistanceSquared(stroke.Points[0], from, to) <= num2; if (!changed) { list.Add(stroke); } return list; } ChartStroke chartStroke = null; for (int i = 1; i < stroke.Points.Count; i++) { ChartPoint chartPoint = stroke.Points[i - 1]; ChartPoint chartPoint2 = stroke.Points[i]; ChartPoint chartPoint3 = chartPoint2 - chartPoint; List<float> list2 = new List<float> { 0f, 1f }; CircleCuts(chartPoint, chartPoint3, from, num, list2); CircleCuts(chartPoint, chartPoint3, to, num, list2); ChartPoint chartPoint4 = to - from; if (chartPoint4.LengthSquared > 1E-12f) { ChartPoint b = new ChartPoint(0f - chartPoint4.Z, chartPoint4.X) * (1f / (float)Math.Sqrt(chartPoint4.LengthSquared)); float num3 = ChartPoint.Dot(chartPoint3, b); if (Math.Abs(num3) > 1E-09f) { float num4 = ChartPoint.Dot(chartPoint - from, b); AddCut((num - num4) / num3, list2); AddCut((0f - num - num4) / num3, list2); } } list2.Sort(); for (int j = 1; j < list2.Count; j++) { float num5 = list2[j - 1]; float num6 = list2[j]; if (num6 - num5 < 1E-07f) { continue; } if (DistanceSquared(ChartPoint.Lerp(chartPoint, chartPoint2, (num5 + num6) * 0.5f), from, to) < num2) { changed = true; chartStroke = null; continue; } ChartPoint item = ChartPoint.Lerp(chartPoint, chartPoint2, num5); ChartPoint item2 = ChartPoint.Lerp(chartPoint, chartPoint2, num6); if (chartStroke == null) { chartStroke = new ChartStroke(stroke.Width); chartStroke.Points.Add(item); list.Add(chartStroke); } chartStroke.Points.Add(item2); } } if (!changed) { return new List<ChartStroke> { stroke }; } return list; } private static void CircleCuts(ChartPoint a, ChartPoint d, ChartPoint center, float radius, List<float> cuts) { double num = (double)d.X * (double)d.X + (double)d.Z * (double)d.Z; if (!(num < 1E-12)) { ChartPoint chartPoint = a - center; double num2 = 2.0 * ((double)chartPoint.X * (double)d.X + (double)chartPoint.Z * (double)d.Z); double num3 = (double)chartPoint.X * (double)chartPoint.X + (double)chartPoint.Z * (double)chartPoint.Z - (double)radius * (double)radius; double num4 = num2 * num2 - 4.0 * num * num3; if (!(num4 < 0.0)) { double num5 = Math.Sqrt(num4); AddCut((float)((0.0 - num2 - num5) / (2.0 * num)), cuts); AddCut((float)((0.0 - num2 + num5) / (2.0 * num)), cuts); } } } private static void AddCut(float t, List<float> cuts) { if (t > 0f && t < 1f) { cuts.Add(t); } } public static bool ClipLine(ref ChartPoint a, ref ChartPoint b, float halfWidth, float halfHeight) { ChartPoint chartPoint = b - a; float lo = 0f; float hi = 1f; if (!Clip(0f - chartPoint.X, a.X + halfWidth, ref lo, ref hi) || !Clip(chartPoint.X, halfWidth - a.X, ref lo, ref hi) || !Clip(0f - chartPoint.Z, a.Z + halfHeight, ref lo, ref hi) || !Clip(chartPoint.Z, halfHeight - a.Z, ref lo, ref hi)) { return false; } b = a + chartPoint * hi; a += chartPoint * lo; return true; } private static bool Clip(float p, float q, ref float lo, ref float hi) { if (Math.Abs(p) < 1E-12f) { return q >= 0f; } float num = q / p; if (p < 0f) { if (num > hi) { return false; } lo = Math.Max(lo, num); } else { if (num < lo) { return false; } hi = Math.Min(hi, num); } return true; } private static float Clamp(float value, float lo, float hi) { return Math.Max(lo, Math.Min(hi, value)); } } internal readonly struct InkSegment { public readonly Vector2 A; public readonly Vector2 B; public readonly float Width; public readonly Color Color; public InkSegment(Vector2 a, Vector2 b, float width, Color color) { //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_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_0016: 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) A = a; B = b; Width = width; Color = color; } } public sealed class ChartGraphic : MaskableGraphic { internal const int BatchSize = 6000; internal CanvasWindow Window; internal int Batch; protected override void OnPopulateMesh(VertexHelper mesh) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_0081: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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_0147: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) mesh.Clear(); if (Window == null) { return; } int num = Batch * 6000; int num2 = Mathf.Min(num + 6000, Window.Segments.Count); for (int i = num; i < num2; i++) { InkSegment inkSegment = Window.Segments[i]; Vector2 val = inkSegment.B - inkSegment.A; ? val2; if (!(((Vector2)(ref val)).sqrMagnitude > 1E-06f)) { val2 = new Vector2(0f, inkSegment.Width * 0.5f); } else { Vector2 val3 = new Vector2(0f - val.y, val.x); val2 = ((Vector2)(ref val3)).normalized * (inkSegment.Width * 0.5f); } Vector2 val4 = (Vector2)val2; Vector2 val5 = (Vector2)((((Vector2)(ref val)).sqrMagnitude > 1E-06f) ? (((Vector2)(ref val)).normalized * (inkSegment.Width * 0.5f)) : new Vector2(inkSegment.Width * 0.5f, 0f)); int currentVertCount = mesh.currentVertCount; Add(mesh, inkSegment.A - val5 - val4, inkSegment.Color); Add(mesh, inkSegment.A - val5 + val4, inkSegment.Color); Add(mesh, inkSegment.B + val5 + val4, inkSegment.Color); Add(mesh, inkSegment.B + val5 - val4, inkSegment.Color); mesh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2); mesh.AddTriangle(currentVertCount, currentVertCount + 2, currentVertCount + 3); } } private static void Add(VertexHelper mesh, Vector2 position, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_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_0015: 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) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) UIVertex simpleVert = UIVertex.simpleVert; simpleVert.position = Vector2.op_Implicit(position); simpleVert.color = Color32.op_Implicit(color); simpleVert.uv0 = Vector4.op_Implicit(Vector2.zero); mesh.AddVert(simpleVert); } } internal static class ChartStore { private const int Magic = 1212435761; private const int Version = 1; public static ChartDocument Load(string path) { ChartDocument chartDocument = new ChartDocument(); if (!File.Exists(path)) { return chartDocument; } using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path)); if (binaryReader.ReadInt32() != 1212435761 || binaryReader.ReadInt32() != 1) { throw new InvalidDataException("Unsupported chart file."); } chartDocument.Center = ReadPoint(binaryReader); chartDocument.Zoom = ReadFinite(binaryReader); if (chartDocument.Zoom <= 0f || chartDocument.Zoom > 10f) { throw new InvalidDataException("Invalid zoom."); } int num = ReadCount(binaryReader, 20000); for (int i = 0; i < num; i++) { float num2 = ReadFinite(binaryReader); if (num2 <= 0f || num2 > 100000f) { throw new InvalidDataException("Invalid stroke width."); } ChartStroke chartStroke = new ChartStroke(num2); int num3 = ReadCount(binaryReader, 200000); if (num3 == 0 || chartDocument.PointCount + num3 > 200000) { throw new InvalidDataException("Invalid point count."); } for (int j = 0; j < num3; j++) { chartStroke.Points.Add(ReadPoint(binaryReader)); } chartDocument.PointCount += num3; chartDocument.Strokes.Add(chartStroke); } if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length) { throw new InvalidDataException("Unexpected chart data."); } return chartDocument; } public static void Save(string path, ChartDocument document) { Directory.CreateDirectory(Path.GetDirectoryName(path)); string text = path + ".tmp"; using (FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None)) { using (BinaryWriter binaryWriter = new BinaryWriter(fileStream, Encoding.UTF8, leaveOpen: true)) { binaryWriter.Write(1212435761); binaryWriter.Write(1); WritePoint(binaryWriter, document.Center); binaryWriter.Write(document.Zoom); binaryWriter.Write(document.Strokes.Count); foreach (ChartStroke stroke in document.Strokes) { binaryWriter.Write(stroke.Width); binaryWriter.Write(stroke.Points.Count); foreach (ChartPoint point in stroke.Points) { WritePoint(binaryWriter, point); } } } fileStream.Flush(flushToDisk: true); } if (File.Exists(path)) { File.Replace(text, path, path + ".bak"); } else { File.Move(text, path); } } private static int ReadCount(BinaryReader reader, int maximum) { int num = reader.ReadInt32(); if (num < 0 || num > maximum) { throw new InvalidDataException("Chart exceeds size limits."); } return num; } private static float ReadFinite(BinaryReader reader) { float num = reader.ReadSingle(); if (float.IsNaN(num) || float.IsInfinity(num) || Math.Abs(num) > 10000000f) { throw new InvalidDataException("Invalid chart coordinate."); } return num; } private static ChartPoint ReadPoint(BinaryReader reader) { return new ChartPoint(ReadFinite(reader), ReadFinite(reader)); } private static void WritePoint(BinaryWriter writer, ChartPoint point) { writer.Write(point.X); writer.Write(point.Z); } } public sealed class InkHistory { private sealed class Edit { public readonly List<SavedStroke> Added = new List<SavedStroke>(); public readonly List<SavedStroke> Removed = new List<SavedStroke>(); public int AddedPoints => Added.Sum((SavedStroke stroke) => stroke.Points.Length); public int RemovedPoints => Removed.Sum((SavedStroke stroke) => stroke.Points.Length); public int PointCount => AddedPoints + RemovedPoints; } private sealed class SavedStroke { public readonly ChartStroke Stroke; public readonly ChartPoint[] Points; public readonly int Index; private readonly float width; public SavedStroke(ChartStroke stroke, int index) { Stroke = stroke; Points = stroke.Points.ToArray(); Index = index; width = stroke.Width; } public bool Matches() { if (Stroke.Width != width || Stroke.Points.Count != Points.Length) { return false; } for (int i = 0; i < Points.Length; i++) { if (Stroke.Points[i].X != Points[i].X || Stroke.Points[i].Z != Points[i].Z) { return false; } } return true; } } private const int MaxActions = 50; private const int MaxRetainedPoints = 1000000; private readonly List<Edit> edits = new List<Edit>(); private List<ChartStroke> before; private int retainedPoints; public int Count => edits.Count; public void Begin(ChartDocument document) { if (before == null) { before = new List<ChartStroke>(document.Strokes); } } public void Commit(ChartDocument document) { if (before == null) { return; } HashSet<ChartStroke> hashSet = new HashSet<ChartStroke>(before); HashSet<ChartStroke> hashSet2 = new HashSet<ChartStroke>(document.Strokes); Edit edit = new Edit(); for (int i = 0; i < before.Count; i++) { if (!hashSet2.Contains(before[i])) { edit.Removed.Add(new SavedStroke(before[i], i)); } } for (int j = 0; j < document.Strokes.Count; j++) { if (!hashSet.Contains(document.Strokes[j])) { edit.Added.Add(new SavedStroke(document.Strokes[j], j)); } } before = null; if (edit.Added.Count != 0 || edit.Removed.Count != 0) { edits.Add(edit); retainedPoints += edit.PointCount; while (edits.Count > 50 || retainedPoints > 1000000) { retainedPoints -= edits[0].PointCount; edits.RemoveAt(0); } } } public bool Undo(ChartDocument document, out bool conflict) { conflict = false; if (before != null || edits.Count == 0) { return false; } Edit edit = edits[edits.Count - 1]; HashSet<ChartStroke> hashSet = new HashSet<ChartStroke>(document.Strokes); foreach (SavedStroke item in edit.Added) { if (!hashSet.Contains(item.Stroke) || !item.Matches()) { conflict = true; return false; } } foreach (SavedStroke item2 in edit.Removed) { if (hashSet.Contains(item2.Stroke) || !item2.Matches()) { conflict = true; return false; } } int num = document.PointCount - edit.AddedPoints + edit.RemovedPoints; int num2 = document.Strokes.Count - edit.Added.Count + edit.Removed.Count; if (num > 200000 || num2 > 20000) { conflict = true; return false; } foreach (SavedStroke item3 in edit.Added) { document.Strokes.Remove(item3.Stroke); } foreach (SavedStroke item4 in edit.Removed) { document.Strokes.Insert(Math.Min(item4.Index, document.Strokes.Count), item4.Stroke); } document.PointCount = num; retainedPoints -= edit.PointCount; edits.RemoveAt(edits.Count - 1); return true; } } public static class MetricScale { public static float Length(float worldPerPixel, float targetPixels) { double num = worldPerPixel * targetPixels; if (num <= 0.0 || double.IsInfinity(num) || double.IsNaN(num)) { return 1f; } double num2 = Math.Pow(10.0, Math.Floor(Math.Log10(num))); double num3 = num / num2; return (float)((double)((num3 >= 5.0) ? 5 : ((!(num3 >= 2.0)) ? 1 : 2)) * num2); } public static string Label(float meters) { if (!(meters >= 1000f)) { return meters.ToString("0.##", CultureInfo.InvariantCulture) + " m"; } return (meters / 1000f).ToString("0.##", CultureInfo.InvariantCulture) + " km"; } } public sealed class MapJournal : IDisposable { private sealed class Record { public long Revision; public byte[] Bytes; } private const int Magic = 1212435762; private readonly string path; private readonly ConcurrentQueue<Record> queue = new ConcurrentQueue<Record>(); private readonly object gate = new object(); private Task worker = Task.CompletedTask; private long durable; private Exception failure; private long bytes; public readonly Guid Generation; public readonly SharedMap Loaded = new SharedMap(); public bool Corrupt { get; private set; } public long Durable { get { lock (gate) { return durable; } } } public Exception Failure { get { lock (gate) { return failure; } } } public bool HasRoom(int count) { return bytes + count + 36 < 65011712; } public MapJournal(string path, long world) { this.path = path; Directory.CreateDirectory(Path.GetDirectoryName(path)); if (File.Exists(path)) { if (new FileInfo(path).Length > 67108864) { throw new InvalidDataException("Shared map journal too large"); } using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(path))) { if (binaryReader.ReadInt32() != 1212435762 || binaryReader.ReadInt32() != 1 || binaryReader.ReadInt64() != world) { throw new InvalidDataException("Invalid shared map journal header"); } Generation = MapWire.ReadGuid(binaryReader); while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length) { try { int num = MapWire.Count(binaryReader, 32768); if (num == 0) { throw new InvalidDataException(); } byte[] array = binaryReader.ReadBytes(32); byte[] array2 = binaryReader.ReadBytes(num); if (array.Length != 32 || array2.Length != num) { throw new EndOfStreamException(); } using (SHA256 sHA = SHA256.Create()) { if (!sHA.ComputeHash(array2).SequenceEqual(array)) { throw new InvalidDataException("Journal checksum mismatch"); } } Loaded.Apply(MapWire.DecodeEdit(array2)); } catch (Exception ex) when (ex is IOException || ex is InvalidOperationException) { Corrupt = true; break; } } } bytes = new FileInfo(path).Length; if (!Corrupt) { File.Copy(path, path + ".bak", overwrite: true); } } else { Generation = Guid.NewGuid(); using (FileStream fileStream = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.Read)) { using BinaryWriter binaryWriter = new BinaryWriter(fileStream); binaryWriter.Write(1212435762); binaryWriter.Write(1); binaryWriter.Write(world); binaryWriter.Write(Generation.ToByteArray()); binaryWriter.Flush(); fileStream.Flush(flushToDisk: true); } bytes = new FileInfo(path).Length; } durable = Loaded.Revision; } public void Append(MapEdit edit) { byte[] array = MapWire.EncodeEdit(edit); lock (gate) { if (Corrupt || failure != null) { throw new IOException("Shared map storage is read-only", failure); } if (!HasRoom(array.Length)) { throw new IOException("Shared map storage limit reached"); } bytes += array.Length + 36; queue.Enqueue(new Record { Revision = edit.Revision, Bytes = array }); worker = worker.ContinueWith(delegate { Drain(); }, TaskScheduler.Default); } } private void Drain() { lock (gate) { if (failure != null) { return; } } if (queue.IsEmpty) { return; } try { long val = 0L; using (FileStream fileStream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read)) { using BinaryWriter binaryWriter = new BinaryWriter(fileStream); using SHA256 sHA = SHA256.Create(); Record result; while (queue.TryDequeue(out result)) { binaryWriter.Write(result.Bytes.Length); binaryWriter.Write(sHA.ComputeHash(result.Bytes)); binaryWriter.Write(result.Bytes); val = result.Revision; } binaryWriter.Flush(); fileStream.Flush(flushToDisk: true); } lock (gate) { durable = Math.Max(durable, val); } } catch (Exception ex) { lock (gate) { failure = ex; } } } public void Flush() { Task task; lock (gate) { task = worker; } task.GetAwaiter().GetResult(); } public void Dispose() { Flush(); } } [BepInPlugin("com.nopetrides.valheim.hand-drawn-map", "Hand Drawn Map", "0.4.1")] [DefaultExecutionOrder(-10000)] public sealed class MapPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(Minimap), "IsOpen")] private static class MapInput { private static void Postfix(ref bool __result) { if (BlocksInput) { __result = true; } } } [HarmonyPatch(typeof(Minimap), "Update")] private static class MapUpdate { private static bool Prefix() { Instance?.Poll(); if (!IsOpen) { return !ConsumedInput; } return false; } } [HarmonyPatch(typeof(Menu), "Update")] private static class MenuUpdate { private static bool Prefix() { if (!IsOpen) { return !ConsumedInput; } return false; } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class PeerConnected { private static void Prefix(ZNetPeer __0) { Instance?.Shared?.Register(__0); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private static class WorldShutdown { private static void Prefix() { Instance?.Window?.FinishSharedGesture(); Instance?.Shared?.Flush(); } } public const string Guid = "com.nopetrides.valheim.hand-drawn-map"; public const string Version = "0.4.1"; internal static MapPlugin Instance; internal ConfigEntry<KeyboardShortcut> MapKey; internal ConfigEntry<float> SurveyLifetime; internal ConfigEntry<float> PencilPixels; internal ConfigEntry<float> EraserPixels; internal ConfigEntry<float> AnnotationLifetime; internal ConfigEntry<float> BrushOpacity; internal ConfigEntry<bool> ShowMyLocation; internal ConfigEntry<bool> PersonalMapOnly; internal readonly List<SurveyGuide> Guides = new List<SurveyGuide>(); internal ChartDocument Document; internal CanvasWindow Window; internal bool Dirty; internal MapSession Shared; private bool headless; private Harmony harmony; private string savePath; private bool saveBlocked; private float lastSave; private int lastPoll = -1; private int consumedFrame = -10; private int blockThroughFrame = -10; private MapMode previousMode; internal bool Headless => headless; internal static bool IsOpen { get { if ((Object)(object)Instance != (Object)null && Instance.Window != null) { return Instance.Window.IsOpen; } return false; } } internal static bool BlocksInput { get { if (!IsOpen) { if ((Object)(object)Instance != (Object)null) { return Time.frameCount <= Instance.blockThroughFrame; } return false; } return true; } } internal static bool ConsumedInput { get { if ((Object)(object)Instance != (Object)null) { return Instance.consumedFrame == Time.frameCount; } return false; } } private void Awake() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_002c: 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_0079: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Expected O, but got Unknown headless = (int)SystemInfo.graphicsDeviceType == 4; Instance = this; MapKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "OpenMap", new KeyboardShortcut((KeyCode)109, Array.Empty<KeyCode>()), "[Local] Open or close the drawing canvas."); SurveyLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Drawing", "SurveyLifetimeSeconds", 120f, new ConfigDescription("[Local] How long your personal survey guides last.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 1800f), Array.Empty<object>())); PencilPixels = ((BaseUnityPlugin)this).Config.Bind<float>("Drawing", "PencilWidthPixels", 2.5f, new ConfigDescription("[Local] Width of new pencil and annotation strokes. Everyone sees the resulting ink at the same size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 16f), Array.Empty<object>())); EraserPixels = ((BaseUnityPlugin)this).Config.Bind<float>("Drawing", "EraserRadiusPixels", 14f, new ConfigDescription("[Local] Size of your eraser. Shared-map erasing is visible to everyone.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 100f), Array.Empty<object>())); AnnotationLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Drawing", "AnnotationLifetimeSeconds", 120f, new ConfigDescription("[Server-controlled] How long annotations last. Shared maps use the host or server's value for everyone; your value applies only when hosting or using a personal map.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 1800f), Array.Empty<object>())); BrushOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("Drawing", "BrushIndicatorOpacity", 0.2f, new ConfigDescription("[Local] Opacity of your brush indicator.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); ShowMyLocation = ((BaseUnityPlugin)this).Config.Bind<bool>("Map", "ShowMyLocation", false, "[Local] Show your current position and camera heading on the drawing canvas."); PersonalMapOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Map", "PersonalMapOnly", false, "[Local] Use a personal map immediately, without connecting to the host's shared map."); Shared = new MapSession(this); harmony = new Harmony("com.nopetrides.valheim.hand-drawn-map"); harmony.PatchAll(typeof(MapPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hand Drawn Map 0.4.1 loaded."); } private void Update() { Shared.Tick(); if (!headless) { Poll(); } } internal void Poll() { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) if (lastPoll == Time.frameCount) { return; } lastPoll = Time.frameCount; Shared.Tick(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || (Object)(object)Minimap.instance == (Object)null) { ReleaseWorld(); return; } long worldUID = ZNet.instance.GetWorldUID(); long playerID = localPlayer.GetPlayerID(); if (worldUID == 0L || playerID == 0L) { return; } string text = Path.Combine(Paths.ConfigPath, "com.nopetrides.valheim.hand-drawn-map", worldUID + "_" + playerID + ".view.chart"); if (text != savePath) { LoadWorld(text); } if (IsOpen && (!Application.isFocused || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || ((Character)localPlayer).InCutscene() || OtherUiOpen())) { CloseMap(); } if (ShortcutDown(MapKey.Value) && !OtherUiOpen()) { consumedFrame = Time.frameCount; if (IsOpen) { CloseMap(); } else if (CanUseWorldInput(localPlayer)) { OpenMap(); } } bool flag = SurveyTool.IsEquipped(localPlayer) && Input.GetMouseButtonDown(1); if (!IsOpen && flag && CanUseWorldInput(localPlayer)) { AddSurvey(localPlayer); } if (IsOpen) { Window.Tick(); } if (Guides.RemoveAll((SurveyGuide guide) => guide.Expires <= Time.unscaledTime) > 0) { Window?.Invalidate(); } if (Dirty && Time.unscaledTime - lastSave > 5f && (Window == null || !Window.InGesture)) { Save(); } } private static bool ShortcutDown(KeyboardShortcut shortcut) { //IL_0002: 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_0029: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { if (!Input.GetKey(modifier)) { return false; } } return true; } private static bool CanUseWorldInput(Player player) { if (Application.isFocused && !OtherUiOpen() && !Minimap.IsOpen() && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Character)player).InCutscene() && !((Character)player).InAttack()) { return !((Character)player).InDodge(); } return false; } private static bool OtherUiOpen() { if (!InventoryGui.IsVisible() && !Menu.IsVisible() && !Console.IsVisible() && !TextInput.IsVisible() && !StoreGui.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !ZInput.VirtualKeyboardOpen) { return UnifiedPopup.IsVisible(); } return true; } private void LoadWorld(string path) { ReleaseWorld(); savePath = path; saveBlocked = false; try { bool num = File.Exists(path); string text = path.Replace(".view.chart", ".chart"); ChartDocument chartDocument = ChartStore.Load(num ? path : text); Document = new ChartDocument { Center = chartDocument.Center, Zoom = chartDocument.Zoom }; if (!num) { Document.Zoom = Minimap.instance.LargeZoom; } } catch (Exception ex) { saveBlocked = true; Document = new ChartDocument(); ((BaseUnityPlugin)this).Logger.LogError((object)("Chart could not be loaded; saving disabled to preserve the file: " + ex.Message)); } Window = new CanvasWindow(this, readOnly: false); Shared.Bind(Document, delegate { Window?.Invalidate(); }); lastSave = Time.unscaledTime; } private void OpenMap() { //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) previousMode = Minimap.instance.m_mode; Minimap.instance.SetMapMode((MapMode)0); Window.SetOpen(open: true); ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); } internal void CloseMap() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (IsOpen) { Window.SetOpen(open: false); blockThroughFrame = Time.frameCount + 2; consumedFrame = Time.frameCount; if ((Object)(object)Minimap.instance != (Object)null) { Minimap.instance.SetMapMode((MapMode)((!Game.m_noMap) ? ((int)previousMode) : 0)); } Save(); } } private void AddSurvey(Player player) { //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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_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_007a: 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_0091: 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) if ((Object)(object)GameCamera.instance == (Object)null) { return; } Vector3 forward = ((Component)GameCamera.instance).transform.forward; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(forward.x, forward.z); if (!(((Vector2)(ref val)).sqrMagnitude < 0.001f)) { ((Vector2)(ref val)).Normalize(); Vector3 position = ((Component)player).transform.position; if (Guides.Count >= 32) { Guides.RemoveAt(0); } Guides.Add(new SurveyGuide { Origin = new ChartPoint(position.x, position.z), Direction = new ChartPoint(val.x, val.y), Created = Time.unscaledTime, Expires = Time.unscaledTime + SurveyLifetime.Value }); Window.Invalidate(); if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)1, "You sketch a guide line across your map.", 0, (Sprite)null, false, true); } } } internal void LogToolError(Exception exception) { ((BaseUnityPlugin)this).Logger.LogError((object)("Survey Compass registration failed: " + exception)); } internal void LogToolWarning(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); } internal void LogMapInfo(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); } internal void Save() { if (!Dirty || savePath == null || saveBlocked) { return; } lastSave = Time.unscaledTime; try { ChartStore.Save(savePath, new ChartDocument { Center = Document.Center, Zoom = Document.Zoom }); Dirty = false; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Chart save failed: " + ex.Message)); } } private void ReleaseWorld() { CloseMap(); Save(); Shared?.Unbind(); Window?.Dispose(); Window = null; Document = null; savePath = null; Guides.Clear(); Dirty = false; } private void OnApplicationFocus(bool focused) { if (!focused) { CloseMap(); } } private void OnApplicationQuit() { Window?.FinishSharedGesture(); Save(); Shared?.Flush(); } private void OnDestroy() { ReleaseWorld(); Shared?.Dispose(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } } internal sealed class SurveyGuide { public ChartPoint Origin; public ChartPoint Direction; public float Created; public float Expires; } internal sealed class MapSession : IDisposable { private enum Message : byte { Hello, Welcome, Edit, Commit, Reject, Start, Part, Finish, Resync, Ping, Pong } private sealed class Peer { public ZNetPeer Network; public Guid Session; public long Actor; public bool Welcomed; public readonly MapEditorGuard Guard = new MapEditorGuard(); public float LastSnapshot = -100f; public readonly Dictionary<Guid, string> Rejected = new Dictionary<Guid, string>(); } private sealed class Transfer { public Peer Peer; public Guid Id = Guid.NewGuid(); public byte[] Bytes; public byte[] Hash; public int Offset; public long Revision; public bool Started; } private sealed class Download { public Guid Id; public byte[] Bytes; public byte[] Hash; public int Offset; public long Revision; } private const string RpcName = "NPR_SharedMap_V1"; private readonly MapPlugin plugin; private readonly Dictionary<ZRpc, Peer> peers = new Dictionary<ZRpc, Peer>(); private readonly List<MapEdit> outgoing = new List<MapEdit>(); private readonly Dictionary<Guid, MapEdit> inflight = new Dictionary<Guid, MapEdit>(); private readonly List<MapEdit> received = new List<MapEdit>(); private readonly List<Transfer> transfers = new List<Transfer>(); private readonly List<MapEdit> waitingCommits = new List<MapEdit>(); private MapReplica replica = new MapReplica(); private SharedMap owner; private SharedMap published; private MapJournal journal; private ChartDocument view; private Action changed; private long ownerWorld; private long clientWorld; private long sequence; private MapEditorGuard localGuard = new MapEditorGuard(); private Guid clientSession; private bool ownerFailed; private string ownerError; private float helloAt; private float nextSend; private float nextPing; private float nextFade; private float syncStarted; private int lastTick = -1; private float clientStarted; private double clockOffset; private Download download; private bool syncing; private bool personal; private bool personalOnly; private long character; internal readonly List<TemporaryInk> Annotations = new List<TemporaryInk>(); internal bool CanEdit { get { if (replica.Ready && !syncing && !ownerFailed && replica.Pending.Count < 256) { return inflight.Count < 256; } return false; } } internal string Status { get { object obj = ownerError; if (obj == null) { obj = (ownerFailed ? "Map is read-only" : null); if (obj == null) { obj = replica.Error; if (obj == null) { if (!syncing) { if (replica.Ready) { if (replica.Pending.Count <= 0) { if (!personal) { return "Shared map"; } return "Personal map"; } return "Pending edits: " + replica.Pending.Count; } return "Connecting to map owner..."; } obj = "Downloading shared map..."; } } } return (string)obj; } } internal double Now => UtcNow + clockOffset; private static double UtcNow => (double)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() / 1000.0; internal MapSession(MapPlugin plugin) { this.plugin = plugin; } internal void Register(ZNetPeer network) { if (!peers.ContainsKey(network.m_rpc)) { Peer peer = new Peer { Network = network }; peers.Add(network.m_rpc, peer); network.m_rpc.Register<ZPackage>("NPR_SharedMap_V1", (Action<ZRpc, ZPackage>)delegate(ZRpc rpc, ZPackage package) { Receive(peer, package); }); } } internal void Bind(ChartDocument document, Action onChanged) { view = document; changed = onChanged; Refresh(); } internal void Unbind() { view = null; changed = null; Annotations.Clear(); } internal void Tick() { if (lastTick == Time.frameCount) { return; } lastTick = Time.frameCount; ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { StopOwner(); ResetClient(); peers.Clear(); } else if (!instance.IsServer() && instance.GetServerPeer() == null) { if (replica.Ready) { SaveRecovery(); replica.Ready = false; Refresh(); } } else { if (instance.GetWorld() == null) { return; } long world = instance.GetWorldUID(); if (world == 0L) { return; } long num = (((Object)(object)Player.m_localPlayer == (Object)null) ? 0 : Player.m_localPlayer.GetPlayerID()); if (clientWorld != 0L && (clientWorld != world || character != num || personalOnly != plugin.PersonalMapOnly.Value)) { plugin.Window?.FinishSharedGesture(); Flush(); StopOwner(); ResetClient(); } if (owner != null && ownerWorld != world) { StopOwner(); } bool flag = !instance.IsDedicated() && !plugin.Headless && num != 0; if (plugin.PersonalMapOnly.Value) { if (flag && !personal) { StartPersonal(world); } if (!flag) { StopOwner(); return; } } if (!personal && !plugin.PersonalMapOnly.Value && instance.IsServer() && owner == null && (instance.IsDedicated() || plugin.Headless || flag)) { StartOwner(world); } if (flag && (clientWorld != world || (owner != null && !replica.Ready))) { StartClient(world); } Peer[] array = peers.Values.ToArray(); foreach (Peer peer in array) { if (!instance.GetPeers().Contains(peer.Network)) { peers.Remove(peer.Network.m_rpc); transfers.RemoveAll((Transfer t) => t.Peer == peer); } } if (journal != null) { if (journal.Failure != null && !ownerFailed) { ownerFailed = true; ownerError = "Shared map storage failed; editing paused"; plugin.LogToolError(journal.Failure); MapEdit[] array2 = waitingCommits.ToArray(); foreach (MapEdit mapEdit in array2) { RejectAll(mapEdit.Id, ownerError); } waitingCommits.Clear(); } if (!ownerFailed) { while (waitingCommits.Count > 0 && waitingCommits[0].Revision <= journal.Durable) { MapEdit edit = waitingCommits[0]; waitingCommits.RemoveAt(0); published.Apply(edit); if (clientWorld == ownerWorld && replica.Ready) { Accept(edit); } foreach (Peer item in peers.Values.Where((Peer p) => !personal && p.Welcomed)) { Send(item, Message.Commit, delegate(BinaryWriter writer) { MapWire.WriteEdit(writer, edit); }); } } } } if (owner != null && !personal) { PumpTransfers(); } if (!personal && !instance.IsServer() && clientWorld == world) { ZNetPeer serverPeer = instance.GetServerPeer(); if (serverPeer != null && serverPeer.m_uid != 0L && !replica.Ready && !syncing && Time.unscaledTime - helloAt > 2f) { helloAt = Time.unscaledTime; if (peers.TryGetValue(serverPeer.m_rpc, out var value)) { Send(value, Message.Hello, delegate(BinaryWriter writer) { writer.Write("0.4.1"); writer.Write(world); }); } } if (serverPeer == null && replica.Ready) { SaveRecovery(); replica.Ready = false; } if (serverPeer != null && clientSession == Guid.Empty && Time.unscaledTime - clientStarted > 10f) { StartPersonal(world); plugin.LogMapInfo("No shared map response; using a personal map for this session."); } if (!personal && Time.unscaledTime >= nextSend && serverPeer != null && clientSession != Guid.Empty && !syncing) { nextSend = Time.unscaledTime + 0.05f; if (peers.TryGetValue(serverPeer.m_rpc, out var value2)) { MapEdit[] array2 = outgoing.ToArray(); foreach (MapEdit edit2 in array2) { Send(value2, Message.Edit, delegate(BinaryWriter writer) { writer.Write(clientSession.ToByteArray()); MapWire.WriteEdit(writer, edit2); }); outgoing.Remove(edit2); } } } if (!personal && replica.Ready && Time.unscaledTime > nextPing && serverPeer != null && peers.TryGetValue(serverPeer.m_rpc, out var value3)) { nextPing = Time.unscaledTime + 3f; Send(value3, Message.Ping, delegate(BinaryWriter writer) { writer.Write(replica.Confirmed.Revision); }); } } if (syncing && Time.unscaledTime - syncStarted > 30f) { syncing = false; download = null; replica.Error = "Map sync timed out; press Resync"; replica.Ready = false; } if (replica.Ready && Annotations.Count > 0 && Time.unscaledTime > nextFade) { nextFade = Time.unscaledTime + 0.05f; Refresh(); } } } private void StartOwner(long world) { ownerWorld = world; string path = (personal ? Path.Combine(Paths.ConfigPath, "com.nopetrides.valheim.hand-drawn-map", "personal", world + "_" + Player.m_localPlayer.GetPlayerID() + ".journal") : Path.Combine(Paths.ConfigPath, "com.nopetrides.valheim.hand-drawn-map", "shared", world + ".journal")); try { bool num = !File.Exists(path); journal = new MapJournal(path, world); owner = journal.Loaded; ownerFailed = journal.Corrupt; if (ownerFailed) { ownerError = "Map save is damaged; recovered drawings are read-only"; } if (num && !ZNet.instance.IsDedicated() && !plugin.Headless) { ImportPersonalMap(world); } published = owner.Fork(); } catch (Exception exception) { owner = new SharedMap(); ownerFailed = true; published = new SharedMap(); ownerError = "Map could not be loaded; editing paused"; plugin.LogToolError(exception); } } private void ImportPersonalMap(long world) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } string path = Path.Combine(Paths.ConfigPath, "com.nopetrides.valheim.hand-drawn-map", world + "_" + localPlayer.GetPlayerID() + ".chart"); if (!File.Exists(path)) { return; } ChartDocument chartDocument; try { chartDocument = ChartStore.Load(path); } catch (Exception exception) { plugin.LogToolError(exception); return; } foreach (ChartStroke stroke in chartDocument.Strokes) { Guid gesture = Guid.NewGuid(); for (int i = 0; i < stroke.Points.Count; i += 127) { MapEdit request = new MapEdit { Kind = MapEditKind.Draw, Gesture = gesture, Width = stroke.Width, Points = stroke.Points.Skip(i).Take(128).ToArray() }; if (!owner.Prepare(request, 0L, UtcNow, 120f, out var edit, out var error)) { throw new InvalidDataException(error); } owner.Apply(edit); journal.Append(owner.ForDisk(edit)); } MapEdit request2 = new MapEdit { Kind = MapEditKind.End, Gesture = gesture }; if (owner.Prepare(request2, 0L, UtcNow, 120f, out var edit2, out var _)) { owner.Apply(edit2); journal.Append(edit2); } } journal.Flush(); plugin.LogMapInfo("Imported existing personal ink into the new " + (personal ? "personal" : "shared") + " map; original file retained."); } private void StartPersonal(long world) { plugin.Window?.FinishSharedGesture(); Flush(); StopOwner(); ResetClient(); personal = true; StartOwner(world); StartClient(world); } private void StartClient(long world) { bool flag = personal; ResetClient(); clientWorld = world; personal = flag; personalOnly = plugin.PersonalMapOnly.Value; character = (((Object)(object)Player.m_localPlayer == (Object)null) ? 0 : Player.m_localPlayer.GetPlayerID()); localGuard = new MapEditorGuard(); clientStarted = Time.unscaledTime; if ((personal || ZNet.instance.IsServer()) && owner != null) { clientSession = Guid.NewGuid(); replica.Actor = NewActor(); replica.AnnotationLifetime = plugin.AnnotationLifetime.Value; replica.Snapshot(owner.Fork(), UtcNow); Refresh(); } else { helloAt = -100f; } } internal bool Draw(Guid gesture, ChartPoint[] points, float width, bool temporary) { return Submit(new MapEdit { Gesture = gesture, Kind = ((!temporary) ? MapEditKind.Draw : MapEditKind.Annotate), Points = points, Width = width }); } internal bool Erase(Guid gesture, ChartPoint from, ChartPoint to, float radius) { if (!CanEdit) { return false; } Guid[] array = replica.Predicted.Targets(from, to, radius, Now); bool flag = false; for (int i = 0; i < array.Length; i += 1024) { flag |= Submit(new MapEdit { Gesture = gesture, Kind = MapEditKind.Erase, Points = new ChartPoint[2] { from, to }, Width = radius, Targets = array.Skip(i).Take(1024).ToArray() }); } return flag; } internal void End(Guid gesture) { Submit(new MapEdit { Kind = MapEditKind.End, Gesture = gesture }); } internal bool Undo() { return Submit(new MapEdit { Kind = MapEditKind.Undo, UndoGesture = replica.Predicted.LastUndo(replica.Actor) }); } internal void ClearAnnotations() { Submit(new MapEdit { Kind = MapEditKind.ClearAnnotations }); } private bool Submit(MapEdit edit) { if (!CanEdit) { return false; } edit.Sequence = sequence + 1; if (!replica.Propose(edit, Now)) { Refresh(); return false; } sequence++; Refresh(); if (personal || ZNet.instance.IsServer()) { ProcessEdit(null, edit); } else { outgoing.Add(edit); inflight.Add(edit.Id, edit); } return true; } private void ProcessEdit(Peer peer, MapEdit edit) { long num = peer?.Actor ?? replica.Actor; if (owner == null || ownerFailed) { Reject(peer, edit.Id