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 Mailbox v1.0.0
plugins/Mailbox.dll
Decompiled 3 days agousing 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.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Splatform; using UnityEngine; using UnityEngine.Networking; [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("Mailbox")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Mailbox")] [assembly: AssemblyTitle("Mailbox")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Mailbox { internal sealed class ConfigurationManagerAttributes { public int? Order; public bool? HideDefaultButton; public Action<ConfigEntryBase> CustomDrawer; } internal static class FilePicker { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private class OpenFileName { public int lStructSize; public IntPtr hwndOwner; public IntPtr hInstance; public string lpstrFilter; public string lpstrCustomFilter; public int nMaxCustFilter; public int nFilterIndex; public string lpstrFile; public int nMaxFile; public string lpstrFileTitle; public int nMaxFileTitle; public string lpstrInitialDir; public string lpstrTitle; public int Flags; public short nFileOffset; public short nFileExtension; public string lpstrDefExt; public IntPtr lCustData; public IntPtr lpfnHook; public string lpTemplateName; public IntPtr pvReserved; public int dwReserved; public int FlagsEx; } private const int OFN_NOCHANGEDIR = 8; private const int OFN_PATHMUSTEXIST = 2048; private const int OFN_FILEMUSTEXIST = 4096; private const int OFN_EXPLORER = 524288; private static volatile bool _isOpen; private static volatile string _result; public static bool IsSupported { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if ((int)Application.platform != 2) { return (int)Application.platform == 7; } return true; } } public static bool IsOpen => _isOpen; public static void Open() { if (!_isOpen && IsSupported) { _isOpen = true; IntPtr owner = GetActiveWindow(); Thread thread = new Thread((ThreadStart)delegate { Run(owner); }); thread.IsBackground = true; thread.Name = "Mailbox file picker"; thread.SetApartmentState(ApartmentState.STA); thread.Start(); } } public static bool TryTakeResult(out string path) { path = _result; if (path == null) { return false; } _result = null; return true; } private static void Run(IntPtr owner) { try { OpenFileName openFileName = new OpenFileName { hwndOwner = owner, lpstrFilter = "Audio files (*.wav, *.ogg, *.mp3)\0*.wav;*.ogg;*.mp3\0All files (*.*)\0*.*\0\0", lpstrFile = new string('\0', 1024), lpstrTitle = "Mailbox - choose a sound", Flags = 530440 }; openFileName.nMaxFile = openFileName.lpstrFile.Length; openFileName.lStructSize = Marshal.SizeOf(openFileName); if (GetOpenFileNameW(openFileName)) { string text = openFileName.lpstrFile?.TrimEnd('\0'); if (!string.IsNullOrEmpty(text)) { _result = text; } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not open the file dialog: " + ex.Message)); } finally { _isOpen = false; } } [DllImport("user32.dll")] private static extern IntPtr GetActiveWindow(); [DllImport("comdlg32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool GetOpenFileNameW([In][Out] OpenFileName ofn); } internal class Letter { public long Id; public string Sender; public string Text; public long SentTicks; public bool Read; } internal static class LetterStore { public const int MaxLetters = 20; public const int MaxLength = 300; public const string ZdoKey = "batera_mailbox_letters"; private const int FormatVersion = 1; private const string ZeroWidthSpace = "\u200b"; public static List<Letter> Load(ZDO zdo) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown List<Letter> list = new List<Letter>(); string text = ((zdo != null) ? zdo.GetString("batera_mailbox_letters", "") : null); if (string.IsNullOrEmpty(text)) { return list; } try { ZPackage val = new ZPackage(text); if (val.ReadInt() != 1) { return list; } int num = val.ReadInt(); for (int i = 0; i < num; i++) { list.Add(new Letter { Id = val.ReadLong(), Sender = val.ReadString(), Text = val.ReadString(), SentTicks = val.ReadLong(), Read = val.ReadBool() }); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not read mailbox letters: " + ex.Message)); } return list; } public static void Save(ZDO zdo, List<Letter> letters) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(letters.Count); foreach (Letter letter in letters) { val.Write(letter.Id); val.Write(letter.Sender ?? ""); val.Write(letter.Text ?? ""); val.Write(letter.SentTicks); val.Write(letter.Read); } zdo.Set("batera_mailbox_letters", val.GetBase64()); } public static string Sanitize(string text) { if (text == null) { return ""; } text = text.Replace('<', ' ').Replace('>', ' ').Replace("$", "$\u200b") .Trim(); if (text.Length <= 300) { return text; } return text.Substring(0, 300); } public static string ForRuneFont(string text) { if (string.IsNullOrEmpty(text)) { return ""; } StringBuilder stringBuilder = new StringBuilder(text.Length); string text2 = text.Replace("\u200b", "").Normalize(NormalizationForm.FormD); foreach (char c in text2) { if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) { stringBuilder.Append(c); } } return stringBuilder.ToString().Normalize(NormalizationForm.FormC); } } internal class MailboxComponent : MonoBehaviour, Hoverable, Interactable, TextReceiver { private const string RpcAdd = "Batera_Mailbox_Add"; private const string RpcMarkRead = "Batera_Mailbox_MarkRead"; private const string RpcDelete = "Batera_Mailbox_Delete"; private const string OwnerNameKey = "batera_mailbox_owner"; private const float WriteCooldown = 10f; private const float AnnounceDistance = 15f; private static float s_lastWriteTime = -999f; private ZNetView _nview; private Piece _piece; private Transform _flag; private float _flagAngle = 90f; private long _lastReadId; private bool _writeAnonymous; private bool _announced; private string _cachedData; private List<Letter> _cachedLetters = new List<Letter>(); private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); _piece = ((Component)this).GetComponent<Piece>(); _flag = ((Component)this).transform.Find("mailbox_model/flag_pivot"); if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null) { _nview.Register<string, string, long>("Batera_Mailbox_Add", (Action<long, string, string, long>)RPC_Add); _nview.Register<long>("Batera_Mailbox_MarkRead", (Action<long, long>)RPC_MarkRead); _nview.Register<long>("Batera_Mailbox_Delete", (Action<long, long>)RPC_Delete); } } private void Start() { if (IsValid() && _nview.IsOwner() && IsMine()) { ZDO zDO = _nview.GetZDO(); if (string.IsNullOrEmpty(zDO.GetString("batera_mailbox_owner", "")) && (Object)(object)Player.m_localPlayer != (Object)null) { zDO.Set("batera_mailbox_owner", Player.m_localPlayer.GetPlayerName()); } } } private void Update() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) if (IsValid()) { int num = CountUnread(Letters()); float num2 = ((num > 0) ? 0f : 90f); _flagAngle = Mathf.MoveTowards(_flagAngle, num2, 180f * Time.deltaTime); if ((Object)(object)_flag != (Object)null) { _flag.localRotation = Quaternion.Euler(_flagAngle, 0f, 0f); } if (num == 0) { _announced = false; } else if (!_announced && IsMine() && (Object)(object)Player.m_localPlayer != (Object)null && Vector3.Distance(((Component)Player.m_localPlayer).transform.position, ((Component)this).transform.position) < 15f) { _announced = true; Message((MessageType)2, Translations.Format("$batera_mailbox_you_have_mail", num)); } } } public string GetHoverName() { return Translations.Get("$piece_batera_mailbox"); } public float GetHoverOffset() { return 0f; } public string GetHoverText() { if (!IsValid()) { return ""; } string text = _nview.GetZDO().GetString("batera_mailbox_owner", ""); string text2 = (string.IsNullOrEmpty(text) ? Translations.Get("$piece_batera_mailbox") : Translations.Format("$batera_mailbox_owned_by", text)); List<Letter> list = Letters(); if (IsMine()) { if (list.Count == 0) { return text2 + "\n" + Translations.Get("$batera_mailbox_empty"); } text2 = text2 + "\n" + Translations.Format("$batera_mailbox_counts", CountUnread(list), list.Count); text2 = text2 + "\n" + Translations.Get("[<color=yellow><b>$KEY_Use</b></color>] $batera_mailbox_read"); if (_lastReadId != 0L) { text2 = text2 + "\n" + Translations.Get("[<color=yellow><b>" + AltKey() + " + $KEY_Use</b></color>] $batera_mailbox_delete"); } return text2; } if (list.Count >= 20) { return text2 + "\n" + Translations.Get("$batera_mailbox_full"); } return text2 + "\n" + Translations.Get("[<color=yellow><b>$KEY_Use</b></color>] $batera_mailbox_write") + "\n" + Translations.Get("[<color=yellow><b>" + AltKey() + " + $KEY_Use</b></color>] $batera_mailbox_write_anonymous"); } private static string AltKey() { if (!ZInput.IsNonClassicFunctionality() || !ZInput.IsGamepadActive()) { return "$KEY_AltPlace"; } return "$KEY_AltKeys"; } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold || !IsValid()) { return false; } if (IsMine()) { if (alt) { DeleteLastRead(); } else { ReadNext(); } return true; } if (Letters().Count >= 20) { Message((MessageType)2, Translations.Get("$batera_mailbox_full")); return true; } if (Time.time - s_lastWriteTime < 10f || (Object)(object)TextInput.instance == (Object)null) { return true; } _writeAnonymous = alt; string text = _nview.GetZDO().GetString("batera_mailbox_owner", ""); string text2 = Translations.Format(alt ? "$batera_mailbox_write_topic_anonymous" : "$batera_mailbox_write_topic", text); TextInput.instance.RequestText((TextReceiver)(object)this, text2, 300); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetText() { return ""; } public void SetText(string text) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) text = LetterStore.Sanitize(text); if (!string.IsNullOrEmpty(text) && IsValid()) { s_lastWriteTime = Time.time; string text2 = (_writeAnonymous ? "" : (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerName() : "?")); long num = DateTime.UtcNow.Ticks + Random.Range(0, 10000); _nview.InvokeRPC("Batera_Mailbox_Add", new object[3] { text2, text, num }); if ((Object)(object)_piece != (Object)null) { OwnerNotify.Send(_piece.GetCreator(), text2, ((Component)this).transform.position); } string text3 = _nview.GetZDO().GetString("batera_mailbox_owner", ""); Message((MessageType)2, Translations.Format("$batera_mailbox_sent", text3)); } } private void ReadNext() { List<Letter> list = Letters(); if (list.Count == 0) { Message((MessageType)2, Translations.Get("$batera_mailbox_empty")); return; } Letter letter = list.Find((Letter l) => !l.Read); if (letter == null) { int num = list.FindIndex((Letter l) => l.Id == _lastReadId); letter = list[(num + 1) % list.Count]; } string text = new DateTime(letter.SentTicks, DateTimeKind.Utc).ToLocalTime().ToString("dd/MM/yyyy HH:mm"); string text2 = (string.IsNullOrEmpty(letter.Sender) ? Translations.Get("$batera_mailbox_anonymous_letter") : Translations.Format("$batera_mailbox_letter_from", LetterStore.Sanitize(letter.Sender))); TextViewer instance = TextViewer.instance; if ((Object)(object)instance != (Object)null) { instance.ShowText((Style)0, text2, letter.Text + "\n\n" + text, true); if ((Object)(object)instance.m_runeText != (Object)null) { instance.m_runeText.text = LetterStore.ForRuneFont(letter.Text); } } _lastReadId = letter.Id; if (!letter.Read) { _nview.InvokeRPC("Batera_Mailbox_MarkRead", new object[1] { letter.Id }); } } private void DeleteLastRead() { if (_lastReadId != 0L) { _nview.InvokeRPC("Batera_Mailbox_Delete", new object[1] { _lastReadId }); _lastReadId = 0L; TextViewer instance = TextViewer.instance; if (instance != null) { instance.Hide(); } Message((MessageType)2, Translations.Get("$batera_mailbox_deleted")); } } private void RPC_Add(long sender, string from, string text, long id) { if (_nview.IsOwner()) { List<Letter> list = LetterStore.Load(_nview.GetZDO()); if (list.Count < 20 && !list.Exists((Letter l) => l.Id == id)) { list.Add(new Letter { Id = id, Sender = from, Text = LetterStore.Sanitize(text), SentTicks = DateTime.UtcNow.Ticks }); LetterStore.Save(_nview.GetZDO(), list); } } } private void RPC_MarkRead(long sender, long id) { if (_nview.IsOwner()) { List<Letter> list = LetterStore.Load(_nview.GetZDO()); Letter letter = list.Find((Letter l) => l.Id == id); if (letter != null && !letter.Read) { letter.Read = true; LetterStore.Save(_nview.GetZDO(), list); } } } private void RPC_Delete(long sender, long id) { if (_nview.IsOwner()) { List<Letter> list = LetterStore.Load(_nview.GetZDO()); if (list.RemoveAll((Letter l) => l.Id == id) > 0) { LetterStore.Save(_nview.GetZDO(), list); } } } private bool IsValid() { if ((Object)(object)_nview != (Object)null) { return _nview.IsValid(); } return false; } public bool HasLetters() { if (IsValid()) { return Letters().Count > 0; } return false; } public bool IsMine() { if ((Object)(object)_piece != (Object)null) { return _piece.IsCreator(); } return false; } private List<Letter> Letters() { string text = _nview.GetZDO().GetString("batera_mailbox_letters", ""); if ((object)text != _cachedData && text != _cachedData) { _cachedData = text; _cachedLetters = LetterStore.Load(_nview.GetZDO()); } return _cachedLetters; } private static int CountUnread(List<Letter> letters) { int num = 0; foreach (Letter letter in letters) { if (!letter.Read) { num++; } } return num; } private static void Message(MessageType type, string text) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage(type, text, 0, (Sprite)null, false, true); } } } internal static class MailboxModel { public const string FlagPath = "mailbox_model/flag_pivot"; private static readonly Color IronFallback = new Color(0.35f, 0.35f, 0.38f); private static readonly Color DoorColor = new Color(0.62f, 0.5f, 0.4f); private static readonly Color FlagColor = new Color(0.75f, 0.12f, 0.08f); public static void Apply(GameObject prefab) { //IL_003b: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_0152: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: 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_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) Material val = FirstMaterial(prefab); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)"Mailbox: base prefab has no material to reuse."); return; } Material material = ItemMaterial("Iron") ?? Tinted(val, IronFallback); Material material2 = Tinted(val, DoorColor); Material material3 = Tinted(val, FlagColor); RemoveBaseVisuals(prefab); GameObject val2 = new GameObject("mailbox_model"); val2.transform.SetParent(prefab.transform, false); val2.layer = LayerMask.NameToLayer("piece"); Mesh mesh = PrimitiveMesh((PrimitiveType)3); Mesh mesh2 = PrimitiveMesh((PrimitiveType)2); Transform transform = val2.transform; Part(transform, "foot", mesh, val, new Vector3(0f, 0.02f, 0f), new Vector3(0.26f, 0.04f, 0.26f)); Part(transform, "post", mesh, val, new Vector3(0f, 0.5f, 0f), new Vector3(0.09f, 1f, 0.09f)); Part(transform, "box", mesh, val, new Vector3(0f, 1.11f, 0f), new Vector3(0.28f, 0.22f, 0.46f)); Part(transform, "roof", mesh2, val, new Vector3(0f, 1.22f, 0f), new Vector3(0.28f, 0.23f, 0.28f), Quaternion.Euler(90f, 0f, 0f)); float[] array = new float[2] { -0.15f, 0.15f }; foreach (float num in array) { Part(transform, "band", mesh, material, new Vector3(0f, 1.11f, num), new Vector3(0.295f, 0.225f, 0.025f)); Part(transform, "band_roof", mesh2, material, new Vector3(0f, 1.22f, num), new Vector3(0.295f, 0.0125f, 0.295f), Quaternion.Euler(90f, 0f, 0f)); } Part(transform, "door", mesh, material2, new Vector3(0f, 1.13f, 0.233f), new Vector3(0.22f, 0.24f, 0.012f)); Part(transform, "handle", mesh, material, new Vector3(0f, 1.2f, 0.245f), new Vector3(0.06f, 0.015f, 0.02f)); GameObject val3 = new GameObject("flag_pivot") { layer = val2.layer }; val3.transform.SetParent(transform, false); val3.transform.localPosition = new Vector3(0.15f, 1.08f, -0.08f); val3.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); Part(val3.transform, "flag_pole", mesh, material, new Vector3(0.01f, 0.12f, 0f), new Vector3(0.015f, 0.24f, 0.015f)); Part(val3.transform, "flag", mesh, material3, new Vector3(0.01f, 0.2f, 0.06f), new Vector3(0.012f, 0.08f, 0.11f)); BoxCollider obj = val2.AddComponent<BoxCollider>(); obj.center = new Vector3(0f, 0.68f, 0f); obj.size = new Vector3(0.34f, 1.36f, 0.5f); WearNTear component = prefab.GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { component.m_new = val2; component.m_worn = val2; component.m_broken = val2; component.m_wet = null; component.m_fragmentRoots = null; } } private static void RemoveBaseVisuals(GameObject prefab) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown List<GameObject> list = new List<GameObject>(); foreach (Transform item in prefab.transform) { Transform val = item; list.Add(((Component)val).gameObject); } foreach (GameObject item2 in list) { Object.DestroyImmediate((Object)(object)item2); } LODGroup[] components = prefab.GetComponents<LODGroup>(); for (int i = 0; i < components.Length; i++) { Object.DestroyImmediate((Object)(object)components[i]); } Renderer[] components2 = prefab.GetComponents<Renderer>(); for (int i = 0; i < components2.Length; i++) { Object.DestroyImmediate((Object)(object)components2[i]); } MeshFilter[] components3 = prefab.GetComponents<MeshFilter>(); for (int i = 0; i < components3.Length; i++) { Object.DestroyImmediate((Object)(object)components3[i]); } Collider[] components4 = prefab.GetComponents<Collider>(); for (int i = 0; i < components4.Length; i++) { Object.DestroyImmediate((Object)(object)components4[i]); } } private static GameObject Part(Transform parent, string name, Mesh mesh, Material material, Vector3 position, Vector3 scale, Quaternion? rotation = null) { //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_0017: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown GameObject val = new GameObject(name) { layer = ((Component)parent).gameObject.layer }; val.transform.SetParent(parent, false); val.transform.localPosition = position; val.transform.localRotation = (Quaternion)(((??)rotation) ?? Quaternion.identity); val.transform.localScale = scale; val.AddComponent<MeshFilter>().sharedMesh = mesh; ((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterial = material; return val; } private static Mesh PrimitiveMesh(PrimitiveType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive(type); Mesh sharedMesh = obj.GetComponent<MeshFilter>().sharedMesh; Object.DestroyImmediate((Object)(object)obj); return sharedMesh; } private static Material FirstMaterial(GameObject go) { MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val in componentsInChildren) { if ((Object)(object)((Renderer)val).sharedMaterial != (Object)null) { return ((Renderer)val).sharedMaterial; } } return null; } private static Material ItemMaterial(string itemPrefab) { GameObject prefab = Cache.GetPrefab<GameObject>(itemPrefab); if (!((Object)(object)prefab != (Object)null)) { return null; } return FirstMaterial(prefab); } private static Material Tinted(Material source, Color color) { //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_001d: Expected O, but got Unknown //IL_002b: Unknown result type (might be due to invalid IL or missing references) Material val = new Material(source) { name = ((Object)source).name + "_mailbox" }; if (val.HasProperty("_Color")) { val.color = color; } return val; } } internal static class MailboxPiece { public const string PrefabName = "piece_batera_mailbox"; private const string BasePrefab = "itemstand"; public static void Register() { PrefabManager.OnVanillaPrefabsAvailable += AddPiece; } private static void AddPiece() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown PrefabManager.OnVanillaPrefabsAvailable -= AddPiece; PieceConfig val = new PieceConfig(); val.Name = "$piece_batera_mailbox"; val.Description = "$piece_batera_mailbox_desc"; val.PieceTable = PieceTables.Hammer; val.Category = PieceCategories.Furniture; val.CraftingStation = CraftingStations.Workbench; val.Requirements = (RequirementConfig[])(object)new RequirementConfig[2] { new RequirementConfig("Wood", 4, 0, true), new RequirementConfig("Copper", 1, 0, true) }; PieceConfig val2 = val; CustomPiece val3 = new CustomPiece("piece_batera_mailbox", "itemstand", val2); if (!val3.IsValid()) { Plugin.Log.LogError((object)"Could not create the mailbox piece from 'itemstand'."); return; } ReplaceBehaviour(val3.PiecePrefab); MailboxModel.Apply(val3.PiecePrefab); val3.PiecePrefab.AddComponent<MailboxComponent>(); SetIcon(val3); PieceManager.Instance.AddPiece(val3); } private static void SetIcon(CustomPiece piece) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Sprite val = RenderManager.Instance.Render(piece.PiecePrefab, Quaternion.Euler(12f, 35f, 0f)); if ((Object)(object)val != (Object)null) { piece.Piece.m_icon = val; } else { Plugin.Log.LogWarning((object)"Could not render the mailbox icon; using the base piece icon."); } } private static void ReplaceBehaviour(GameObject prefab) { MonoBehaviour[] componentsInChildren = prefab.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren) { if (val is Interactable || val is Hoverable || val is TextReceiver) { Object.DestroyImmediate((Object)(object)val); } } } } internal static class MapPing { public static void Show(Vector3 position, string label, float seconds) { //IL_0028: 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) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Minimap.instance == (Object)null) && !(seconds <= 0f) && !((Object)(object)SoundPlayer.Instance == (Object)null)) { PinData pin = Minimap.instance.AddPin(position, (PinType)12, label, false, false, 0L, default(PlatformUserID)); ((MonoBehaviour)SoundPlayer.Instance).StartCoroutine(RemoveLater(pin, seconds)); } } private static IEnumerator RemoveLater(PinData pin, float seconds) { yield return (object)new WaitForSeconds(seconds); if ((Object)(object)Minimap.instance != (Object)null) { Minimap.instance.RemovePin(pin); } } } internal static class OwnerNotify { [HarmonyPatch(typeof(Game), "Start")] private static class GameStartPatch { private static void Postfix() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.Register<long, string, Vector3>("Batera_Mailbox_NotifyOwner", (Action<long, long, string, Vector3>)RPC_NotifyOwner); } } } private const string RpcNotify = "Batera_Mailbox_NotifyOwner"; public static void Send(long ownerId, string sender, Vector3 position) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (ownerId != 0L && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Batera_Mailbox_NotifyOwner", new object[3] { ownerId, sender, position }); } } private static void RPC_NotifyOwner(long peer, long ownerId, string sender, Vector3 position) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || localPlayer.GetPlayerID() != ownerId || !Plugin.NotifyNewLetter.Value) { return; } SoundPlayer.Instance?.Play2D(); if (string.IsNullOrEmpty(sender)) { sender = Translations.Get("$batera_mailbox_anonymous"); } if ((Object)(object)MessageHud.instance != (Object)null) { string text = Plugin.NotifyMessage.Value; if (string.IsNullOrWhiteSpace(text)) { text = "Nova carta de {player}!"; } MessageHud.instance.ShowMessage((MessageType)2, text.Replace("{player}", sender), 0, (Sprite)null, false, true); } MapPing.Show(position, Translations.Format("$batera_mailbox_new_letter_pin", sender), Plugin.MapPingSeconds.Value); } } [BepInPlugin("batera.Mailbox", "Mailbox", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "batera.Mailbox"; public const string PluginName = "Mailbox"; public const string PluginVersion = "1.0.0"; internal static Plugin Instance; internal static ManualLogSource Log; internal static ConfigEntry<bool> NotifyNewLetter; internal static ConfigEntry<string> NotifyMessage; internal static ConfigEntry<float> MapPingSeconds; internal static ConfigEntry<SoundPreset> SoundPresetSetting; internal static ConfigEntry<string> SoundFile; internal static ConfigEntry<float> Volume; private Harmony _harmony; private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; BindConfig(); GameObject val = new GameObject("Mailbox"); Object.DontDestroyOnLoad((Object)val); val.AddComponent<SoundPlayer>(); Translations.Register(); MailboxPiece.Register(); _harmony = new Harmony("batera.Mailbox"); _harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Mailbox 1.0.0 loaded"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void BindConfig() { //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown NotifyNewLetter = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - New letters", "Notify", true, Desc("When someone writes to your mailbox, play a sound and show a message wherever you are.", 3)); NotifyMessage = ((BaseUnityPlugin)this).Config.Bind<string>("1 - New letters", "MessageText", "Nova carta de {player}!", Desc("Message shown when you get a letter. {player} = who wrote it.", 2)); MapPingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("1 - New letters", "MapPingSeconds", 30f, Desc("How long (seconds) your mailbox stays marked on your map after a new letter. Only you see it. 0 = off.", 1, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f))); SoundPresetSetting = ((BaseUnityPlugin)this).Config.Bind<SoundPreset>("2 - Sound", "SoundPreset", SoundPreset.MagicBells, Desc("Sound for new letters. DingDong is built into the mod; MagicBells, Knock and Forge are game sounds; Custom uses SoundFile.", 5)); Volume = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Sound", "Volume", 0.7f, Desc("Sound volume.", 4, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f))); SoundFile = ((BaseUnityPlugin)this).Config.Bind<string>("2 - Sound", "SoundFile", "", new ConfigDescription("Custom sound file (.wav, .ogg or .mp3), used when SoundPreset = Custom. Click Browse to pick a file, or Reset to clear it.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 3, CustomDrawer = DrawSoundFile } })); ((BaseUnityPlugin)this).Config.Bind<string>("2 - Sound", "TestSound", "", new ConfigDescription("Plays the new letter sound with the current settings.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 2, HideDefaultButton = true, CustomDrawer = DrawTestButton } })); } private static ConfigDescription Desc(string text, int order, AcceptableValueBase range = null) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown return new ConfigDescription(text, range, new object[1] { new ConfigurationManagerAttributes { Order = order } }); } private static void DrawSoundFile(ConfigEntryBase entry) { string value = SoundFile.Value; GUILayout.Label(string.IsNullOrEmpty(value) ? "(none)" : Path.GetFileName(value), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (FilePicker.IsSupported) { bool enabled = GUI.enabled; GUI.enabled = enabled && !FilePicker.IsOpen; if (GUILayout.Button(FilePicker.IsOpen ? "Choosing..." : "Browse...", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) })) { FilePicker.Open(); } GUI.enabled = enabled; } } private static void DrawTestButton(ConfigEntryBase entry) { if (GUILayout.Button("Test sound", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) })) { SoundPlayer.Instance?.Play2D(); } } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class RemovalGuard { private static float s_lastHint = -999f; private static void Postfix(Piece __instance, ref bool __result) { if (!__result) { return; } MailboxComponent component = ((Component)__instance).GetComponent<MailboxComponent>(); if (!((Object)(object)component == (Object)null) && component.HasLetters()) { __result = false; if (Time.time - s_lastHint > 3f && (Object)(object)MessageHud.instance != (Object)null) { s_lastHint = Time.time; MessageHud.instance.ShowMessage((MessageType)1, Translations.Get("$batera_mailbox_remove_hint"), 0, (Sprite)null, false, true); } } } } internal class SoundPlayer : MonoBehaviour { private static readonly Dictionary<SoundPreset, string> GameSounds = new Dictionary<SoundPreset, string> { { SoundPreset.MagicBells, "sfx_secretfound" }, { SoundPreset.Knock, "sfx_gui_craftitem_workbench" }, { SoundPreset.Forge, "sfx_gui_craftitem_forge_end" } }; private readonly Dictionary<SoundPreset, AudioClip> _gameClips = new Dictionary<SoundPreset, AudioClip>(); private AudioSource _source2D; private AudioClip _dingDong; private AudioClip _customClip; public static SoundPlayer Instance { get; private set; } private void Awake() { Instance = this; _source2D = ((Component)this).gameObject.AddComponent<AudioSource>(); _source2D.playOnAwake = false; _source2D.spatialBlend = 0f; _source2D.ignoreListenerPause = true; _dingDong = CreateDingDong(); LoadCustomClip(); Plugin.SoundFile.SettingChanged += delegate { if (!string.IsNullOrWhiteSpace(Plugin.SoundFile.Value)) { Plugin.SoundPresetSetting.Value = SoundPreset.Custom; } LoadCustomClip(); }; } private void Update() { if (FilePicker.TryTakeResult(out var path)) { Plugin.SoundFile.Value = path; } } public void Play2D() { _source2D.Stop(); _source2D.PlayOneShot(GetClip(), Plugin.Volume.Value); } private AudioClip GetClip() { SoundPreset value = Plugin.SoundPresetSetting.Value; if (value == SoundPreset.Custom) { if (!((Object)(object)_customClip != (Object)null)) { return _dingDong; } return _customClip; } if (GameSounds.TryGetValue(value, out var value2)) { if (!_gameClips.TryGetValue(value, out var value3) || (Object)(object)value3 == (Object)null) { value3 = FindGameClip(value2); if ((Object)(object)value3 != (Object)null) { _gameClips[value] = value3; } } if ((Object)(object)value3 != (Object)null) { return value3; } } return _dingDong; } private static AudioClip FindGameClip(string prefabName) { if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } GameObject prefab = ZNetScene.instance.GetPrefab(prefabName); ZSFX val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponentInChildren<ZSFX>(true) : null); if ((Object)(object)val == (Object)null || val.m_audioClips == null || val.m_audioClips.Length == 0) { Plugin.Log.LogWarning((object)("Game sound '" + prefabName + "' not found. Using the built-in ding-dong.")); return null; } return val.m_audioClips[0]; } private void LoadCustomClip() { //IL_008a: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) _customClip = null; string text = Plugin.SoundFile.Value?.Trim().Trim('"'); if (string.IsNullOrEmpty(text)) { return; } string text2 = ResolveSoundPath(text); if (text2 == null) { Plugin.Log.LogWarning((object)("Sound file not found: '" + text + "'. Using the built-in ding-dong.")); return; } AudioType type; switch (Path.GetExtension(text2).ToLowerInvariant()) { case ".wav": type = (AudioType)20; break; case ".ogg": type = (AudioType)14; break; case ".mp3": type = (AudioType)13; break; default: Plugin.Log.LogWarning((object)("Unsupported sound format '" + text2 + "'. Use .wav, .ogg or .mp3.")); return; } ((MonoBehaviour)this).StartCoroutine(LoadClip(text2, type)); } private static string ResolveSoundPath(string setting) { if (Path.IsPathRooted(setting)) { if (!File.Exists(setting)) { return null; } return setting; } string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location); string[] array = new string[3] { Paths.ConfigPath, directoryName, Paths.PluginPath }; foreach (string text in array) { if (!string.IsNullOrEmpty(text)) { string text2 = Path.Combine(text, setting); if (File.Exists(text2)) { return text2; } } } return null; } private IEnumerator LoadClip(string path, AudioType type) { //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) UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(new Uri(path).AbsoluteUri, type); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { Plugin.Log.LogWarning((object)("Failed to load sound '" + path + "': " + request.error)); yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content == (Object)null || content.length <= 0f) { Plugin.Log.LogWarning((object)("Sound '" + path + "' is empty or invalid.")); yield break; } ((Object)content).name = Path.GetFileNameWithoutExtension(path); _customClip = content; Plugin.Log.LogInfo((object)("Loaded custom mailbox sound: " + path)); } finally { ((IDisposable)request)?.Dispose(); } } private static AudioClip CreateDingDong() { float[] array = new float[2] { 659.25f, 523.25f }; int num = 85995; float[] array2 = new float[num]; for (int i = 0; i < array.Length; i++) { float num2 = array[i]; int num3 = (int)(24255f * (float)i); int num4 = 61740; for (int j = 0; j < num4 && num3 + j < num; j++) { float num5 = (float)j / 44100f; float num6 = Mathf.Clamp01(num5 / 0.004f); float num7 = Mathf.Exp((0f - num5) * 3.2f); float num8 = Mathf.Sin(MathF.PI * 2f * num2 * num5) + 0.5f * Mathf.Sin(MathF.PI * 2f * num2 * 2f * num5) * Mathf.Exp((0f - num5) * 5f) + 0.25f * Mathf.Sin(MathF.PI * 2f * num2 * 3.01f * num5) * Mathf.Exp((0f - num5) * 9f); array2[num3 + j] += num8 * num6 * num7 * 0.35f; } } AudioClip obj = AudioClip.Create("MailboxDingDong", array2.Length, 1, 44100, false); obj.SetData(array2, 0); return obj; } } public enum SoundPreset { MagicBells, DingDong, Knock, Forge, Custom } internal static class Translations { public const string PieceName = "$piece_batera_mailbox"; public const string PieceDescription = "$piece_batera_mailbox_desc"; public const string OwnedBy = "$batera_mailbox_owned_by"; public const string Write = "$batera_mailbox_write"; public const string WriteTopic = "$batera_mailbox_write_topic"; public const string WriteAnonymous = "$batera_mailbox_write_anonymous"; public const string WriteTopicAnonymous = "$batera_mailbox_write_topic_anonymous"; public const string AnonymousLetter = "$batera_mailbox_anonymous_letter"; public const string Anonymous = "$batera_mailbox_anonymous"; public const string Full = "$batera_mailbox_full"; public const string Read = "$batera_mailbox_read"; public const string Delete = "$batera_mailbox_delete"; public const string Counts = "$batera_mailbox_counts"; public const string Empty = "$batera_mailbox_empty"; public const string LetterFrom = "$batera_mailbox_letter_from"; public const string Sent = "$batera_mailbox_sent"; public const string Deleted = "$batera_mailbox_deleted"; public const string YouHaveMail = "$batera_mailbox_you_have_mail"; public const string NewLetterPin = "$batera_mailbox_new_letter_pin"; public const string RemoveHint = "$batera_mailbox_remove_hint"; public static void Register() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { Key("$piece_batera_mailbox"), "Mailbox" }, { Key("$piece_batera_mailbox_desc"), "Other players can leave you letters, even inside your ward. Only you can read them." }, { Key("$batera_mailbox_owned_by"), "{0}'s mailbox" }, { Key("$batera_mailbox_write"), "Write a letter" }, { Key("$batera_mailbox_write_topic"), "Letter to {0} (type \\n for a new line)" }, { Key("$batera_mailbox_write_anonymous"), "Write an anonymous letter" }, { Key("$batera_mailbox_write_topic_anonymous"), "Anonymous letter to {0} (type \\n for a new line)" }, { Key("$batera_mailbox_anonymous_letter"), "Anonymous letter" }, { Key("$batera_mailbox_anonymous"), "anonymous" }, { Key("$batera_mailbox_full"), "Mailbox full" }, { Key("$batera_mailbox_read"), "Read letter" }, { Key("$batera_mailbox_delete"), "Delete the letter you just read" }, { Key("$batera_mailbox_counts"), "{0} new, {1} total" }, { Key("$batera_mailbox_empty"), "No letters" }, { Key("$batera_mailbox_letter_from"), "Letter from {0}" }, { Key("$batera_mailbox_sent"), "Letter delivered to {0}'s mailbox" }, { Key("$batera_mailbox_deleted"), "Letter deleted" }, { Key("$batera_mailbox_you_have_mail"), "You have {0} new letter(s)!" }, { Key("$batera_mailbox_new_letter_pin"), "Letter from {0}" }, { Key("$batera_mailbox_remove_hint"), "Delete all letters before removing the mailbox" } }); text = "Portuguese_Brazilian"; localization.AddTranslation(ref text, new Dictionary<string, string> { { Key("$piece_batera_mailbox"), "Caixa de correio" }, { Key("$piece_batera_mailbox_desc"), "Outros jogadores podem te deixar cartas, mesmo dentro do seu ward. Só você pode ler." }, { Key("$batera_mailbox_owned_by"), "Caixa de correio de {0}" }, { Key("$batera_mailbox_write"), "Escrever carta" }, { Key("$batera_mailbox_write_topic"), "Carta para {0} (digite \\n para pular linha)" }, { Key("$batera_mailbox_write_anonymous"), "Escrever carta anônima" }, { Key("$batera_mailbox_write_topic_anonymous"), "Carta anônima para {0} (digite \\n para pular linha)" }, { Key("$batera_mailbox_anonymous_letter"), "Carta anônima" }, { Key("$batera_mailbox_anonymous"), "anônimo" }, { Key("$batera_mailbox_full"), "Caixa de correio cheia" }, { Key("$batera_mailbox_read"), "Ler carta" }, { Key("$batera_mailbox_delete"), "Apagar a carta que você leu" }, { Key("$batera_mailbox_counts"), "{0} nova(s), {1} no total" }, { Key("$batera_mailbox_empty"), "Nenhuma carta" }, { Key("$batera_mailbox_letter_from"), "Carta de {0}" }, { Key("$batera_mailbox_sent"), "Carta entregue na caixa de correio de {0}" }, { Key("$batera_mailbox_deleted"), "Carta apagada" }, { Key("$batera_mailbox_you_have_mail"), "Você tem {0} carta(s) nova(s)!" }, { Key("$batera_mailbox_new_letter_pin"), "Carta de {0}" }, { Key("$batera_mailbox_remove_hint"), "Apague todas as cartas antes de remover a caixa de correio" } }); } public static string Get(string token) { if (Localization.instance == null) { return token; } return Localization.instance.Localize(token); } public static string Format(string token, params object[] args) { return string.Format(Get(token), args); } private static string Key(string token) { return token.TrimStart('$'); } } }