using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Runtime.Versioning;
using System.Text;
using System.Xml;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("0.1.7.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")]
[assembly: AssemblyVersion("0.1.7.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 CustomPaintings
{
internal sealed class MenuButton : GoPointerButton
{
private static readonly FieldInfo OutlineField = AccessTools.Field(typeof(GoPointerButton), "outline");
internal Action Clicked;
public override void Start()
{
Component component = ((Component)this).GetComponent("Outline");
if ((Object)(object)component == (Object)null)
{
((GoPointerButton)this).Start();
}
else
{
OutlineField?.SetValue(this, component);
}
}
public override void OnActivate()
{
if (!base.unclickable)
{
Clicked?.Invoke();
}
}
}
internal sealed class PaintingPicture : MonoBehaviour
{
private static readonly HashSet<string> reportedMeshes = new HashSet<string>();
private ShipItem item;
private SaveablePrefab saveable;
private Renderer canvasRenderer;
private Material[] originals;
private Material custom;
private CanvasShape canvas;
private bool knownCanvas;
private Texture2D picture;
private float pictureAspect;
private MeshRenderer overlay;
private Material overlayMaterial;
private bool failureReported;
public string Path { get; private set; }
public FitMode Mode { get; private set; }
public string Background { get; private set; } = "#000000";
public bool CanChoose
{
get
{
if ((Object)(object)item != (Object)null && item.sold && (Object)(object)saveable != (Object)null)
{
return saveable.instanceId != 0;
}
return false;
}
}
public static bool IsPainting(ShipItem item)
{
if ((Object)(object)item != (Object)null && ((object)item).GetType() == typeof(ShipItem) && item.name == "painting" && (Object)(object)((Component)item).GetComponent<Renderer>() != (Object)null)
{
return ((Component)item).GetComponent<Renderer>().sharedMaterials.Length >= 1;
}
return false;
}
public void Init(ShipItem shipItem)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
item = shipItem;
saveable = ((Component)item).GetComponent<SaveablePrefab>();
canvasRenderer = ((Component)item).GetComponent<Renderer>();
originals = canvasRenderer.sharedMaterials;
MeshFilter component = ((Component)item).GetComponent<MeshFilter>();
Mesh val = ((component != null) ? component.sharedMesh : null);
string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : "(no mesh)");
knownCanvas = PictureFit.TryGetCanvas(text, out canvas);
if (!knownCanvas && (Object)(object)val != (Object)null)
{
Bounds bounds = val.bounds;
if (((Bounds)(ref bounds)).size.y > 0f)
{
CanvasShape canvasShape = default(CanvasShape);
bounds = val.bounds;
canvasShape.Width = ((Bounds)(ref bounds)).size.x;
bounds = val.bounds;
canvasShape.Height = ((Bounds)(ref bounds)).size.y;
canvas = canvasShape;
}
}
if (reportedMeshes.Add(text))
{
Plugin.Log.LogInfo((object)(knownCanvas ? $"Frame {text}: canvas {canvas.Width:0.000} x {canvas.Height:0.000}, aspect {canvas.Aspect:0.000}." : ("Frame " + text + " is not a known painting frame. Its shape is estimated from its outline, and Fit shows as Fill.")));
}
if ((Object)(object)saveable != (Object)null && saveable.instanceId != 0 && Plugin.Store.TryGet(saveable.instanceId, saveable.prefabIndex, out var record))
{
Mode = record.FitMode;
Background = record.BackgroundColor;
Show(record.Path);
}
}
public void Choose(string path, FitMode mode, string background)
{
if (CanChoose)
{
Mode = mode;
Background = background;
Plugin.Store.Set(saveable.instanceId, saveable.prefabIndex, path, mode, background);
failureReported = false;
if (path == Path && (Object)(object)picture == (Object)null)
{
Show(null, restore: false);
}
if (path == Path)
{
Apply();
}
else
{
Show(path);
}
}
}
public void SetFit(FitMode mode, string background)
{
if (Path != null)
{
Choose(Path, mode, background);
}
}
public void ChooseOriginal()
{
if ((Object)(object)saveable != (Object)null)
{
Plugin.Store.Remove(saveable.instanceId);
}
Show(null);
}
private void Show(string path, bool restore = true)
{
if (path == Path)
{
return;
}
PictureTextures.Instance?.Release(Path, this);
Path = path;
picture = null;
if (path == null)
{
if (restore)
{
RestoreOriginal();
}
}
else
{
PictureTextures.Instance?.Acquire(path, this);
}
}
public void OnPictureReady(Texture2D texture, float aspect)
{
picture = texture;
pictureAspect = aspect;
Apply();
}
private void Apply()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Expected O, but got Unknown
//IL_00b1: 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_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
//IL_0216: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)canvasRenderer == (Object)null || (Object)(object)picture == (Object)null)
{
return;
}
if ((Object)(object)custom == (Object)null)
{
custom = new Material(originals[0])
{
name = ((Object)originals[0]).name + " (custom picture)"
};
}
FitMode num = ((Mode != FitMode.Fit || knownCanvas) ? Mode : FitMode.Fill);
bool flag = num == FitMode.Fit;
if (custom.HasProperty("_Color"))
{
if (flag)
{
PictureFit.ParseColor(Background, out var r, out var g, out var b);
custom.color = new Color(r, g, b, 1f);
}
else
{
custom.color = (originals[0].HasProperty("_Color") ? originals[0].color : Color.white);
}
}
custom.mainTexture = (Texture)(object)(flag ? Texture2D.whiteTexture : picture);
PictureFit.Crop(num, pictureAspect, canvas.Aspect, out var scaleX, out var scaleY, out var offsetX, out var offsetY);
custom.mainTextureScale = new Vector2(scaleX, scaleY);
custom.mainTextureOffset = new Vector2(offsetX, offsetY);
Material[] array = (Material[])originals.Clone();
array[0] = custom;
canvasRenderer.sharedMaterials = array;
if (flag)
{
EnsureOverlay();
overlayMaterial.mainTexture = (Texture)(object)picture;
PictureFit.FitSize(pictureAspect, canvas.Aspect, out var widthFraction, out var heightFraction);
((Component)overlay).transform.localPosition = new Vector3(canvas.CenterX, canvas.CenterY, canvas.Z - 0.003f);
((Component)overlay).transform.localScale = new Vector3(canvas.Width * widthFraction, canvas.Height * heightFraction, 1f);
((Renderer)overlay).enabled = true;
}
else if ((Object)(object)overlay != (Object)null)
{
((Renderer)overlay).enabled = false;
}
}
private void EnsureOverlay()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected O, but got Unknown
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Expected O, but got Unknown
//IL_00e0: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)overlay != (Object)null)
{
return;
}
GameObject val = new GameObject("Custom Paintings picture");
val.layer = ((Component)this).gameObject.layer;
val.transform.SetParent(((Component)this).transform, false);
val.AddComponent<MeshFilter>().sharedMesh = Quad.Mesh;
overlay = val.AddComponent<MeshRenderer>();
((Renderer)overlay).shadowCastingMode = (ShadowCastingMode)0;
overlayMaterial = new Material(originals[0])
{
name = ((Object)originals[0]).name + " (custom picture overlay)"
};
if (overlayMaterial.HasProperty("_Color"))
{
overlayMaterial.color = (originals[0].HasProperty("_Color") ? originals[0].color : Color.white);
}
overlayMaterial.mainTextureScale = Vector2.one;
overlayMaterial.mainTextureOffset = Vector2.zero;
((Renderer)overlay).sharedMaterial = overlayMaterial;
LODGroup component = ((Component)this).GetComponent<LODGroup>();
if ((Object)(object)component != (Object)null)
{
LOD[] lODs = component.GetLODs();
if (lODs.Length != 0)
{
List<Renderer> list = new List<Renderer>((IEnumerable<Renderer>)(((object)lODs[0].renderers) ?? ((object)new Renderer[0]))) { (Renderer)(object)overlay };
lODs[0].renderers = list.ToArray();
component.SetLODs(lODs);
}
}
}
public void OnPictureFailed()
{
picture = null;
RestoreOriginal();
if (!failureReported)
{
failureReported = true;
Plugin.Log.LogWarning((object)("A painting keeps its original art because its picture could not be loaded: " + Path));
}
}
private void RestoreOriginal()
{
if ((Object)(object)canvasRenderer != (Object)null && originals != null)
{
canvasRenderer.sharedMaterials = originals;
}
if ((Object)(object)overlay != (Object)null)
{
((Renderer)overlay).enabled = false;
}
if ((Object)(object)custom != (Object)null)
{
Object.Destroy((Object)(object)custom);
}
custom = null;
}
private void OnDestroy()
{
PictureTextures.Instance?.Release(Path, this);
if ((Object)(object)custom != (Object)null)
{
Object.Destroy((Object)(object)custom);
}
if ((Object)(object)overlayMaterial != (Object)null)
{
Object.Destroy((Object)(object)overlayMaterial);
}
}
}
internal static class Quad
{
private static Mesh mesh;
public static Mesh Mesh
{
get
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Expected O, but got Unknown
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//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_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_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_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: 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_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_018d: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)mesh != (Object)null)
{
return mesh;
}
mesh = new Mesh
{
name = "Custom Paintings quad"
};
mesh.vertices = (Vector3[])(object)new Vector3[4]
{
new Vector3(-0.5f, -0.5f, 0f),
new Vector3(0.5f, -0.5f, 0f),
new Vector3(0.5f, 0.5f, 0f),
new Vector3(-0.5f, 0.5f, 0f)
};
mesh.uv = (Vector2[])(object)new Vector2[4]
{
new Vector2(0f, 0f),
new Vector2(1f, 0f),
new Vector2(1f, 1f),
new Vector2(0f, 1f)
};
mesh.normals = (Vector3[])(object)new Vector3[4]
{
Vector3.back,
Vector3.back,
Vector3.back,
Vector3.back
};
mesh.tangents = (Vector4[])(object)new Vector4[4]
{
new Vector4(1f, 0f, 0f, -1f),
new Vector4(1f, 0f, 0f, -1f),
new Vector4(1f, 0f, 0f, -1f),
new Vector4(1f, 0f, 0f, -1f)
};
mesh.triangles = new int[6] { 0, 3, 2, 0, 2, 1 };
mesh.RecalculateBounds();
return mesh;
}
}
}
internal enum FitMode
{
Fill,
Fit,
Stretch
}
internal struct CanvasShape
{
public float Width;
public float Height;
public float CenterX;
public float CenterY;
public float Z;
public float Aspect => Width / Height;
}
internal static class PictureFit
{
private static readonly Dictionary<string, CanvasShape> Canvases = new Dictionary<string, CanvasShape>
{
{
"painting",
new CanvasShape
{
Width = 1.331f,
Height = 0.832f,
Z = -0.009f
}
},
{
"painting_square",
new CanvasShape
{
Width = 1.234f,
Height = 1.165f,
CenterX = 0.001f,
CenterY = 0.0005f,
Z = -0.01f
}
},
{
"painting_almost_square",
new CanvasShape
{
Width = 1.097f,
Height = 0.832f,
Z = -0.009f
}
},
{
"painting_wide",
new CanvasShape
{
Width = 1.531f,
Height = 0.832f,
Z = -0.009f
}
},
{
"painting_wide_wide",
new CanvasShape
{
Width = 1.871f,
Height = 0.832f,
Z = -0.009f
}
},
{
"painting_vertical",
new CanvasShape
{
Width = 1.032f,
Height = 1.331f,
Z = -0.009f
}
},
{
"painting_vertical_long",
new CanvasShape
{
Width = 1.261f,
Height = 1.837f,
Z = -0.008f
}
}
};
public static bool TryGetCanvas(string meshName, out CanvasShape canvas)
{
canvas = default(CanvasShape);
if (string.IsNullOrEmpty(meshName))
{
return false;
}
string key = (meshName.EndsWith(" Instance", StringComparison.Ordinal) ? meshName.Substring(0, meshName.Length - " Instance".Length) : meshName);
return Canvases.TryGetValue(key, out canvas);
}
public static void TargetSize(int width, int height, int maxSide, out int targetWidth, out int targetHeight)
{
if (width <= 0 || height <= 0)
{
throw new ArgumentOutOfRangeException("width");
}
long num = Math.Max(width, height);
long num2 = Math.Min(num, maxSide);
targetWidth = (int)Math.Max(4L, width * num2 / num / 4 * 4);
targetHeight = (int)Math.Max(4L, height * num2 / num / 4 * 4);
}
public static void Crop(FitMode mode, float pictureAspect, float canvasAspect, out float scaleX, out float scaleY, out float offsetX, out float offsetY)
{
scaleX = (scaleY = 1f);
offsetX = (offsetY = 0f);
if (mode == FitMode.Fill && !(pictureAspect <= 0f) && !(canvasAspect <= 0f))
{
if (pictureAspect > canvasAspect)
{
scaleX = canvasAspect / pictureAspect;
offsetX = (1f - scaleX) / 2f;
}
else
{
scaleY = pictureAspect / canvasAspect;
offsetY = (1f - scaleY) / 2f;
}
}
}
public static void FitSize(float pictureAspect, float canvasAspect, out float widthFraction, out float heightFraction)
{
widthFraction = (heightFraction = 1f);
if (!(pictureAspect <= 0f) && !(canvasAspect <= 0f))
{
if (pictureAspect > canvasAspect)
{
heightFraction = canvasAspect / pictureAspect;
}
else
{
widthFraction = pictureAspect / canvasAspect;
}
}
}
public static void ParseColor(string hex, out float r, out float g, out float b)
{
r = (g = (b = 0f));
if (hex != null && hex.Length == 7 && hex[0] == '#' && int.TryParse(hex.Substring(1), NumberStyles.HexNumber, null, out var result))
{
r = (float)((result >> 16) & 0xFF) / 255f;
g = (float)((result >> 8) & 0xFF) / 255f;
b = (float)(result & 0xFF) / 255f;
}
}
}
internal struct LibraryEntry
{
public string Path;
public bool IsFolder;
public string Name
{
get
{
if (!IsFolder)
{
return System.IO.Path.GetFileNameWithoutExtension(Path);
}
return System.IO.Path.GetFileName(Path.TrimEnd('\\', '/'));
}
}
}
internal static class PictureLibrary
{
public static List<string> ParseFolders(string setting)
{
List<string> list = new List<string>();
if (string.IsNullOrEmpty(setting))
{
return list;
}
string[] array = setting.Split(new char[1] { '|' });
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim().Trim(new char[1] { '"' }).Trim();
if (text.Length > 0 && !list.Contains(text))
{
list.Add(text);
}
}
return list;
}
public static bool IsPicture(string path)
{
string extension = Path.GetExtension(path);
if (!extension.Equals(".png", StringComparison.OrdinalIgnoreCase) && !extension.Equals(".jpg", StringComparison.OrdinalIgnoreCase))
{
return extension.Equals(".jpeg", StringComparison.OrdinalIgnoreCase);
}
return true;
}
public static List<LibraryEntry> List(string folder, out string problem)
{
problem = null;
List<LibraryEntry> list = new List<LibraryEntry>();
if (!Directory.Exists(folder))
{
problem = "Folder not found: " + folder;
return list;
}
try
{
List<string> list2 = new List<string>(Directory.GetDirectories(folder));
List<string> list3 = new List<string>();
string[] files = Directory.GetFiles(folder);
foreach (string text in files)
{
if (IsPicture(text))
{
list3.Add(text);
}
}
list2.Sort(NaturalCompare);
list3.Sort(NaturalCompare);
foreach (string item in list2)
{
list.Add(new LibraryEntry
{
Path = item,
IsFolder = true
});
}
foreach (string item2 in list3)
{
list.Add(new LibraryEntry
{
Path = item2
});
}
}
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException)
{
problem = "This folder could not be read: " + ex.Message;
}
return list;
}
public static List<LibraryEntry> Filter(List<LibraryEntry> entries, string query)
{
query = query?.Trim();
if (string.IsNullOrEmpty(query))
{
return entries;
}
List<LibraryEntry> list = new List<LibraryEntry>();
foreach (LibraryEntry entry in entries)
{
if (entry.Name.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0)
{
list.Add(entry);
}
}
return list;
}
public static int PageCount(int count, int perPage)
{
return Math.Max(1, (count + perPage - 1) / perPage);
}
public static int NaturalCompare(string a, string b)
{
a = Path.GetFileName((a ?? "").TrimEnd('\\', '/'));
b = Path.GetFileName((b ?? "").TrimEnd('\\', '/'));
int i = 0;
int j = 0;
while (i < a.Length && j < b.Length)
{
if (char.IsDigit(a[i]) && char.IsDigit(b[j]))
{
int num = i;
int num2 = j;
for (; i < a.Length && char.IsDigit(a[i]); i++)
{
}
for (; j < b.Length && char.IsDigit(b[j]); j++)
{
}
string text = a.Substring(num, i - num).TrimStart(new char[1] { '0' });
string text2 = b.Substring(num2, j - num2).TrimStart(new char[1] { '0' });
if (text.Length != text2.Length)
{
return text.Length.CompareTo(text2.Length);
}
int num3 = string.CompareOrdinal(text, text2);
if (num3 != 0)
{
return num3;
}
}
else
{
int num4 = char.ToUpperInvariant(a[i]).CompareTo(char.ToUpperInvariant(b[j]));
if (num4 != 0)
{
return num4;
}
i++;
j++;
}
}
int num5 = (a.Length - i).CompareTo(b.Length - j);
if (num5 == 0)
{
return string.Compare(a, b, StringComparison.OrdinalIgnoreCase);
}
return num5;
}
}
internal sealed class PicturePicker : MonoBehaviour
{
private sealed class Cell
{
public MenuButton Folder;
public MenuButton Thumb;
public Material ThumbMaterial;
public TextMesh Caption;
public TextMesh Status;
public LibraryEntry Entry;
public bool HasEntry;
public bool WaitingForThumbnail;
}
private const float MaxButtonText = 0.0125f;
private const int Columns = 5;
private const int Rows = 4;
private const int PerPage = 20;
private const float CellPitch = 1f;
private const float ThumbWidth = 0.88f;
private const float ThumbHeight = 0.44f;
private const float PaperWidth = 6.2f;
private const float PaperHeight = 4.4f;
private const float PaperScreenHeight = 1.07f;
private const float PaperScreenWidth = 1.05f;
private const float PageDistance = 2.5f;
private static readonly float[] RowY = new float[4] { 0.86f, 0.24f, -0.38f, -1f };
private static readonly Color Ink = new Color(0.06f, 0.035f, 0.02f, 1f);
private static readonly Color MutedInk = new Color(0.27f, 0.21f, 0.17f, 1f);
private static readonly Color MarkInk = new Color(0.45f, 0.08f, 0.03f, 1f);
private static readonly Color Placeholder = new Color(0.85f, 0.8f, 0.7f, 1f);
private static readonly FieldInfo ChoiceUiField = AccessTools.Field(typeof(StartMenu), "chooseIslandUI");
private static readonly string[] Swatches = new string[8] { "#000000", "#FFFFFF", "#E8DCC0", "#7A7A7A", "#2B2B2B", "#1F2F4A", "#5A1E1E", "#3E2A1A" };
private GameObject holder;
private Transform root;
private GameObject buttonTemplate;
private TextMesh titleTemplate;
private TextMesh fontTemplate;
private Camera uiCamera;
private Shader flatShader;
private Material flatFallback;
private readonly List<Material> ownedMaterials = new List<Material>();
private readonly Dictionary<MenuButton, float> buttonWidths = new Dictionary<MenuButton, float>();
private readonly Cell[] cells = new Cell[20];
private TextMesh pathText;
private TextMesh pageText;
private TextMesh messageText;
private TextMesh borderLabel;
private MenuButton backButton;
private MenuButton searchButton;
private MenuButton clearButton;
private MenuButton previousButton;
private MenuButton nextButton;
private MenuButton[] modeButtons;
private MenuButton[] swatchButtons;
private PaintingPicture target;
private List<string> roots = new List<string>();
private int rootIndex = -1;
private string folder;
private List<LibraryEntry> listing = new List<LibraryEntry>();
private List<LibraryEntry> shown = new List<LibraryEntry>();
private string problem;
private string query = "";
private bool searchFocused;
private int page;
private FitMode mode;
private string background;
private readonly List<string> wanted = new List<string>();
internal static PicturePicker Instance { get; private set; }
public bool IsOpen => ((Behaviour)this).enabled;
public bool SearchFocused
{
get
{
if (((Behaviour)this).enabled)
{
return searchFocused;
}
return false;
}
}
private bool AtTop => rootIndex < 0;
private void Awake()
{
Instance = this;
((Behaviour)this).enabled = false;
}
public void Open(PaintingPicture painting)
{
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: 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_0196: Unknown result type (might be due to invalid IL or missing references)
//IL_0233: Unknown result type (might be due to invalid IL or missing references)
//IL_023a: Unknown result type (might be due to invalid IL or missing references)
if (EnsureBuilt())
{
target = painting;
mode = painting.Mode;
background = painting.Background;
List<string> a = PictureLibrary.ParseFolders(Plugin.PictureFolders);
if (!SameFolders(a, roots))
{
roots = a;
rootIndex = -1;
folder = null;
page = 0;
}
if (rootIndex >= 0 && !Inside(folder, roots[rootIndex]))
{
folder = roots[rootIndex];
}
query = "";
searchFocused = false;
LoadListing(keepPage: true);
bool flag = Settings.VRLookEnabled && (Object)(object)Refs.observerMirror != (Object)null;
Transform val = (flag ? ((Component)Refs.observerMirror).transform : (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform : null));
holder.transform.SetParent(val, false);
holder.transform.localPosition = (flag ? new Vector3(0f, 0f, 1.3f) : new Vector3(0f, -1.1f, 1.3f));
holder.transform.localRotation = Quaternion.identity;
holder.transform.localScale = Vector3.one * 0.5f;
root.localPosition = new Vector3(0f, flag ? 0f : 2.2f, 2.4f);
Camera val2 = (((Object)(object)uiCamera != (Object)null) ? uiCamera : Camera.main);
float num = (((Object)(object)val2 != (Object)null) ? val2.fieldOfView : 60f);
float num2 = (((Object)(object)val2 != (Object)null) ? val2.aspect : 1.7777778f);
float num3 = 5f * Mathf.Tan(num * 0.5f * ((float)Math.PI / 180f));
float num4 = Mathf.Min(1.07f * num3 / 2.2f, 1.05f * num3 * num2 / 3.1f);
root.localScale = Vector3.one * num4;
holder.SetActive(true);
MouseLook.ToggleMouseLookAndCursor(false);
Refs.SetPlayerControl(false);
GameState.wasInSettingsMenu = true;
((Behaviour)this).enabled = true;
Refresh();
}
}
public void Close()
{
if (((Behaviour)this).enabled)
{
((Behaviour)this).enabled = false;
target = null;
searchFocused = false;
if ((Object)(object)holder != (Object)null)
{
holder.SetActive(false);
}
PictureTextures.Instance?.ClearThumbnails();
MouseLook.ToggleMouseLookAndCursor(true);
Refs.SetPlayerControl(true);
((MonoBehaviour)this).StartCoroutine(ClearSettingsFlag());
}
}
private static IEnumerator ClearSettingsFlag()
{
yield return (object)new WaitForEndOfFrame();
GameState.wasInSettingsMenu = false;
}
public void Blur()
{
searchFocused = false;
Refresh();
}
private void Update()
{
if ((Object)(object)target == (Object)null || GameState.currentlyLoading || (Object)(object)holder == (Object)null)
{
Close();
return;
}
if (searchFocused)
{
ReadSearchInput();
}
float axis = Input.GetAxis("Mouse ScrollWheel");
if (axis > 0f)
{
ChangePage(-1);
}
else if (axis < 0f)
{
ChangePage(1);
}
Cell[] array = cells;
foreach (Cell cell in array)
{
if (cell.WaitingForThumbnail)
{
ShowThumbnail(cell);
}
}
}
private void ReadSearchInput()
{
string text = query;
bool flag = searchFocused;
string inputString = Input.inputString;
for (int i = 0; i < inputString.Length; i++)
{
char c = inputString[i];
switch (c)
{
case '\b':
if (query.Length > 0)
{
query = query.Substring(0, query.Length - 1);
}
break;
case '\n':
case '\r':
searchFocused = false;
break;
default:
if (!char.IsControl(c) && query.Length < 40)
{
query += c;
}
break;
}
}
if (Input.GetKeyDown((KeyCode)127))
{
query = "";
}
if (query != text)
{
page = 0;
Filter();
}
if (query != text || searchFocused != flag)
{
Refresh();
}
}
private void LoadListing(bool keepPage = false)
{
problem = null;
if (rootIndex < 0)
{
listing = new List<LibraryEntry>();
foreach (string root in roots)
{
listing.Add(new LibraryEntry
{
Path = root,
IsFolder = true
});
}
}
else
{
listing = PictureLibrary.List(folder, out problem);
}
if (!keepPage)
{
page = 0;
}
Filter();
}
private void Filter()
{
shown = PictureLibrary.Filter(listing, query);
page = Mathf.Clamp(page, 0, PictureLibrary.PageCount(shown.Count, 20) - 1);
}
private void Enter(LibraryEntry entry)
{
if (rootIndex < 0)
{
rootIndex = roots.IndexOf(entry.Path);
}
folder = entry.Path;
query = "";
searchFocused = false;
LoadListing();
Refresh();
}
private void Back()
{
if (rootIndex >= 0)
{
if (SamePath(folder, roots[rootIndex]))
{
rootIndex = -1;
folder = null;
}
else
{
folder = Path.GetDirectoryName(Normalize(folder));
}
query = "";
searchFocused = false;
LoadListing();
Refresh();
}
}
private static string Normalize(string path)
{
return path?.TrimEnd('\\', '/');
}
private static bool SamePath(string a, string b)
{
return string.Equals(Normalize(a), Normalize(b), StringComparison.OrdinalIgnoreCase);
}
private static bool Inside(string path, string rootPath)
{
if (path != null && Directory.Exists(path))
{
return Normalize(path).StartsWith(Normalize(rootPath), StringComparison.OrdinalIgnoreCase);
}
return false;
}
private static bool SameFolders(List<string> a, List<string> b)
{
if (a.Count != b.Count)
{
return false;
}
for (int i = 0; i < a.Count; i++)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}
private string PathLabel()
{
if (rootIndex < 0)
{
return "Picture folders";
}
string text = Normalize(roots[rootIndex]);
string text2 = Path.GetFileName(text);
if (string.IsNullOrEmpty(text2))
{
text2 = text;
}
string text3 = Normalize(folder);
string text4 = ((text3.Length > text.Length) ? text3.Substring(text.Length).Trim('\\', '/') : "");
if (text4.Length == 0)
{
return text2;
}
return text2 + " / " + string.Join(" / ", text4.Split(new char[2] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries));
}
private void ChangePage(int direction)
{
int num = Mathf.Clamp(page + direction, 0, PictureLibrary.PageCount(shown.Count, 20) - 1);
if (num != page)
{
page = num;
Refresh();
}
}
private void OnCell(int index)
{
Cell cell = cells[index];
if (!((Object)(object)target == (Object)null) && cell.HasEntry)
{
searchFocused = false;
if (cell.Entry.IsFolder)
{
Enter(cell.Entry);
return;
}
target.Choose(cell.Entry.Path, mode, background);
Close();
}
}
private void SetMode(FitMode next)
{
mode = next;
target.SetFit(mode, background);
Refresh();
}
private void SetBackground(string color)
{
background = color;
target.SetFit(mode, background);
Refresh();
}
private void Refresh()
{
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_022c: Unknown result type (might be due to invalid IL or missing references)
//IL_024e: Unknown result type (might be due to invalid IL or missing references)
//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
//IL_0467: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)holder == (Object)null || (Object)(object)target == (Object)null)
{
return;
}
pathText.text = Trim(PathLabel(), 70);
SetVisible(backButton, !AtTop);
SetText(searchButton, searchFocused ? (query + "_") : ((query.Length > 0) ? query : "Search this folder"), (searchFocused || query.Length > 0) ? Ink : MutedInk);
SetVisible(clearButton, query.Length > 0);
string text = null;
if (roots.Count == 0)
{
text = "Add picture folders to the Picture folders setting\nin the config file or Configuration Manager.";
}
else if (shown.Count == 0)
{
text = problem ?? ((query.Length > 0) ? ("Nothing here matches \"" + query + "\".") : "No folders or PNG or JPG pictures here.");
}
messageText.text = text ?? "";
wanted.Clear();
for (int i = 0; i < 20; i++)
{
int num = page * 20 + i;
Cell cell = cells[i];
cell.HasEntry = text == null && num < shown.Count;
cell.WaitingForThumbnail = false;
if (!cell.HasEntry)
{
SetVisible(cell.Folder, visible: false);
((Component)cell.Thumb).gameObject.SetActive(false);
TextMesh caption = cell.Caption;
string text2 = (cell.Status.text = "");
caption.text = text2;
continue;
}
cell.Entry = shown[num];
if (cell.Entry.IsFolder)
{
SetVisible(cell.Folder, visible: true);
((Component)cell.Thumb).gameObject.SetActive(false);
SetText(cell.Folder, Wrap(cell.Entry.Name, 13, 3), Ink);
cell.Caption.text = "folder";
cell.Caption.color = MutedInk;
cell.Status.text = "";
continue;
}
SetVisible(cell.Folder, visible: false);
cell.Caption.text = Trim(cell.Entry.Name, 22);
cell.Caption.color = (SamePath(cell.Entry.Path, target.Path) ? MarkInk : Ink);
ShowThumbnail(cell);
if (cell.WaitingForThumbnail)
{
wanted.Add(cell.Entry.Path);
}
}
PictureTextures.Instance?.WantThumbnails(wanted);
int num2 = PictureLibrary.PageCount(shown.Count, 20);
pageText.text = ((text == null && num2 > 1) ? ("Page " + (page + 1) + " of " + num2) : "");
SetVisible(previousButton, text == null && page > 0);
SetVisible(nextButton, text == null && page < num2 - 1);
for (int j = 0; j < modeButtons.Length; j++)
{
MenuButton button = modeButtons[j];
FitMode fitMode = (FitMode)j;
SetText(button, fitMode.ToString(), (j == (int)mode) ? MarkInk : Ink);
}
bool flag = mode == FitMode.Fit;
borderLabel.text = (flag ? "Border" : "");
for (int k = 0; k < swatchButtons.Length; k++)
{
((Component)swatchButtons[k]).gameObject.SetActive(flag);
float num3 = ((Swatches[k] == background) ? 0.22f : 0.17f);
((Component)swatchButtons[k]).transform.localScale = new Vector3(num3, num3, 1f);
}
}
private void ShowThumbnail(Cell cell)
{
//IL_003c: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
PictureTextures instance = PictureTextures.Instance;
Texture2D val = instance?.Thumbnail(cell.Entry.Path);
if ((Object)(object)val != (Object)null)
{
cell.ThumbMaterial.mainTexture = (Texture)(object)val;
cell.ThumbMaterial.color = Color.white;
float num = (float)((Texture)val).width / (float)((Texture)val).height;
float num2 = 0.88f;
float num3 = 0.88f / num;
if (num3 > 0.44f)
{
num3 = 0.44f;
num2 = 0.44f * num;
}
((Component)cell.Thumb).transform.localScale = new Vector3(num2, num3, 1f);
((Component)cell.Thumb).gameObject.SetActive(true);
cell.Status.text = "";
cell.WaitingForThumbnail = false;
}
else
{
bool flag = (Object)(object)instance != (Object)null && instance.ThumbnailFailed(cell.Entry.Path);
cell.ThumbMaterial.mainTexture = (Texture)(object)Texture2D.whiteTexture;
cell.ThumbMaterial.color = Placeholder;
((Component)cell.Thumb).transform.localScale = new Vector3(0.704f, 0.352f, 1f);
((Component)cell.Thumb).gameObject.SetActive(true);
cell.Status.text = (flag ? "can't read" : "loading");
cell.WaitingForThumbnail = !flag;
}
}
private static string Trim(string value, int maximum)
{
if (value.Length > maximum)
{
return value.Substring(0, maximum - 3) + "...";
}
return value;
}
private static string Wrap(string value, int width, int lines)
{
List<string> list = new List<string>();
string text = value;
while (text.Length > 0 && list.Count < lines)
{
if (text.Length <= width)
{
list.Add(text);
text = "";
break;
}
int num = text.LastIndexOf(' ', width);
if (num <= 0)
{
num = width;
}
list.Add(text.Substring(0, num).TrimEnd(Array.Empty<char>()));
text = text.Substring(num).TrimStart(Array.Empty<char>());
}
if (text.Length > 0)
{
list[list.Count - 1] = Trim(list[list.Count - 1] + " " + text, width);
}
return string.Join("\n", list.ToArray());
}
private bool EnsureBuilt()
{
if ((Object)(object)holder != (Object)null)
{
return true;
}
try
{
Build();
return true;
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Custom Paintings could not build its picture menu: " + ex));
if ((Object)(object)holder != (Object)null)
{
Object.Destroy((Object)(object)holder);
}
holder = null;
return false;
}
}
private void Build()
{
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Expected O, but got Unknown
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
//IL_01de: Unknown result type (might be due to invalid IL or missing references)
//IL_020f: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Unknown result type (might be due to invalid IL or missing references)
//IL_0218: Unknown result type (might be due to invalid IL or missing references)
//IL_0206: Unknown result type (might be due to invalid IL or missing references)
//IL_021d: Unknown result type (might be due to invalid IL or missing references)
//IL_0226: Unknown result type (might be due to invalid IL or missing references)
//IL_023a: Unknown result type (might be due to invalid IL or missing references)
//IL_0251: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Unknown result type (might be due to invalid IL or missing references)
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_029e: Unknown result type (might be due to invalid IL or missing references)
//IL_0356: Unknown result type (might be due to invalid IL or missing references)
//IL_043c: 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_0478: Unknown result type (might be due to invalid IL or missing references)
//IL_048c: Unknown result type (might be due to invalid IL or missing references)
//IL_0491: Unknown result type (might be due to invalid IL or missing references)
//IL_056e: Unknown result type (might be due to invalid IL or missing references)
//IL_060f: Unknown result type (might be due to invalid IL or missing references)
//IL_06bb: Unknown result type (might be due to invalid IL or missing references)
StartMenu val = Object.FindObjectOfType<StartMenu>();
GameObject val2 = (GameObject)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
if ((Object)(object)val2 == (Object)null)
{
throw new InvalidOperationException("Sailwind's menu panel was not found.");
}
Transform transform = val2.transform;
Transform val3 = transform.Find("button confirm");
Transform obj = transform.Find("text title");
TextMesh val4 = ((obj != null) ? ((Component)obj).GetComponent<TextMesh>() : null);
Transform val5 = transform.Find("bg");
object obj2;
if (!((Object)(object)val3 != (Object)null))
{
obj2 = null;
}
else
{
Transform obj3 = val3.Find("text");
obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<TextMesh>() : null);
}
fontTemplate = (TextMesh)obj2;
if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)fontTemplate == (Object)null)
{
throw new InvalidOperationException("Sailwind's menu button, text or panel templates were not found.");
}
buttonTemplate = ((Component)val3).gameObject;
titleTemplate = val4;
GameObject obj4 = GameObject.Find("UI camera");
uiCamera = ((obj4 != null) ? obj4.GetComponent<Camera>() : null);
flatShader = Shader.Find("Sprites/Default");
Renderer component = ((Component)val5).GetComponent<Renderer>();
flatFallback = ((component != null) ? component.sharedMaterial : null);
holder = new GameObject("Custom Paintings picture menu");
holder.SetActive(false);
holder.layer = val2.layer;
root = new GameObject("page").transform;
((Component)root).gameObject.layer = val2.layer;
root.SetParent(holder.transform, false);
GameObject obj5 = Object.Instantiate<GameObject>(((Component)val5).gameObject, root, false);
((Object)obj5).name = "paper";
obj5.transform.localPosition = new Vector3(0f, 0f, 0.06f);
obj5.transform.localRotation = val5.localRotation;
MeshFilter component2 = obj5.GetComponent<MeshFilter>();
Mesh val6 = ((component2 != null) ? component2.sharedMesh : null);
Vector3 val7;
if (!((Object)(object)val6 != (Object)null))
{
val7 = Vector3.one;
}
else
{
Bounds bounds = val6.bounds;
val7 = ((Bounds)(ref bounds)).size;
}
Vector3 val8 = val7;
obj5.transform.localScale = new Vector3(val5.localScale.x, 6.2f / Mathf.Max(0.01f, val8.y), 4.4f / Mathf.Max(0.01f, val8.z));
Label("Choose a Picture", 0f, 1.6f, 0.017f, Ink);
pathText = Label("", 0f, 1.43f, 0.0095f, Ink);
backButton = Button("Back", -2.25f, 1.27f, 0.5f, 0.17f, Back);
searchButton = Button("Search this folder", 0.05f, 1.27f, 3.2f, 0.17f, delegate
{
searchFocused = true;
Refresh();
});
clearButton = Button("Clear", 2.3f, 1.27f, 0.48f, 0.17f, delegate
{
query = "";
page = 0;
Filter();
Refresh();
});
messageText = Label("", 0f, 0f, 0.01f, Ink);
for (int num = 0; num < 20; num++)
{
float x = ((float)(num % 5) - 2f) * 1f;
float num2 = RowY[num / 5];
int index = num;
Cell cell = new Cell();
cell.Folder = Button("Folder", x, num2, 0.88f, 0.44f, delegate
{
OnCell(index);
});
cell.Thumb = Flat("thumbnail " + num, x, num2, 0.03f, out cell.ThumbMaterial);
cell.Thumb.Clicked = delegate
{
OnCell(index);
};
cell.Caption = Label("", x, num2 - 0.22f - 0.075f, 0.0088f, Ink);
cell.Status = Label("", x, num2, 0.0085f, Ink);
Transform transform2 = ((Component)cell.Status).transform;
transform2.localPosition += new Vector3(0f, 0f, -0.01f);
cells[num] = cell;
}
modeButtons = new MenuButton[3];
float[] array = new float[3] { -2.3f, -1.82f, -1.26f };
float[] array2 = new float[3] { 0.44f, 0.44f, 0.58f };
for (int num3 = 0; num3 < modeButtons.Length; num3++)
{
FitMode fitMode = (FitMode)num3;
modeButtons[num3] = Button(fitMode.ToString(), array[num3], -1.48f, array2[num3], 0.15f, delegate
{
SetMode(fitMode);
});
}
borderLabel = Label("", -0.72f, -1.48f, 0.009f, Ink);
swatchButtons = new MenuButton[Swatches.Length];
for (int num4 = 0; num4 < Swatches.Length; num4++)
{
string color = Swatches[num4];
swatchButtons[num4] = Flat("border " + color, -0.38f + (float)num4 * 0.25f, -1.48f, 0.03f, out var material);
PictureFit.ParseColor(color, out var r, out var g, out var b);
material.color = new Color(r, g, b, 1f);
swatchButtons[num4].Clicked = delegate
{
SetBackground(color);
};
}
Button("Original Art", -2.15f, -1.72f, 0.78f, 0.17f, delegate
{
target.ChooseOriginal();
Close();
});
previousButton = Button("<", -0.6f, -1.72f, 0.27f, 0.17f, delegate
{
ChangePage(-1);
});
pageText = Label("", 0f, -1.72f, 0.0095f, Ink);
nextButton = Button(">", 0.6f, -1.72f, 0.27f, 0.17f, delegate
{
ChangePage(1);
});
Button("Close", 2.2f, -1.72f, 0.6f, 0.17f, Close);
}
private TextMesh Label(string value, float x, float y, float scale, Color color)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = Object.Instantiate<GameObject>(((Component)titleTemplate).gameObject, root, false);
((Object)obj).name = "label";
obj.transform.localPosition = new Vector3(x, y, ((Component)titleTemplate).transform.localPosition.z);
obj.transform.localRotation = ((Component)titleTemplate).transform.localRotation;
obj.transform.localScale = Vector3.one * scale;
TextMesh component = obj.GetComponent<TextMesh>();
component.font = fontTemplate.font;
component.fontStyle = fontTemplate.fontStyle;
component.fontSize = fontTemplate.fontSize;
component.characterSize = fontTemplate.characterSize;
((Component)component).GetComponent<Renderer>().sharedMaterial = ((Component)fontTemplate).GetComponent<Renderer>().sharedMaterial;
component.anchor = (TextAnchor)4;
component.alignment = (TextAlignment)1;
component.color = color;
component.text = value;
return component;
}
private MenuButton Button(string label, float x, float y, float width, float height, Action onClick)
{
//IL_004b: 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_0070: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = Object.Instantiate<GameObject>(buttonTemplate, root, false);
((Object)obj).name = "button " + label;
obj.transform.localPosition = new Vector3(x, y, buttonTemplate.transform.localPosition.z);
obj.transform.localRotation = buttonTemplate.transform.localRotation;
obj.transform.localScale = Vector3.one;
StartMenuButton componentInChildren = obj.GetComponentInChildren<StartMenuButton>(true);
if ((Object)(object)componentInChildren == (Object)null)
{
throw new InvalidOperationException("The cloned menu button has no pointer target.");
}
Transform transform = ((Component)componentInChildren).transform;
Object.DestroyImmediate((Object)(object)componentInChildren);
MeshFilter component = ((Component)transform).GetComponent<MeshFilter>();
Mesh val = ((component != null) ? component.sharedMesh : null);
Vector3 val2;
if (!((Object)(object)val != (Object)null))
{
val2 = Vector3.one;
}
else
{
Bounds bounds = val.bounds;
val2 = ((Bounds)(ref bounds)).size;
}
Vector3 val3 = val2;
transform.localScale = new Vector3(width / Mathf.Max(0.01f, val3.x), height / Mathf.Max(0.01f, val3.y), transform.localScale.z);
TextMesh[] componentsInChildren = obj.GetComponentsInChildren<TextMesh>(true);
for (int i = 1; i < componentsInChildren.Length; i++)
{
((Component)componentsInChildren[i]).gameObject.SetActive(false);
}
MenuButton button = ((Component)transform).gameObject.AddComponent<MenuButton>();
button.Clicked = delegate
{
if ((Object)(object)button != (Object)(object)searchButton)
{
searchFocused = false;
}
onClick();
};
((GoPointerButton)button).lookText = "";
((GoPointerButton)button).description = "";
buttonWidths[button] = width;
SetText(button, label, Ink);
return button;
}
private MenuButton Flat(string name, float x, float y, float z, out Material material)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Expected O, but got Unknown
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name)
{
layer = ((Component)root).gameObject.layer
};
val.transform.SetParent(root, false);
val.transform.localPosition = new Vector3(x, y, z);
val.AddComponent<MeshFilter>().sharedMesh = Quad.Mesh;
MeshRenderer obj = val.AddComponent<MeshRenderer>();
((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
((Renderer)obj).receiveShadows = false;
material = (((Object)(object)flatShader != (Object)null) ? new Material(flatShader) : new Material(flatFallback));
material.mainTexture = (Texture)(object)Texture2D.whiteTexture;
material.mainTextureScale = Vector2.one;
material.mainTextureOffset = Vector2.zero;
ownedMaterials.Add(material);
((Renderer)obj).sharedMaterial = material;
val.AddComponent<BoxCollider>().size = new Vector3(1f, 1f, 0.02f);
return val.AddComponent<MenuButton>();
}
private static TextMesh ButtonText(MenuButton button)
{
if (!((Object)(object)button != (Object)null))
{
return null;
}
return ((Component)((Component)button).transform.parent).GetComponentInChildren<TextMesh>(true);
}
private void SetText(MenuButton button, string value, Color color)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
TextMesh val = ButtonText(button);
if (!((Object)(object)val == (Object)null))
{
val.text = value;
val.color = color;
int num = 1;
string[] array = value.Split(new char[1] { '\n' });
foreach (string text in array)
{
num = Math.Max(num, text.Length);
}
buttonWidths.TryGetValue(button, out var value2);
((Component)val).transform.localScale = Vector3.one * Mathf.Min(0.0125f, value2 * 0.85f / (3.85f * (float)num));
}
}
private static void SetVisible(MenuButton button, bool visible)
{
if ((Object)(object)button != (Object)null)
{
((Component)((Component)button).transform.parent).gameObject.SetActive(visible);
}
}
private void OnDestroy()
{
foreach (Material ownedMaterial in ownedMaterials)
{
if ((Object)(object)ownedMaterial != (Object)null)
{
Object.Destroy((Object)(object)ownedMaterial);
}
}
if ((Object)(object)holder != (Object)null)
{
Object.Destroy((Object)(object)holder);
}
}
}
[DataContract]
internal sealed class PictureRecord
{
[DataMember]
public int InstanceId;
[DataMember]
public int PrefabIndex;
[DataMember]
public string Path;
[DataMember(EmitDefaultValue = false)]
public string Mode;
[DataMember(EmitDefaultValue = false)]
public string Background;
public const string DefaultBackground = "#000000";
public FitMode FitMode
{
get
{
if (Mode == null || !Enum.IsDefined(typeof(FitMode), Mode))
{
return FitMode.Fill;
}
return (FitMode)Enum.Parse(typeof(FitMode), Mode);
}
}
public string BackgroundColor => Background ?? "#000000";
}
[DataContract]
internal sealed class PictureSaveDocument
{
[DataMember(IsRequired = true)]
public int Schema = 1;
[DataMember(IsRequired = true)]
public List<PictureRecord> Pictures = new List<PictureRecord>();
}
internal sealed class PictureStore
{
public const string Key = "com.skeptic043.sailwind.custompaintings";
private readonly Dictionary<int, PictureRecord> records = new Dictionary<int, PictureRecord>();
public int Count => records.Count;
public bool Writable { get; private set; } = true;
public string Problem { get; private set; } = "";
public void Reset()
{
records.Clear();
Writable = true;
Problem = "";
}
public bool Load(string json)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
Reset();
if (string.IsNullOrEmpty(json))
{
return true;
}
try
{
PictureSaveDocument pictureSaveDocument;
using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
pictureSaveDocument = (PictureSaveDocument)((XmlObjectSerializer)new DataContractJsonSerializer(typeof(PictureSaveDocument))).ReadObject((Stream)memoryStream);
}
if (pictureSaveDocument == null || pictureSaveDocument.Schema != 1 || pictureSaveDocument.Pictures == null)
{
throw new SerializationException("unsupported picture save schema");
}
foreach (PictureRecord picture in pictureSaveDocument.Pictures)
{
if (picture == null || picture.InstanceId == 0 || string.IsNullOrEmpty(picture.Path))
{
throw new SerializationException("invalid picture record");
}
if (records.ContainsKey(picture.InstanceId))
{
throw new SerializationException("duplicate picture identity");
}
records.Add(picture.InstanceId, picture);
}
return true;
}
catch (Exception ex) when (ex is SerializationException || ex is ArgumentException || ex is XmlException || ex is FormatException || ex is InvalidCastException)
{
records.Clear();
Writable = false;
Problem = ex.Message;
return false;
}
}
public string Serialize()
{
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
PictureSaveDocument pictureSaveDocument = new PictureSaveDocument();
pictureSaveDocument.Pictures.AddRange(records.Values);
pictureSaveDocument.Pictures.Sort((PictureRecord a, PictureRecord b) => a.InstanceId.CompareTo(b.InstanceId));
using MemoryStream memoryStream = new MemoryStream();
((XmlObjectSerializer)new DataContractJsonSerializer(typeof(PictureSaveDocument))).WriteObject((Stream)memoryStream, (object)pictureSaveDocument);
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
public bool TryGet(int instanceId, int prefabIndex, out PictureRecord record)
{
if (records.TryGetValue(instanceId, out record) && record.PrefabIndex == prefabIndex)
{
return true;
}
record = null;
return false;
}
public void Set(int instanceId, int prefabIndex, string path, FitMode mode, string background)
{
Writable = true;
records[instanceId] = new PictureRecord
{
InstanceId = instanceId,
PrefabIndex = prefabIndex,
Path = path,
Mode = ((mode == FitMode.Fill) ? null : mode.ToString()),
Background = ((background == null || background == "#000000") ? null : background)
};
}
public void Remove(int instanceId)
{
Writable = true;
records.Remove(instanceId);
}
}
internal sealed class PictureTextures : MonoBehaviour
{
private sealed class Entry
{
public Texture2D Texture;
public float Aspect;
public bool Loading;
public bool Failed;
public bool ReloadQueued;
public string Stamp;
public int MaxSize;
public bool Compressed;
public readonly HashSet<PaintingPicture> Owners = new HashSet<PaintingPicture>();
}
public const int ThumbnailSide = 192;
private const long KeptBytes = 16777216L;
private const int KeptThumbnails = 60;
private readonly Dictionary<string, Entry> pictures = new Dictionary<string, Entry>(StringComparer.OrdinalIgnoreCase);
private readonly List<KeyValuePair<string, Entry>> kept = new List<KeyValuePair<string, Entry>>();
private readonly Queue<string> pictureQueue = new Queue<string>();
private readonly Dictionary<string, Texture2D> thumbnails = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase);
private readonly HashSet<string> failedThumbnails = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private readonly List<string> wantedThumbnails = new List<string>();
private string loadingThumbnail;
private bool working;
internal static PictureTextures Instance { get; private set; }
private void Awake()
{
Instance = this;
}
public void Acquire(string path, PaintingPicture owner)
{
if (!pictures.TryGetValue(path, out var value))
{
value = TakeKept(path) ?? new Entry();
pictures.Add(path, value);
}
value.Owners.Add(owner);
if ((Object)(object)value.Texture != (Object)null)
{
owner.OnPictureReady(value.Texture, value.Aspect);
return;
}
value.Failed = false;
Enqueue(path, value);
}
public void Release(string path, PaintingPicture owner)
{
if (path == null || !pictures.TryGetValue(path, out var value))
{
return;
}
value.Owners.Remove(owner);
if (value.Owners.Count <= 0 && !value.Loading)
{
pictures.Remove(path);
if ((Object)(object)value.Texture != (Object)null)
{
Keep(path, value);
}
}
}
private void Keep(string path, Entry entry)
{
kept.Add(new KeyValuePair<string, Entry>(path, entry));
long num = 0L;
foreach (KeyValuePair<string, Entry> item in kept)
{
num += Bytes(item.Value.Texture);
}
while (num > 16777216 && kept.Count > 0)
{
num -= Bytes(kept[0].Value.Texture);
Object.Destroy((Object)(object)kept[0].Value.Texture);
kept.RemoveAt(0);
}
}
private Entry TakeKept(string path)
{
int num = kept.FindIndex((KeyValuePair<string, Entry> pair) => string.Equals(pair.Key, path, StringComparison.OrdinalIgnoreCase));
if (num < 0)
{
return null;
}
Entry value = kept[num].Value;
kept.RemoveAt(num);
if ((Object)(object)value.Texture != (Object)null && value.MaxSize == Plugin.MaxSize && value.Compressed == Plugin.Compress && value.Stamp != null && value.Stamp == Stamp(path))
{
return value;
}
if ((Object)(object)value.Texture != (Object)null)
{
Object.Destroy((Object)(object)value.Texture);
}
return null;
}
private void DropKept()
{
foreach (KeyValuePair<string, Entry> item in kept)
{
if ((Object)(object)item.Value.Texture != (Object)null)
{
Object.Destroy((Object)(object)item.Value.Texture);
}
}
kept.Clear();
}
private static long Bytes(Texture2D texture)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Invalid comparison between Unknown and I4
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Invalid comparison between Unknown and I4
if ((Object)(object)texture == (Object)null)
{
return 0L;
}
long num = (long)((Texture)texture).width * (long)((Texture)texture).height;
long num2 = (((int)texture.format == 10) ? (num / 2) : (((int)texture.format == 12) ? num : (num * 3)));
if (texture.mipmapCount <= 1)
{
return num2;
}
return num2 * 4 / 3;
}
private static string Stamp(string path)
{
try
{
FileInfo fileInfo = new FileInfo(path);
return fileInfo.Exists ? (fileInfo.LastWriteTimeUtc.Ticks + ":" + fileInfo.Length) : null;
}
catch
{
return null;
}
}
public void ReloadAll()
{
DropKept();
foreach (KeyValuePair<string, Entry> picture in pictures)
{
ReloadEntry(picture.Key, picture.Value);
}
}
private void ReloadEntry(string path, Entry entry)
{
entry.Failed = false;
if (entry.Loading)
{
entry.ReloadQueued = true;
}
else
{
Enqueue(path, entry);
}
}
public Texture2D Thumbnail(string path)
{
thumbnails.TryGetValue(path, out var value);
return value;
}
public bool ThumbnailFailed(string path)
{
return failedThumbnails.Contains(path);
}
public void ClearThumbnails()
{
wantedThumbnails.Clear();
foreach (Texture2D value in thumbnails.Values)
{
Object.Destroy((Object)(object)value);
}
thumbnails.Clear();
failedThumbnails.Clear();
}
public void WantThumbnails(List<string> paths)
{
wantedThumbnails.Clear();
foreach (string path in paths)
{
if (!thumbnails.ContainsKey(path) && !failedThumbnails.Contains(path) && !string.Equals(path, loadingThumbnail, StringComparison.OrdinalIgnoreCase))
{
wantedThumbnails.Add(path);
}
}
if (thumbnails.Count > 60)
{
HashSet<string> hashSet = new HashSet<string>(paths, StringComparer.OrdinalIgnoreCase);
foreach (string item in new List<string>(thumbnails.Keys))
{
if (thumbnails.Count <= 60)
{
break;
}
if (!hashSet.Contains(item))
{
Object.Destroy((Object)(object)thumbnails[item]);
thumbnails.Remove(item);
}
}
}
Pump();
}
private void Enqueue(string path, Entry entry)
{
if (!entry.Loading)
{
entry.Loading = true;
pictureQueue.Enqueue(path);
Pump();
}
}
private void Pump()
{
if (!working && (pictureQueue.Count > 0 || wantedThumbnails.Count > 0))
{
((MonoBehaviour)this).StartCoroutine(Work());
}
}
private IEnumerator Work()
{
working = true;
try
{
while (true)
{
if (pictureQueue.Count > 0)
{
string path = pictureQueue.Dequeue();
yield return LoadPicture(path);
}
else
{
if (wantedThumbnails.Count <= 0)
{
break;
}
string path2 = wantedThumbnails[0];
wantedThumbnails.RemoveAt(0);
yield return LoadThumbnail(path2);
}
yield return null;
}
}
finally
{
working = false;
}
}
private IEnumerator LoadPicture(string path)
{
if (!pictures.TryGetValue(path, out var entry))
{
yield break;
}
Texture2D result = null;
float aspect = 0f;
string stamp = Stamp(path);
int maxSize = Plugin.MaxSize;
bool compressed = Plugin.Compress;
yield return Decode(path, maxSize, mipmaps: true, compressed, delegate(Texture2D val, float sourceAspect)
{
result = val;
aspect = sourceAspect;
});
entry.Loading = false;
if (entry.Owners.Count == 0)
{
if ((Object)(object)result != (Object)null)
{
Object.Destroy((Object)(object)result);
}
if ((Object)(object)entry.Texture != (Object)null)
{
Object.Destroy((Object)(object)entry.Texture);
}
pictures.Remove(path);
yield break;
}
bool reloadQueued = entry.ReloadQueued;
entry.ReloadQueued = false;
if ((Object)(object)result == (Object)null)
{
if ((Object)(object)entry.Texture == (Object)null)
{
entry.Failed = true;
foreach (PaintingPicture item in new List<PaintingPicture>(entry.Owners))
{
item.OnPictureFailed();
}
}
}
else
{
Texture2D texture = entry.Texture;
entry.Texture = result;
entry.Aspect = aspect;
entry.Stamp = stamp;
entry.MaxSize = maxSize;
entry.Compressed = compressed;
foreach (PaintingPicture item2 in new List<PaintingPicture>(entry.Owners))
{
item2.OnPictureReady(result, aspect);
}
if ((Object)(object)texture != (Object)null)
{
Object.Destroy((Object)(object)texture);
}
}
if (reloadQueued)
{
ReloadEntry(path, entry);
}
}
private IEnumerator LoadThumbnail(string path)
{
Texture2D result = null;
loadingThumbnail = path;
yield return Decode(path, 192, mipmaps: false, compress: true, delegate(Texture2D texture, float _)
{
result = texture;
});
loadingThumbnail = null;
if ((Object)(object)result != (Object)null && thumbnails.ContainsKey(path))
{
Object.Destroy((Object)(object)result);
}
else if ((Object)(object)result != (Object)null && ((Object)(object)PicturePicker.Instance == (Object)null || !PicturePicker.Instance.IsOpen))
{
Object.Destroy((Object)(object)result);
}
else if ((Object)(object)result != (Object)null)
{
thumbnails[path] = result;
}
else
{
failedThumbnails.Add(path);
}
}
private static IEnumerator Decode(string path, int maxSide, bool mipmaps, bool compress, Action<Texture2D, float> done)
{
string absoluteUri;
try
{
absoluteUri = new Uri(Path.GetFullPath(path)).AbsoluteUri;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Not a usable picture path " + path + ": " + ex.Message));
done(null, 0f);
yield break;
}
UnityWebRequest request = UnityWebRequestTexture.GetTexture(absoluteUri, true);
Texture2D texture;
float aspect;
try
{
yield return request.SendWebRequest();
texture = ReadBack(path, request, maxSide, mipmaps, out aspect);
}
finally
{
((IDisposable)request)?.Dispose();
}
if ((Object)(object)texture == (Object)null)
{
done(null, 0f);
yield break;
}
bool finished = false;
try
{
yield return null;
if (!Step(path, delegate
{
texture.Apply(mipmaps, !compress);
}))
{
yield break;
}
if (compress)
{
yield return null;
if (!Step(path, delegate
{
texture.Compress(false);
texture.Apply(false, true);
}))
{
yield break;
}
}
finished = true;
}
finally
{
if (!finished && (Object)(object)texture != (Object)null)
{
Object.Destroy((Object)(object)texture);
}
}
done(texture, aspect);
}
private static bool Step(string path, Action action)
{
try
{
action();
return true;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not prepare picture " + path + ": " + ex.Message));
return false;
}
}
private static Texture2D ReadBack(string path, UnityWebRequest request, int maxSide, bool mipmaps, out float aspect)
{
aspect = 0f;
Texture2D val = null;
try
{
if (request.isNetworkError || request.isHttpError)
{
Plugin.Log.LogWarning((object)("Could not read picture " + path + ": " + request.error));
return null;
}
val = DownloadHandlerTexture.GetContent(request);
if ((Object)(object)val == (Object)null || ((Texture)val).width <= 0 || ((Texture)val).height <= 0)
{
Plugin.Log.LogWarning((object)("Could not decode picture " + path));
return null;
}
aspect = (float)((Texture)val).width / (float)((Texture)val).height;
PictureFit.TargetSize(((Texture)val).width, ((Texture)val).height, maxSide, out var targetWidth, out var targetHeight);
return Resample((Texture)(object)val, targetWidth, targetHeight, mipmaps);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not prepare picture " + path + ": " + ex.Message));
return null;
}
finally
{
if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)val);
}
}
}
private static Texture2D Resample(Texture source, int width, int height, bool mipmaps)
{
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Expected O, but got Unknown
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
RenderTexture val = null;
RenderTexture val2 = null;
Texture2D val3 = null;
RenderTexture active = RenderTexture.active;
try
{
Texture val4 = source;
int num = source.width;
int num2 = source.height;
while (num / 2 >= width && num2 / 2 >= height)
{
num /= 2;
num2 /= 2;
RenderTexture temporary = RenderTexture.GetTemporary(num, num2, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
((Texture)temporary).filterMode = (FilterMode)1;
Graphics.Blit(val4, temporary);
if ((Object)(object)val != (Object)null)
{
RenderTexture.ReleaseTemporary(val);
}
val4 = (Texture)(object)(val = temporary);
}
if ((Object)(object)val != (Object)null && num == width && num2 == height)
{
val2 = val;
val = null;
}
else
{
val2 = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
Graphics.Blit(val4, val2);
}
val3 = new Texture2D(width, height, (TextureFormat)3, mipmaps, false);
RenderTexture.active = val2;
val3.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0, false);
RenderTexture.active = active;
((Texture)val3).wrapMode = (TextureWrapMode)1;
((Texture)val3).filterMode = (FilterMode)((!mipmaps) ? 1 : 2);
((Texture)val3).anisoLevel = (mipmaps ? 4 : 0);
Texture2D result = val3;
val3 = null;
return result;
}
finally
{
RenderTexture.active = active;
if ((Object)(object)val != (Object)null)
{
RenderTexture.ReleaseTemporary(val);
}
if ((Object)(object)val2 != (Object)null)
{
RenderTexture.ReleaseTemporary(val2);
}
if ((Object)(object)val3 != (Object)null)
{
Object.Destroy((Object)(object)val3);
}
}
}
}
[BepInPlugin("com.skeptic043.sailwind.custompaintings", "Custom Paintings", "0.1.7")]
public sealed class Plugin : BaseUnityPlugin
{
[HarmonyPatch(typeof(ShipItem), "OnLoad")]
private static class AttachPatch
{
private static void Postfix(ShipItem __instance)
{
Guard("attach", delegate
{
if (PaintingPicture.IsPainting(__instance) && (Object)(object)Picture((Component)(object)__instance) == (Object)null)
{
((Component)__instance).gameObject.AddComponent<PaintingPicture>().Init(__instance);
}
});
}
}
[HarmonyPatch(typeof(ShipItem), "OnAltActivate", new Type[] { })]
private static class AltActivatePatch
{
private static bool Prefix(ShipItem __instance)
{
bool consumed = false;
Guard("open picker", delegate
{
PaintingPicture paintingPicture = Picture((Component)(object)__instance);
if (!((Object)(object)paintingPicture == (Object)null) && paintingPicture.CanChoose && !((Object)(object)PicturePicker.Instance == (Object)null) && !PicturePicker.Instance.IsOpen)
{
PicturePicker.Instance.Open(paintingPicture);
consumed = true;
}
});
return !consumed;
}
}
[HarmonyPatch(typeof(StartMenu), "LateUpdate")]
private static class EscapePatch
{
private static bool Prefix()
{
PicturePicker picker = PicturePicker.Instance;
if ((Object)(object)picker == (Object)null || !picker.IsOpen)
{
return true;
}
if (!Input.GetKeyDown("escape") && !Input.GetKeyDown("f10") && !Input.GetKeyDown((KeyCode)336))
{
return true;
}
Guard("escape", delegate
{
if (picker.SearchFocused)
{
picker.Blur();
}
else
{
picker.Close();
}
});
return false;
}
}
private static class PointerAccess
{
public static readonly FieldRef<GoPointer, RaycastHit> Hit = AccessTools.FieldRefAccess<GoPointer, RaycastHit>("hit");
public static readonly FieldRef<GoPointer, GoPointerButton> PointedAt = AccessTools.FieldRefAccess<GoPointer, GoPointerButton>("pointedAtButton");
public static readonly FieldRef<GoPointer, float> LookDistance = AccessTools.FieldRefAccess<GoPointer, float>("currentLookDistance");
}
[HarmonyPatch(typeof(GoPointer), "DoRaycast")]
private static class PointerTargetPatch
{
private static void Postfix(GoPointer __instance)
{
try
{
Target(__instance);
}
catch (Exception exception)
{
Failed("pointer target", exception);
}
}
private static void Target(GoPointer __instance)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
if (((int)__instance.type == 2 && GameState.inCursorMenu) || (Object)(object)PointerAccess.PointedAt.Invoke(__instance) != (Object)null || (Object)(object)__instance.GetHeldItem() != (Object)null || GameState.sleeping || (Object)(object)GameState.inBed != (Object)null || BoatCamera.on)
{
return;
}
RaycastHit val = PointerAccess.Hit.Invoke(__instance);
Collider val2 = ((RaycastHit)(ref val)).collider;
if (!((Object)(object)val2 == (Object)null))
{
if (((Component)val2).CompareTag("ItemSubcollider"))
{
val2 = ((Component)((Component)val2).transform.parent).GetComponent<Collider>();
}
ShipItem val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<ShipItem>() : null);
if (!((Object)(object)val3 == (Object)null) && val3.nailed && !((GoPointerButton)val3).unclickable && !((Object)(object)Picture((Component)(object)val3) == (Object)null))
{
PointerAccess.PointedAt.Invoke(__instance) = (GoPointerButton)(object)val3;
PointerAccess.LookDistance.Invoke(__instance) = ((RaycastHit)(ref val)).distance;
}
}
}
}
private static class LookUiAccess
{
public static readonly FieldRef<LookUI, TextMesh> ControlsText = AccessTools.FieldRefAccess<LookUI, TextMesh>("controlsText");
public static readonly FieldRef<LookUI, GoPointer> Pointer = AccessTools.FieldRefAccess<LookUI, GoPointer>("pointer");
public static readonly Action<LookUI> ShowRicon = AccessTools.MethodDelegate<Action<LookUI>>(AccessTools.Method(typeof(LookUI), "ShowRicon", (Type[])null, (Type[])null), (object)null, true);
public static readonly Action<LookUI> HideIcons = AccessTools.MethodDelegate<Action<LookUI>>(AccessTools.Method(typeof(LookUI), "HideIcons", (Type[])null, (Type[])null), (object)null, true);
}
[HarmonyPatch(typeof(LookUI), "ShowLookText")]
private static class LookPromptPatch
{
private static void Postfix(LookUI __instance, GoPointerButton button)
{
try
{
Prompt(__instance, button);
}
catch (Exception exception)
{
Failed("look prompt", exception);
}
}
private static void Prompt(LookUI __instance, GoPointerButton button)
{
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
if (button.IsStickyClicked())
{
return;
}
PaintingPicture paintingPicture = Picture((Component)(object)button);
if ((Object)(object)paintingPicture == (Object)null || !paintingPicture.CanChoose)
{
return;
}
GoPointer val = LookUiAccess.Pointer.Invoke(__instance);
if (!((Object)(object)val == (Object)null) && !((Object)(object)val.GetHeldItem() != (Object)null))
{
if (((ShipItem)button).nailed)
{
__instance.ClearText();
}
else if (Settings.controlsTextEnabled)
{
LookUiAccess.ShowRicon(__instance);
TextMesh obj = LookUiAccess.ControlsText.Invoke(__instance);
obj.text = obj.text.Split(new char[1] { '\n' })[0] + "\nchange picture";
}
}
}
}
[HarmonyPatch(typeof(LookUI), "ShowHoldText")]
private static class HoldPromptPatch
{
private static void Postfix(LookUI __instance, PickupableItem item)
{
try
{
PaintingPicture paintingPicture = Picture((Component)(object)item);
if (Settings.controlsTextEnabled && !((Object)(object)paintingPicture == (Object)null) && paintingPicture.CanChoose)
{
LookUiAccess.ShowRicon(__instance);
LookUiAccess.ControlsText.Invoke(__instance).text = "change picture";
}
}
catch (Exception exception)
{
Failed("hold prompt", exception);
}
}
}
[HarmonyPatch(typeof(SaveLoadManager), "SaveModData")]
private static class SavePatch
{
private static void Postfix()
{
Guard("save", delegate
{
if (Store.Writable)
{
if (Store.Count > 0)
{
GameState.modData["com.skeptic043.sailwind.custompaintings"] = Store.Serialize();
}
else
{
GameState.modData.Remove("com.skeptic043.sailwind.custompaintings");
}
}
});
}
}
[HarmonyPatch(typeof(SaveLoadManager), "LoadGame")]
private static class LoadGamePatch
{
private static void Prefix()
{
Guard("load reset", Reset);
}
}
[HarmonyPatch(typeof(SaveLoadManager), "LoadModData")]
private static class LoadModDataPatch
{
private static void Postfix()
{
Guard("load", delegate
{
GameState.modData.TryGetValue("com.skeptic043.sailwind.custompaintings", out var value);
if (!Store.Load(value))
{
Log.LogWarning((object)("Saved pictures could not be read and were left unchanged in the save: " + Store.Problem));
}
});
}
}
[HarmonyPatch(typeof(StartMenu), "StartNewGame")]
private static class NewGamePatch
{
private static void Prefix()
{
Guard("new game reset", Reset);
}
}
public const string Id = "com.skeptic043.sailwind.custompaintings";
private const string ChangePrompt = "change picture";
private static ConfigEntry<string> pictureFolders;
private static ConfigEntry<int> maxSize;
private static ConfigEntry<bool> compress;
private Harmony harmony;
internal static ManualLogSource Log { get; private set; }
internal static PictureStore Store { get; } = new PictureStore();
internal static string PictureFolders => pictureFolders.Value;
internal static int MaxSize => maxSize.Value;
internal static bool Compress => compress.Value;
private void Awake()
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
pictureFolders = ((BaseUnityPlugin)this).Config.Bind<string>("Pictures", "Picture folders", "", "Folders to choose pictures from, separated by |. Each one is listed when the menu opens, and its subfolders can be browsed. PNG and JPG are supported.");
maxSize = ((BaseUnityPlugin)this).Config.Bind<int>("Pictures", "Maximum size", 1024, new ConfigDescription("Pictures larger than this on their longer side are shrunk to it. Smaller pictures keep their size. 1024 uses a quarter of the memory of 2048. 2048 matches the game's own paintings and looks sharper up close.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[3] { 1024, 2048, 4096 }), Array.Empty<object>()));
compress = ((BaseUnityPlugin)this).Config.Bind<bool>("Pictures", "Compress pictures", true, "Store pictures compressed in video memory, using about a sixth of the memory with a slight loss of quality.");
try
{
((Component)this).gameObject.AddComponent<PictureTextures>();
((Component)this).gameObject.AddComponent<PicturePicker>();
maxSize.SettingChanged += delegate
{
PictureTextures.Instance?.ReloadAll();
};
compress.SettingChanged += delegate
{
PictureTextures.Instance?.ReloadAll();
};
harmony = new Harmony("com.skeptic043.sailwind.custompaintings");
harmony.PatchAll(typeof(Plugin).Assembly);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom Paintings loaded.");
}
catch (Exception ex)
{
((Behaviour)this).enabled = false;
try
{
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
}
catch (Exception ex2)
{
((BaseUnityPlugin)this).Logger.LogError((object)("Custom Paintings could not remove its partial patches: " + ex2));
}
((BaseUnityPlugin)this).Logger.LogError((object)("Custom Paintings disabled after initialization failed. Check game and mod compatibility: " + ex));
}
}
private static void Guard(string patch, Action action)
{
try
{
action();
}
catch (Exception exception)
{
Failed(patch, exception);
}
}
private static void Failed(string patch, Exception exception)
{
Log.LogError((object)$"Custom Paintings {patch} failed: {exception}");
}
private static PaintingPicture Picture(Component item)
{
if (!((Object)(object)item != (Object)null))
{
return null;
}
return item.GetComponent<PaintingPicture>();
}
private static void Reset()
{
PicturePicker.Instance?.Close();
Store.Reset();
GameState.modData.Remove("com.skeptic043.sailwind.custompaintings");
}
}
}