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 MMOHeimSimpleQuest v1.0.3
MMOHeimSimpleQuest.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Newtonsoft.Json; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("MMOHeim SimpleQuest")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("MMOHeim SimpleQuest")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("526f6350-8ad0-4fd8-8066-5806b070f058")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace SimpleQuest; [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] public static class ItemCollectionPatch { private static void Postfix(Inventory __instance, ItemData item, bool __result) { if (!__result || item == null || (Object)(object)item.m_dropPrefab == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || __instance != ((Humanoid)Player.m_localPlayer).GetInventory()) { return; } if ((Object)(object)SimpleQuestPro.Instance != (Object)null) { string name = ((Object)item.m_dropPrefab).name; foreach (QuestConfig item2 in SimpleQuestPro.Instance.serverQuests.Quests.Where((QuestConfig q) => string.IsNullOrEmpty(q.PreReqID) || SimpleQuestPro.Instance.completedQuests.Contains(q.PreReqID)).ToList()) { if (!SimpleQuestPro.Instance.completedQuests.Contains(item2.ID)) { QuestRequirement questRequirement = item2.Reqs?.FirstOrDefault((QuestRequirement r) => r.Prefab.Trim().Equals(name, StringComparison.OrdinalIgnoreCase)); if (questRequirement != null) { int itemCount = QuestUtils.GetItemCount(name); string itemName = QuestUtils.GetItemName(name); ((Character)Player.m_localPlayer).Message((MessageType)1, $"<b><color=#FFD700>{itemName}: {itemCount} / {questRequirement.Amount}</color></b>", 0, (Sprite)null); } } } if (SimpleQuestPro.Instance.IsWindowActive()) { QuestUI.UpdateUI(); } } QuestUI.UpdateHUD(); } } [HarmonyPatch] public static class PlantWatcher { [HarmonyPatch(typeof(Player), "ConsumeResources")] [HarmonyPrefix] private static void Prefix(Requirement[] requirements, int itemQuality) { if (requirements == null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } foreach (Requirement val in requirements) { if (val == null || (Object)(object)val.m_resItem == (Object)null) { continue; } string name = ((Object)val.m_resItem).name; string questName = ""; if (name.Contains("CarrotSeeds")) { questName = "Carrot"; } else if (name.Contains("TurnipSeeds")) { questName = "Turnip"; } else if (name.Contains("OnionSeeds")) { questName = "Onion"; } else if (name.Contains("Seed")) { questName = name.Replace("Seeds", "").Replace("Seed", ""); } if (string.IsNullOrEmpty(questName)) { continue; } if ((Object)(object)SimpleQuestPro.Instance != (Object)null) { foreach (QuestConfig visibleQuest in QuestUtils.GetVisibleQuests()) { if (SimpleQuestPro.Instance.completedQuests.Contains(visibleQuest.ID)) { continue; } QuestRequirement questRequirement = visibleQuest.KillReqs?.FirstOrDefault((QuestRequirement k) => string.Equals(k.Prefab.Trim(), questName, StringComparison.OrdinalIgnoreCase)); if (questRequirement != null) { if (!SimpleQuestPro.playerKills.ContainsKey(questName)) { SimpleQuestPro.playerKills[questName] = 0; } SimpleQuestPro.playerKills[questName]++; int num = SimpleQuestPro.playerKills[questName]; string itemName = QuestUtils.GetItemName(questName); ((Character)Player.m_localPlayer).Message((MessageType)1, $"<b><color=#FFD700>{itemName}: {num} / {questRequirement.Amount}</color></b>", 0, (Sprite)null); } } if (SimpleQuestPro.Instance.IsWindowActive()) { QuestUI.UpdateUI(); } } QuestUI.UpdateHUD(); } } } public class QuestConfig { public string ID; public string Title; public string Goal; public string Rarity; public string RewardItem; public string PreReqID; public int RewardAmount; public int ExpReward; public List<QuestRequirement> Reqs; public List<QuestRequirement> KillReqs; public List<QuestRequirement> RewardItems; } public class QuestList { public List<QuestConfig> Quests = new List<QuestConfig>(); } public class QuestRequirement { public string Prefab; public int Amount; } public static class QuestUI { private class TrackerDragHandler : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler { private RectTransform rectTransform; private Canvas canvas; private bool canDrag; public void OnBeginDrag(PointerEventData eventData) { canDrag = IsTrackerDragAllowed() && (Object)(object)hudPanel != (Object)null && hudPanel.activeSelf; if (canDrag) { rectTransform = hudPanel.GetComponent<RectTransform>(); canvas = (((Object)(object)rectTransform != (Object)null) ? ((Component)rectTransform).GetComponentInParent<Canvas>() : null); } } public void OnDrag(PointerEventData eventData) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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) if (!IsTrackerDragAllowed()) { canDrag = false; } else if (canDrag && !((Object)(object)rectTransform == (Object)null)) { float num = (((Object)(object)canvas != (Object)null && canvas.scaleFactor > 0f) ? canvas.scaleFactor : 1f); RectTransform obj = rectTransform; obj.anchoredPosition += eventData.delta / num; ClampRectToScreen(rectTransform); } } public void OnEndDrag(PointerEventData eventData) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (canDrag && (Object)(object)rectTransform != (Object)null && (Object)(object)SimpleQuestPro.Instance != (Object)null) { ClampRectToScreen(rectTransform); SimpleQuestPro.Instance.SaveTrackerPosition(ToSavedTopLeft(rectTransform)); } canDrag = false; } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__10_0; public static UnityAction <>9__10_1; public static UnityAction <>9__10_2; public static UnityAction <>9__10_3; public static Func<KeyValuePair<string, int>, int> <>9__11_2; public static Func<QuestRequirement, string> <>9__11_0; public static Func<KeyValuePair<string, int>, int> <>9__12_2; internal void <CreateUI>b__10_0() { List<QuestConfig> visibleQuests = QuestUtils.GetVisibleQuests(); if (visibleQuests.Count > 0) { QuestConfig questConfig = visibleQuests[currentIndex]; if (SimpleQuestPro.trackedQuests.Contains(questConfig.ID)) { SimpleQuestPro.trackedQuests.Remove(questConfig.ID); } else { SimpleQuestPro.trackedQuests.Add(questConfig.ID); } UpdateUI(); UpdateHUD(); QuestUtils.PlaySfx("sfx_gui_mouse_over"); } } internal void <CreateUI>b__10_1() { int count = QuestUtils.GetVisibleQuests().Count; if (count > 0) { currentIndex = (currentIndex - 1 + count) % count; currentIconIndex = 0; UpdateUI(); QuestUtils.PlaySfx("sfx_book_page"); } } internal void <CreateUI>b__10_2() { int count = QuestUtils.GetVisibleQuests().Count; if (count > 0) { currentIndex = (currentIndex + 1) % count; currentIconIndex = 0; UpdateUI(); QuestUtils.PlaySfx("sfx_book_page"); } } internal void <CreateUI>b__10_3() { showHistoryMode = !showHistoryMode; currentIndex = 0; UpdateUI(); QuestUtils.PlaySfx("sfx_book_page"); } internal int <UpdateUI>b__11_2(KeyValuePair<string, int> x) { return x.Value; } internal string <UpdateUI>b__11_0(QuestRequirement x) { return $"{QuestUtils.GetItemName(x.Prefab)} x{x.Amount}"; } internal int <UpdateHUD>b__12_2(KeyValuePair<string, int> x) { return x.Value; } } public static GameObject window; public static GameObject hudPanel; public static Text infoText; public static Text pageText; public static Text btnText; public static Text titleText; public static Text historyBtnText; public static Text hudText; public static Text trackBtnText; public static GameObject btnFinish; public static GameObject btnHistory; public static GameObject btnTrack; public static Image rewardIcon; public static int currentIndex; public static int currentIconIndex; public static float iconTimer; public static bool showHistoryMode; private static bool hudAttachedToMinimap; private static Image hudBackground; private static CanvasGroup hudCanvasGroup; private static readonly Color hudGhostColor = new Color(0.22f, 0.16f, 0.1f, 0f); private static Transform ResolveMainUiRoot() { if ((Object)(object)GUIManager.CustomGUIFront != (Object)null) { return GUIManager.CustomGUIFront.transform; } if ((Object)(object)Hud.instance != (Object)null) { return ((Component)Hud.instance).transform; } return null; } private static void DestroySafe(GameObject go) { if ((Object)(object)go != (Object)null) { Object.Destroy((Object)(object)go); } } public static void CleanupUI() { DestroySafe(window); DestroySafe(hudPanel); window = null; hudPanel = null; infoText = null; pageText = null; btnText = null; titleText = null; historyBtnText = null; hudText = null; trackBtnText = null; btnFinish = null; btnHistory = null; btnTrack = null; rewardIcon = null; hudBackground = null; hudCanvasGroup = null; hudAttachedToMinimap = false; } private static string L(string key, string fallback) { string text = "$" + key; string text2 = ((Localization.instance != null) ? Localization.instance.Localize(text) : text); if (!(text2 == text) && !string.IsNullOrEmpty(text2)) { return text2; } return fallback; } private static bool IsTrackerDragAllowed() { if ((Object)(object)Menu.instance != (Object)null) { return Menu.IsVisible(); } return false; } public static void SetTrackerInteractionEnabled(bool enabled) { if ((Object)(object)hudBackground != (Object)null) { ((Graphic)hudBackground).raycastTarget = enabled; } if ((Object)(object)hudCanvasGroup != (Object)null) { hudCanvasGroup.blocksRaycasts = enabled; hudCanvasGroup.interactable = enabled; } } private static Vector2 ToSavedTopLeft(RectTransform rectTransform) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) Vector2 anchoredPosition = rectTransform.anchoredPosition; Rect rect = rectTransform.rect; return anchoredPosition - new Vector2(((Rect)(ref rect)).width, 0f); } private static Vector2 FromSavedTopLeft(RectTransform rectTransform, Vector2 savedTopLeft) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Rect rect = rectTransform.rect; return savedTopLeft + new Vector2(((Rect)(ref rect)).width, 0f); } private static void ClampRectToScreen(RectTransform rectTransform) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rectTransform == (Object)null)) { Vector3[] array = (Vector3[])(object)new Vector3[4]; rectTransform.GetWorldCorners(array); Vector3 zero = Vector3.zero; if (array[0].x < 0f) { zero.x += 0f - array[0].x; } if (array[2].x > (float)Screen.width) { zero.x -= array[2].x - (float)Screen.width; } if (array[0].y < 0f) { zero.y += 0f - array[0].y; } if (array[2].y > (float)Screen.height) { zero.y -= array[2].y - (float)Screen.height; } if (zero != Vector3.zero) { ((Transform)rectTransform).position = ((Transform)rectTransform).position + zero; } } } private static void TryAttachHudToMinimap() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hudPanel == (Object)null) { return; } RectTransform component = hudPanel.GetComponent<RectTransform>(); if ((Object)(object)component == (Object)null) { return; } Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_smallRoot == (Object)null) { Transform val = ResolveMainUiRoot(); if ((Object)(object)val != (Object)null) { ((Transform)component).SetParent(val, false); hudAttachedToMinimap = false; Debug.Log((object)"[MMOHeim SimpleQuest] Minimap root missing. Tracker parented to fallback UI root."); } else { Debug.LogWarning((object)"[MMOHeim SimpleQuest] Could not attach tracker: both minimap and fallback UI root are unavailable."); } hudAttachedToMinimap = false; } else { ((Transform)component).SetParent(instance.m_smallRoot.transform, false); component.anchorMin = new Vector2(1f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(1f, 1f); component.sizeDelta = new Vector2(360f, 120f); LayoutRebuilder.ForceRebuildLayoutImmediate(component); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(-380f, -20f); Vector2 savedTopLeft = (((Object)(object)SimpleQuestPro.Instance != (Object)null) ? SimpleQuestPro.Instance.GetSavedTrackerPosition(val2) : val2); component.anchoredPosition = FromSavedTopLeft(component, savedTopLeft); ClampRectToScreen(component); hudAttachedToMinimap = true; Debug.Log((object)"[MMOHeim SimpleQuest] Tracker parented to Minimap.smallRoot."); } } public static void CreateUI() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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_011f: 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_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Expected O, but got Unknown //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Expected O, but got Unknown //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_0449: Unknown result type (might be due to invalid IL or missing references) //IL_044e: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Expected O, but got Unknown //IL_0518: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_0536: Unknown result type (might be due to invalid IL or missing references) //IL_0578: Unknown result type (might be due to invalid IL or missing references) //IL_0582: Expected O, but got Unknown //IL_05db: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Expected O, but got Unknown //IL_0602: Unknown result type (might be due to invalid IL or missing references) //IL_0617: Unknown result type (might be due to invalid IL or missing references) //IL_062c: Unknown result type (might be due to invalid IL or missing references) //IL_0641: Unknown result type (might be due to invalid IL or missing references) //IL_0655: Unknown result type (might be due to invalid IL or missing references) //IL_0673: Unknown result type (might be due to invalid IL or missing references) //IL_06bc: Unknown result type (might be due to invalid IL or missing references) //IL_06c6: Expected O, but got Unknown //IL_06fb: Unknown result type (might be due to invalid IL or missing references) //IL_070a: Unknown result type (might be due to invalid IL or missing references) //IL_0719: Unknown result type (might be due to invalid IL or missing references) //IL_072a: Unknown result type (might be due to invalid IL or missing references) //IL_0730: Unknown result type (might be due to invalid IL or missing references) //IL_0755: Unknown result type (might be due to invalid IL or missing references) //IL_0787: Unknown result type (might be due to invalid IL or missing references) //IL_079c: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Unknown result type (might be due to invalid IL or missing references) //IL_04ef: Unknown result type (might be due to invalid IL or missing references) //IL_04f5: Expected O, but got Unknown //IL_07bd: Unknown result type (might be due to invalid IL or missing references) //IL_07c8: Unknown result type (might be due to invalid IL or missing references) //IL_07dd: Unknown result type (might be due to invalid IL or missing references) //IL_07f2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)window != (Object)null && (Object)(object)hudPanel != (Object)null) { return; } CleanupUI(); if (GUIManager.Instance == null) { Debug.LogWarning((object)"[MMOHeim SimpleQuest] CreateUI aborted: GUIManager.Instance is null."); return; } Transform val = ResolveMainUiRoot(); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)"[MMOHeim SimpleQuest] CreateUI aborted: no valid UI root (CustomGUIFront/Hud) is available."); return; } try { window = GUIManager.Instance.CreateWoodpanel(val, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 600f, 550f, true); Image component = window.GetComponent<Image>(); if ((Object)(object)component != (Object)null) { ((Graphic)component).color = new Color(0.6f, 0.6f, 0.6f, 1f); } titleText = GUIManager.Instance.CreateText("", window.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -20f), GUIManager.Instance.AveriaSerifBold, 18, new Color(1f, 0.84f, 0f, 1f), false, Color.clear, 400f, 30f, false).GetComponent<Text>(); titleText.alignment = (TextAnchor)4; pageText = GUIManager.Instance.CreateText("", window.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -40f), GUIManager.Instance.AveriaSerifBold, 14, Color.white, false, Color.clear, 200f, 30f, false).GetComponent<Text>(); pageText.alignment = (TextAnchor)4; infoText = GUIManager.Instance.CreateText("", window.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 60f), GUIManager.Instance.AveriaSerifBold, 17, Color.white, false, Color.clear, 500f, 350f, false).GetComponent<Text>(); infoText.alignment = (TextAnchor)4; GameObject val2 = new GameObject("RewardIcon", new Type[1] { typeof(Image) }); val2.transform.SetParent(window.transform, false); rewardIcon = val2.GetComponent<Image>(); RectTransform component2 = val2.GetComponent<RectTransform>(); component2.anchoredPosition = new Vector2(0f, -145f); component2.sizeDelta = new Vector2(64f, 64f); val2.SetActive(false); btnTrack = GUIManager.Instance.CreateButton(L("sq_track", "TRACK"), window.transform, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-100f, 45f), 130f, 30f); trackBtnText = btnTrack.GetComponentInChildren<Text>(); ButtonClickedEvent onClick = btnTrack.GetComponent<Button>().onClick; object obj = <>c.<>9__10_0; if (obj == null) { UnityAction val3 = delegate { List<QuestConfig> visibleQuests = QuestUtils.GetVisibleQuests(); if (visibleQuests.Count > 0) { QuestConfig questConfig = visibleQuests[currentIndex]; if (SimpleQuestPro.trackedQuests.Contains(questConfig.ID)) { SimpleQuestPro.trackedQuests.Remove(questConfig.ID); } else { SimpleQuestPro.trackedQuests.Add(questConfig.ID); } UpdateUI(); UpdateHUD(); QuestUtils.PlaySfx("sfx_gui_mouse_over"); } }; <>c.<>9__10_0 = val3; obj = (object)val3; } ((UnityEvent)onClick).AddListener((UnityAction)obj); ButtonClickedEvent onClick2 = GUIManager.Instance.CreateButton("<", window.transform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(60f, 0f), 45f, 45f).GetComponent<Button>().onClick; object obj2 = <>c.<>9__10_1; if (obj2 == null) { UnityAction val4 = delegate { int count2 = QuestUtils.GetVisibleQuests().Count; if (count2 > 0) { currentIndex = (currentIndex - 1 + count2) % count2; currentIconIndex = 0; UpdateUI(); QuestUtils.PlaySfx("sfx_book_page"); } }; <>c.<>9__10_1 = val4; obj2 = (object)val4; } ((UnityEvent)onClick2).AddListener((UnityAction)obj2); ButtonClickedEvent onClick3 = GUIManager.Instance.CreateButton(">", window.transform, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-60f, 0f), 45f, 45f).GetComponent<Button>().onClick; object obj3 = <>c.<>9__10_2; if (obj3 == null) { UnityAction val5 = delegate { int count = QuestUtils.GetVisibleQuests().Count; if (count > 0) { currentIndex = (currentIndex + 1) % count; currentIconIndex = 0; UpdateUI(); QuestUtils.PlaySfx("sfx_book_page"); } }; <>c.<>9__10_2 = val5; obj3 = (object)val5; } ((UnityEvent)onClick3).AddListener((UnityAction)obj3); btnHistory = GUIManager.Instance.CreateButton(L("sq_history", "HISTORY"), window.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-90f, -40f), 130f, 30f); historyBtnText = btnHistory.GetComponentInChildren<Text>(); ButtonClickedEvent onClick4 = btnHistory.GetComponent<Button>().onClick; object obj4 = <>c.<>9__10_3; if (obj4 == null) { UnityAction val6 = delegate { showHistoryMode = !showHistoryMode; currentIndex = 0; UpdateUI(); QuestUtils.PlaySfx("sfx_book_page"); }; <>c.<>9__10_3 = val6; obj4 = (object)val6; } ((UnityEvent)onClick4).AddListener((UnityAction)obj4); btnFinish = GUIManager.Instance.CreateButton("", window.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 45f), 200f, 40f); btnText = btnFinish.GetComponentInChildren<Text>(); ((UnityEvent)btnFinish.GetComponent<Button>().onClick).AddListener(new UnityAction(SimpleQuestPro.Instance.CompleteQuest)); hudPanel = new GameObject("TrackerContainer", new Type[6] { typeof(RectTransform), typeof(Image), typeof(CanvasGroup), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter), typeof(TrackerDragHandler) }); RectTransform component3 = hudPanel.GetComponent<RectTransform>(); ((Transform)component3).SetParent(val, false); component3.anchorMin = new Vector2(1f, 1f); component3.anchorMax = new Vector2(1f, 1f); component3.pivot = new Vector2(1f, 1f); component3.anchoredPosition = new Vector2(-380f, -20f); component3.sizeDelta = new Vector2(360f, 280f); hudBackground = hudPanel.GetComponent<Image>(); ((Graphic)hudBackground).color = hudGhostColor; hudCanvasGroup = hudPanel.GetComponent<CanvasGroup>(); SetTrackerInteractionEnabled(enabled: false); VerticalLayoutGroup component4 = hudPanel.GetComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)component4).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)component4).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)component4).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)component4).childForceExpandHeight = false; ((LayoutGroup)component4).padding = new RectOffset(5, 5, 5, 5); ContentSizeFitter component5 = hudPanel.GetComponent<ContentSizeFitter>(); component5.horizontalFit = (FitMode)2; component5.verticalFit = (FitMode)2; GameObject obj5 = GUIManager.Instance.CreateText("", hudPanel.transform, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0f, 0f), GUIManager.Instance.AveriaSerifBold, 16, Color.white, false, Color.clear, 360f, 280f, false); hudText = obj5.GetComponent<Text>(); ((Graphic)hudText).color = Color.white; hudText.horizontalOverflow = (HorizontalWrapMode)0; hudText.verticalOverflow = (VerticalWrapMode)1; hudText.alignment = (TextAnchor)0; Outline obj6 = obj5.AddComponent<Outline>(); ((Shadow)obj6).effectColor = Color.black; ((Shadow)obj6).effectDistance = new Vector2(0.8f, -0.8f); ((Shadow)obj6).useGraphicAlpha = true; RectTransform component6 = obj5.GetComponent<RectTransform>(); if ((Object)(object)component6 != (Object)null) { component6.anchorMin = Vector2.zero; component6.anchorMax = Vector2.one; component6.offsetMin = new Vector2(5f, 5f); component6.offsetMax = new Vector2(-5f, -5f); } obj5.transform.SetAsLastSibling(); TryAttachHudToMinimap(); hudPanel.SetActive(false); window.SetActive(false); Debug.Log((object)("[MMOHeim SimpleQuest] CreateUI completed successfully. Main UI root: " + ((Object)val).name)); } catch (Exception ex) { Debug.LogError((object)("[MMOHeim SimpleQuest] CreateUI failed: " + ex)); CleanupUI(); } } public static void UpdateUI() { List<QuestConfig> visibleQuests = QuestUtils.GetVisibleQuests(); titleText.text = (showHistoryMode ? ("<color=#FFD700><b>" + L("sq_history", "HERO HISTORY") + "</b></color>") : ("<color=#FFD700><b>" + Localization.instance.Localize("$sq_journal") + "</b></color>")); historyBtnText.text = (showHistoryMode ? L("sq_back", "BACK") : L("sq_history", "HISTORY")); if (visibleQuests.Count == 0) { infoText.text = (showHistoryMode ? ("\n\n" + L("sq_no_history", "No hero history yet.")) : ("\n\n" + L("sq_no_quests", "Quest list is empty"))); pageText.text = "0 / 0"; btnFinish.SetActive(false); btnTrack.SetActive(false); Image val = rewardIcon; if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } return; } btnFinish.SetActive(!showHistoryMode); btnTrack.SetActive(!showHistoryMode); if (currentIndex >= visibleQuests.Count) { currentIndex = 0; } QuestConfig questConfig = visibleQuests[currentIndex]; trackBtnText.text = (SimpleQuestPro.trackedQuests.Contains(questConfig.ID) ? ("<color=#FF4500>" + L("sq_untrack", "UNTRACK") + "</color>") : L("sq_track", "TRACK")); bool flag = SimpleQuestPro.Instance.completedQuests.Contains(questConfig.ID); bool flag2 = true; string rarityColor = QuestUtils.GetRarityColor(questConfig.Rarity); string text = (showHistoryMode ? "\n<color=#00FF00><b>[ COMPLETED ]</b></color>\n" : ""); string text2 = "\n<color=" + rarityColor + ">━━━━━━━━━━━━━━━━━━</color>\n"; if (questConfig.Reqs != null) { foreach (QuestRequirement req in questConfig.Reqs) { int num = (flag ? req.Amount : QuestUtils.GetItemCount(req.Prefab)); text2 += string.Format("• {0}: <color={1}><b>{2}</b> / {3}</color>\n", QuestUtils.GetItemName(req.Prefab), (num >= req.Amount) ? "#00FF00" : "#FF4500", num, req.Amount); if (!flag && num < req.Amount) { flag2 = false; } } } if (questConfig.KillReqs != null) { foreach (QuestRequirement i in questConfig.KillReqs) { int num2 = (flag ? i.Amount : SimpleQuestPro.playerKills.Where(delegate(KeyValuePair<string, int> x) { KeyValuePair<string, int> keyValuePair = x; return keyValuePair.Key.Equals(i.Prefab.Trim(), StringComparison.OrdinalIgnoreCase); }).Sum((KeyValuePair<string, int> x) => x.Value)); int num3 = num2; text2 += string.Format("• {0}: <color={1}><b>{2}</b> / {3}</color>\n", Localization.instance.Localize("$" + i.Prefab.Trim()), (num3 >= i.Amount) ? "#00FF00" : "#FF4500", num3, i.Amount); if (!flag && num3 < i.Amount) { flag2 = false; } } } bool flag3 = QuestUtils.HasEnoughVanillaInventoryForRewards(questConfig, ((Humanoid)Player.m_localPlayer).GetInventory(), includeSlotsFreedByRequirements: true); if (flag) { btnText.text = L("sq_done", "DONE"); ((Selectable)btnFinish.GetComponent<Button>()).interactable = false; } else { btnText.text = ((!flag2) ? L("sq_not_enough", "NOT ENOUGH") : ((!flag3) ? L("sq_no_space", "NO SPACE") : ("<b>" + L("sq_finish", "COMPLETE") + "</b>"))); ((Selectable)btnFinish.GetComponent<Button>()).interactable = flag2 && flag3; } pageText.text = $"{currentIndex + 1} / {visibleQuests.Count}"; SetRewardIcon((questConfig.RewardItems != null && questConfig.RewardItems.Count > 0) ? questConfig.RewardItems[currentIconIndex % questConfig.RewardItems.Count].Prefab : questConfig.RewardItem); string text3 = ((questConfig.RewardItems != null && questConfig.RewardItems.Count > 0) ? string.Join(", ", questConfig.RewardItems.Select((QuestRequirement x) => $"{QuestUtils.GetItemName(x.Prefab)} x{x.Amount}")) : $"{QuestUtils.GetItemName(questConfig.RewardItem)} x{questConfig.RewardAmount}"); string text4 = text3; if (questConfig.ExpReward > 0) { text4 += $" | <color=#00BFFF>+{questConfig.ExpReward} XP</color>"; } infoText.text = string.Concat("<size=26><color=", rarityColor, "><b>", questConfig.Title, "</b></color></size>\n", text, "<i>", questConfig.Goal, "</i>\n", text2, "\n<color=#FFD700><b>" + L("sq_reward", "REWARD") + ":</b></color> ", text4); UpdateHUD(); } public static void UpdateHUD() { if (!hudAttachedToMinimap) { TryAttachHudToMinimap(); } if ((Object)(object)hudPanel == (Object)null) { return; } if (SimpleQuestPro.trackedQuests == null || SimpleQuestPro.trackedQuests.Count == 0 || (Object)(object)Player.m_localPlayer == (Object)null) { hudPanel.SetActive(false); return; } string text = ""; foreach (string id in SimpleQuestPro.trackedQuests.ToList()) { QuestConfig questConfig = SimpleQuestPro.Instance.serverQuests.Quests.FirstOrDefault((QuestConfig x) => x.ID.Equals(id, StringComparison.OrdinalIgnoreCase)); if (questConfig == null) { continue; } if (SimpleQuestPro.Instance.completedQuests.Contains(questConfig.ID)) { SimpleQuestPro.trackedQuests.Remove(id); continue; } text = text + "<b><color=" + QuestUtils.GetRarityColor(questConfig.Rarity) + ">" + questConfig.Title + "</color></b>\n"; if (questConfig.Reqs != null) { foreach (QuestRequirement req in questConfig.Reqs) { int itemCount = QuestUtils.GetItemCount(req.Prefab); string text2 = ((itemCount >= req.Amount) ? "#00FF00" : "white"); text += $"<b> • {QuestUtils.GetItemName(req.Prefab)}: <color={text2}>{itemCount}/{req.Amount}</color></b>\n"; } } if (questConfig.KillReqs != null) { foreach (QuestRequirement i in questConfig.KillReqs) { int num = SimpleQuestPro.playerKills.Where(delegate(KeyValuePair<string, int> x) { KeyValuePair<string, int> keyValuePair = x; return keyValuePair.Key.Equals(i.Prefab.Trim(), StringComparison.OrdinalIgnoreCase); }).Sum((KeyValuePair<string, int> x) => x.Value); string text3 = ((num >= i.Amount) ? "#00FF00" : "white"); text += string.Format("<b> • {0}: <color={1}>{2}/{3}</color></b>\n", Localization.instance.Localize("$" + i.Prefab.Trim()), text3, num, i.Amount); } } text += "\n"; } if (!string.IsNullOrEmpty(text)) { hudText.text = text; hudPanel.SetActive(true); } else { hudPanel.SetActive(false); } } public static void SetRewardIcon(string prefabName) { if (!((Object)(object)rewardIcon == (Object)null) && !string.IsNullOrEmpty(prefabName)) { ZNetScene instance = ZNetScene.instance; ItemDrop val; if ((Object)(object)instance == (Object)null) { val = null; } else { GameObject prefab = instance.GetPrefab(prefabName); val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null); } ItemDrop val2 = val; if ((Object)(object)val2 != (Object)null) { rewardIcon.sprite = val2.m_itemData.GetIcon(); ((Component)rewardIcon).gameObject.SetActive(true); } else { ((Component)rewardIcon).gameObject.SetActive(false); } } } } public static class QuestUtils { public const int VanillaPlayerInventoryWidth = 8; public const int VanillaPlayerInventoryHeight = 4; public static List<QuestConfig> GetVisibleQuests() { if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)SimpleQuestPro.Instance == (Object)null) { return new List<QuestConfig>(); } if (QuestUI.showHistoryMode) { return SimpleQuestPro.Instance.serverQuests.Quests.Where((QuestConfig q) => SimpleQuestPro.Instance.completedQuests.Contains(q.ID)).ToList(); } return SimpleQuestPro.Instance.serverQuests.Quests.Where((QuestConfig q) => (string.IsNullOrEmpty(q.PreReqID) || SimpleQuestPro.Instance.completedQuests.Contains(q.PreReqID)) && !SimpleQuestPro.Instance.completedQuests.Contains(q.ID)).ToList(); } public static string GetRarityColor(string rarity) { if (string.IsNullOrEmpty(rarity)) { return "#4d2600"; } return rarity.ToLower() switch { "mythic" => "#FF4500", "legendary" => "#FFD700", "epic" => "#9400D3", "rare" => "#1E90FF", "common" => "#696969", _ => "#4d2600", }; } public static int GetItemCount(string prefab) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return 0; } return (from x in ((Humanoid)localPlayer).GetInventory().GetAllItems() where (Object)(object)x.m_dropPrefab != (Object)null && string.Equals(((Object)x.m_dropPrefab).name, prefab, StringComparison.OrdinalIgnoreCase) select x).Sum((ItemData x) => x.m_stack); } public static string GetItemName(string prefab) { if (string.IsNullOrEmpty(prefab)) { return ""; } string[] array = new string[3] { "$item_" + prefab.ToLower(), "$" + prefab, "$" + prefab.ToLower() }; foreach (string text in array) { string text2 = Localization.instance.Localize(text); if (!text2.StartsWith("$")) { return text2; } } return prefab; } public static void PlaySfx(string sfxName) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null)) { GameObject prefab = ZNetScene.instance.GetPrefab(sfxName); if ((Object)(object)prefab == (Object)null) { prefab = ZNetScene.instance.GetPrefab("sfx_gui_click"); } if ((Object)(object)prefab != (Object)null) { Object.Instantiate<GameObject>(prefab, ((Component)Utils.GetMainCamera()).transform.position, Quaternion.identity); } } } public static int CountVanillaEmptyInventorySlots(Inventory inventory) { if (inventory == null) { return 0; } int num = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 8; j++) { if (inventory.GetItemAt(j, i) == null) { num++; } } } return num; } public static int CountSlotsFreedByTurningInRequirements(QuestConfig quest, Inventory inventory) { if (quest == null || inventory == null || quest.Reqs == null) { return 0; } int num = 0; foreach (QuestRequirement questRequirement in quest.Reqs) { int num2 = questRequirement.Amount; List<ItemData> list = (from x in inventory.GetAllItems() where (Object)(object)x.m_dropPrefab != (Object)null && string.Equals(((Object)x.m_dropPrefab).name, questRequirement.Prefab, StringComparison.OrdinalIgnoreCase) select x).ToList(); int num3 = list.Count - 1; while (num3 >= 0 && num2 > 0) { int num4 = Math.Min(list[num3].m_stack, num2); num2 -= num4; if (num4 >= list[num3].m_stack) { num++; } num3--; } } return num; } public static int CountItemRewardLines(QuestConfig quest) { if (quest == null) { return 0; } if (quest.RewardItems != null && quest.RewardItems.Count > 0) { return quest.RewardItems.Count((QuestRequirement reward) => !string.IsNullOrEmpty(reward.Prefab) && reward.Amount > 0); } return (!string.IsNullOrEmpty(quest.RewardItem) && quest.RewardAmount > 0) ? 1 : 0; } public static bool HasEnoughVanillaInventoryForRewards(QuestConfig quest, Inventory inventory, bool includeSlotsFreedByRequirements) { int num = CountItemRewardLines(quest); if (num <= 0) { return true; } int num2 = CountVanillaEmptyInventorySlots(inventory); if (includeSlotsFreedByRequirements) { num2 += CountSlotsFreedByTurningInRequirements(quest, inventory); } return num2 >= num; } public static void ShowInsufficientInventoryWarning() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { string text = Localization.instance.Localize("$sq_inventory_warning"); if (string.IsNullOrEmpty(text) || text == "$sq_inventory_warning") { text = "<color=yellow>Clear space in your inventory before claiming this quest reward.</color>"; } ((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null); } } public static bool TryGrantQuestRewards(QuestConfig quest, Inventory inventory) { if (quest == null || inventory == null) { return true; } if (CountItemRewardLines(quest) > 0 && !HasEnoughVanillaInventoryForRewards(quest, inventory, includeSlotsFreedByRequirements: false)) { return false; } if (quest.RewardItems != null && quest.RewardItems.Count > 0) { foreach (QuestRequirement rewardItem in quest.RewardItems) { if (!string.IsNullOrEmpty(rewardItem.Prefab) && rewardItem.Amount > 0 && inventory.AddItem(rewardItem.Prefab, rewardItem.Amount, 1, 0, 0L, "", false) == null) { return false; } } } else if (!string.IsNullOrEmpty(quest.RewardItem) && quest.RewardAmount > 0 && inventory.AddItem(quest.RewardItem, quest.RewardAmount, 1, 0, 0L, "", false) == null) { return false; } return true; } public static void AddExp(int amount) { if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } try { if (!Chainloader.PluginInfos.ContainsKey("WackyMole.EpicMMOSystem")) { return; } Type type = ((object)Chainloader.PluginInfos["WackyMole.EpicMMOSystem"].Instance).GetType().Assembly.GetType("EpicMMOSystem.LevelSystem"); if (type == null) { return; } PropertyInfo property = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); object obj = ((property != null) ? property.GetValue(null) : null); if (obj == null) { return; } MethodInfo method = type.GetMethod("AddExp", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 2) { object obj2 = ((parameters[0].ParameterType == typeof(Player)) ? Player.m_localPlayer : Convert.ChangeType(amount, parameters[0].ParameterType)); object obj3 = ((parameters[1].ParameterType == typeof(Player)) ? Player.m_localPlayer : Convert.ChangeType(amount, parameters[1].ParameterType)); method.Invoke(obj, new object[2] { obj2, obj3 }); } else if (parameters.Length == 1) { object obj4 = Convert.ChangeType(amount, parameters[0].ParameterType); method.Invoke(obj, new object[1] { obj4 }); } } } catch { } } } [BepInPlugin("com.mmoheim.simplequest", "MMOHeim SimpleQuest", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SimpleQuestPro : BaseUnityPlugin { [CompilerGenerated] private sealed class <OnClientQuestRequest>d__16 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SimpleQuestPro <>4__this; public long sender; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <OnClientQuestRequest>d__16(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown int num = <>1__state; SimpleQuestPro simpleQuestPro = <>4__this; if (num != 0) { return false; } <>1__state = -1; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && simpleQuestPro.questSyncRPC != null) { ZPackage val = new ZPackage(); val.Write(RawServerJson ?? string.Empty); simpleQuestPro.questSyncRPC.SendPackage(sender, val); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <OnServerQuestReceived>d__17 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ZPackage package; public SimpleQuestPro <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <OnServerQuestReceived>d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; SimpleQuestPro simpleQuestPro = <>4__this; if (num != 0) { return false; } <>1__state = -1; if (package != null) { try { string text = package.ReadString(); if (!string.IsNullOrEmpty(text)) { RawServerJson = text; simpleQuestPro.serverQuests = JsonConvert.DeserializeObject<QuestList>(text) ?? new QuestList(); if ((Object)(object)QuestUI.window != (Object)null) { QuestUI.UpdateUI(); } QuestUI.UpdateHUD(); } } catch (Exception ex) { ((BaseUnityPlugin)simpleQuestPro).Logger.LogError((object)("Failed to apply synced quest data: " + ex.Message)); } } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string LogPrefix = "[MMOHeim SimpleQuest] "; public const string ModGUID = "com.mmoheim.simplequest"; public const string ModName = "MMOHeim SimpleQuest"; public const string ModVersion = "1.0.0"; public const string ConfigFolderName = "MMOHeim SimpleQuest"; public static SimpleQuestPro Instance; private ConfigEntry<KeyCode> questKey; public static ConfigEntry<float> TrackerPositionX; public static ConfigEntry<float> TrackerPositionY; public QuestList serverQuests = new QuestList(); public HashSet<string> completedQuests = new HashSet<string>(); public static Dictionary<string, int> playerKills = new Dictionary<string, int>(); public static HashSet<string> trackedQuests = new HashSet<string>(); private CustomRPC questSyncRPC; private static string RawServerJson = string.Empty; private bool isFirstSpawn = true; public bool IsWindowActive() { if ((Object)(object)QuestUI.window != (Object)null) { return QuestUI.window.activeSelf; } return false; } private void Awake() { //IL_000b: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //IL_00b9: Expected O, but got Unknown Instance = this; new Harmony("com.mmoheim.simplequest").PatchAll(); LoadLocalization(); questKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "QuestKey", (KeyCode)108, "Quest journal key."); TrackerPositionX = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "TrackerPositionX", -18f, "Saved HUD tracker X anchored position."); TrackerPositionY = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "TrackerPositionY", -10f, "Saved HUD tracker Y anchored position."); EnsureQuestsFile(); LoadQuestsLocal(); questSyncRPC = NetworkManager.Instance.AddRPC("QuestSync", new CoroutineHandler(OnClientQuestRequest), new CoroutineHandler(OnServerQuestReceived)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"MMOHeim SimpleQuest version 1.0.0"); } private void Update() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { isFirstSpawn = true; return; } if (isFirstSpawn) { isFirstSpawn = false; LoadProgress(); LoadQuestsLocal(); if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { questSyncRPC.SendPackage(ZNet.instance.GetServerPeer().m_uid, new ZPackage()); } } if (IsWindowActive()) { if (Input.GetKeyDown((KeyCode)9) || Input.GetKeyDown((KeyCode)27)) { ToggleUI(); return; } UpdateIconSlideshow(); float axis = Input.GetAxis("Mouse ScrollWheel"); if (axis != 0f) { int count = QuestUtils.GetVisibleQuests().Count; if (count > 0) { if (axis > 0f) { QuestUI.currentIndex = (QuestUI.currentIndex - 1 + count) % count; } else { QuestUI.currentIndex = (QuestUI.currentIndex + 1) % count; } QuestUI.currentIconIndex = 0; QuestUI.UpdateUI(); QuestUtils.PlaySfx("sfx_book_page"); } } } if ((Object)(object)QuestUI.hudPanel != (Object)null) { bool flag = !IsWindowActive() && !QuestUI.showHistoryMode && trackedQuests.Count > 0; QuestUI.hudPanel.SetActive(flag); if (flag) { QuestUI.SetTrackerInteractionEnabled((Object)(object)Menu.instance != (Object)null && Menu.IsVisible()); } } if (!Chat.instance.HasFocus() && !InventoryGui.IsVisible() && Input.GetKeyDown(questKey.Value)) { ToggleUI(); } } private void UpdateIconSlideshow() { List<QuestConfig> visibleQuests = QuestUtils.GetVisibleQuests(); if (visibleQuests.Count == 0) { return; } QuestConfig questConfig = visibleQuests[Math.Min(QuestUI.currentIndex, visibleQuests.Count - 1)]; if (questConfig.RewardItems != null && questConfig.RewardItems.Count > 1) { QuestUI.iconTimer += Time.deltaTime; if (QuestUI.iconTimer >= 2f) { QuestUI.iconTimer = 0f; QuestUI.currentIconIndex = (QuestUI.currentIconIndex + 1) % questConfig.RewardItems.Count; QuestUI.SetRewardIcon(questConfig.RewardItems[QuestUI.currentIconIndex].Prefab); } } } public void ToggleUI() { if ((Object)(object)QuestUI.window == (Object)null) { QuestUI.CreateUI(); if ((Object)(object)QuestUI.window == (Object)null) { QuestUI.CleanupUI(); ((BaseUnityPlugin)this).Logger.LogWarning((object)"[MMOHeim SimpleQuest] ToggleUI aborted: QuestUI.CreateUI could not create the window yet."); return; } } bool flag = !QuestUI.window.activeSelf; if (flag) { QuestUI.showHistoryMode = false; QuestUI.currentIndex = 0; QuestUI.UpdateUI(); QuestUtils.PlaySfx("sfx_gui_mouse_over"); } else { SaveProgress(); QuestUtils.PlaySfx("sfx_gui_mouse_over"); } QuestUI.window.SetActive(flag); GUIManager.BlockInput(flag); Cursor.visible = flag; Cursor.lockState = (CursorLockMode)((!flag) ? 1 : 0); } public void CompleteQuest() { List<QuestConfig> visibleQuests = QuestUtils.GetVisibleQuests(); if (visibleQuests.Count == 0) { return; } QuestConfig questConfig = visibleQuests[QuestUI.currentIndex]; if (completedQuests.Contains(questConfig.ID)) { return; } Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory(); if (questConfig.Reqs != null) { foreach (QuestRequirement req in questConfig.Reqs) { if (QuestUtils.GetItemCount(req.Prefab) < req.Amount) { return; } } } if (questConfig.KillReqs != null) { foreach (QuestRequirement i in questConfig.KillReqs) { if (playerKills.Where(delegate(KeyValuePair<string, int> x) { KeyValuePair<string, int> keyValuePair = x; return keyValuePair.Key.Equals(i.Prefab.Trim(), StringComparison.OrdinalIgnoreCase); }).Sum((KeyValuePair<string, int> x) => x.Value) < i.Amount) { return; } } } if (!QuestUtils.HasEnoughVanillaInventoryForRewards(questConfig, inventory, includeSlotsFreedByRequirements: true)) { QuestUtils.ShowInsufficientInventoryWarning(); return; } if (questConfig.Reqs != null) { foreach (QuestRequirement req2 in questConfig.Reqs) { int num = req2.Amount; List<ItemData> list = inventory.GetAllItems().ToList(); for (int num2 = list.Count - 1; num2 >= 0; num2--) { if ((Object)(object)list[num2].m_dropPrefab != (Object)null && string.Equals(((Object)list[num2].m_dropPrefab).name, req2.Prefab, StringComparison.OrdinalIgnoreCase)) { int num3 = Math.Min(list[num2].m_stack, num); ItemData obj = list[num2]; obj.m_stack -= num3; num -= num3; if (list[num2].m_stack <= 0) { inventory.RemoveItem(list[num2]); } if (num <= 0) { break; } } } } } if (!QuestUtils.HasEnoughVanillaInventoryForRewards(questConfig, inventory, includeSlotsFreedByRequirements: false)) { QuestUtils.ShowInsufficientInventoryWarning(); return; } if (!QuestUtils.TryGrantQuestRewards(questConfig, inventory)) { QuestUtils.ShowInsufficientInventoryWarning(); return; } if (questConfig.ExpReward > 0) { QuestUtils.AddExp(questConfig.ExpReward); } completedQuests.Add(questConfig.ID); SaveProgress(); QuestUI.UpdateUI(); QuestUtils.PlaySfx("sfx_coins_up"); ((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$sq_success"), 0, (Sprite)null); } private void LoadLocalization() { //IL_016f: Expected O, but got Unknown try { string text = Path.Combine(GetTranslationsDirectory(), "English.json"); Debug.Log((object)("[MMOHeim SimpleQuest] Loading forced English localization from: " + text)); if (!File.Exists(text)) { Debug.LogError((object)("[MMOHeim SimpleQuest] English localization file not found: " + text)); return; } Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(text)); if (dictionary == null) { Debug.LogError((object)("[MMOHeim SimpleQuest] English localization file is empty or invalid JSON object: " + text)); return; } foreach (KeyValuePair<string, string> item in new Dictionary<string, string> { { "sq_track", "TRACK" }, { "sq_untrack", "UNTRACK" }, { "sq_no_history", "No quest history yet." }, { "sq_inventory_warning", "<color=yellow>Clear space in your inventory before claiming this quest reward.</color>" } }) { if (!dictionary.ContainsKey(item.Key)) { dictionary[item.Key] = item.Value; } } foreach (KeyValuePair<string, string> item2 in dictionary) { LocalizationManager.Instance.AddToken(item2.Key, item2.Value, false); } Debug.Log((object)$"[MMOHeim SimpleQuest] Loaded {dictionary.Count} localization tokens from forced English file."); } catch (IOException ex) { Debug.LogError((object)("[MMOHeim SimpleQuest] I/O error while loading English localization: " + ex.Message)); } catch (JsonException val) { JsonException val2 = val; Debug.LogError((object)("[MMOHeim SimpleQuest] JSON parse error while loading English localization: " + ((Exception)(object)val2).Message)); } catch (Exception ex2) { Debug.LogError((object)("[MMOHeim SimpleQuest] Unexpected localization load error: " + ex2)); } } private string GetPluginDirectory() { return Path.GetDirectoryName(typeof(SimpleQuestPro).Assembly.Location) ?? Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath; } private string GetTranslationsDirectory() { return Path.Combine(GetPluginDirectory(), "translations"); } private string GetConfigDataDirectory() { return Path.Combine(Paths.ConfigPath, "MMOHeim SimpleQuest"); } private void EnsureConfigDataDirectory() { Directory.CreateDirectory(GetConfigDataDirectory()); } private string GetQuestsFilePath() { return Path.Combine(GetConfigDataDirectory(), "quests.json"); } private string GetBundledQuestsFilePath() { return Path.Combine(GetPluginDirectory(), "Quests", "quests.json"); } private void EnsureQuestsFile() { EnsureConfigDataDirectory(); string questsFilePath = GetQuestsFilePath(); if (!File.Exists(questsFilePath)) { string bundledQuestsFilePath = GetBundledQuestsFilePath(); if (File.Exists(bundledQuestsFilePath)) { File.Copy(bundledQuestsFilePath, questsFilePath); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[MMOHeim SimpleQuest] Created quests.json in config from bundled default."); } else { File.WriteAllText(questsFilePath, "{\"Quests\":[]}"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[MMOHeim SimpleQuest] Created empty quests.json in config."); } } } private void LoadQuestsLocal() { EnsureQuestsFile(); string questsFilePath = GetQuestsFilePath(); if (File.Exists(questsFilePath)) { RawServerJson = File.ReadAllText(questsFilePath); serverQuests = JsonConvert.DeserializeObject<QuestList>(RawServerJson) ?? new QuestList(); } } [IteratorStateMachine(typeof(<OnClientQuestRequest>d__16))] private IEnumerator OnClientQuestRequest(long sender, ZPackage package) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <OnClientQuestRequest>d__16(0) { <>4__this = this, sender = sender }; } [IteratorStateMachine(typeof(<OnServerQuestReceived>d__17))] private IEnumerator OnServerQuestReceived(long sender, ZPackage package) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <OnServerQuestReceived>d__17(0) { <>4__this = this, package = package }; } private string GetProgressFilePath(string playerName) { return Path.Combine(GetConfigDataDirectory(), "progress_" + playerName + ".sav"); } private void MigrateLegacyProgressIfNeeded(string playerName) { string progressFilePath = GetProgressFilePath(playerName); if (!File.Exists(progressFilePath)) { string text = Path.Combine(Paths.ConfigPath, "SimpleQuest", "progress_" + playerName + ".sav"); if (File.Exists(text)) { EnsureConfigDataDirectory(); File.Copy(text, progressFilePath); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[MMOHeim SimpleQuest] Migrated progress save to config folder."); } } } private void LoadProgress() { string playerName = Player.m_localPlayer.GetPlayerName(); MigrateLegacyProgressIfNeeded(playerName); string progressFilePath = GetProgressFilePath(playerName); if (File.Exists(progressFilePath)) { string[] source = File.ReadAllLines(progressFilePath); completedQuests = new HashSet<string>(source.Where((string l) => !l.StartsWith("KILLS:"))); string text = source.FirstOrDefault((string l) => l.StartsWith("KILLS:")); if (text != null) { playerKills = JsonConvert.DeserializeObject<Dictionary<string, int>>(text.Replace("KILLS:", "")) ?? new Dictionary<string, int>(); } } } private void SaveProgress() { EnsureConfigDataDirectory(); string progressFilePath = GetProgressFilePath(Player.m_localPlayer.GetPlayerName()); List<string> list = completedQuests.ToList(); list.Add("KILLS:" + JsonConvert.SerializeObject((object)playerKills)); File.WriteAllLines(progressFilePath, list); } public Vector2 GetSavedTrackerPosition(Vector2 fallback) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) return new Vector2((TrackerPositionX != null) ? TrackerPositionX.Value : fallback.x, (TrackerPositionY != null) ? TrackerPositionY.Value : fallback.y); } public void SaveTrackerPosition(Vector2 anchoredPosition) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (TrackerPositionX != null) { TrackerPositionX.Value = anchoredPosition.x; } if (TrackerPositionY != null) { TrackerPositionY.Value = anchoredPosition.y; } ((BaseUnityPlugin)this).Config.Save(); } } [HarmonyPatch(typeof(Character), "ApplyDamage")] public static class UniversalKillPatch { private static void Postfix(Character __instance, HitData hit) { if ((Object)(object)__instance == (Object)null || __instance.IsPlayer() || !(__instance.GetHealth() <= 0f)) { return; } string prefabName = Utils.GetPrefabName(((Component)__instance).gameObject).Trim(); if (!SimpleQuestPro.playerKills.ContainsKey(prefabName)) { SimpleQuestPro.playerKills[prefabName] = 0; } SimpleQuestPro.playerKills[prefabName]++; if ((Object)(object)SimpleQuestPro.Instance != (Object)null) { foreach (QuestConfig quest in SimpleQuestPro.Instance.serverQuests.Quests) { if (SimpleQuestPro.Instance.completedQuests.Contains(quest.ID)) { continue; } QuestRequirement questRequirement = quest.KillReqs?.FirstOrDefault((QuestRequirement k) => k.Prefab.Trim().Equals(prefabName, StringComparison.OrdinalIgnoreCase)); if (questRequirement != null) { int num = SimpleQuestPro.playerKills[prefabName]; string arg = Localization.instance.Localize("$" + prefabName); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)1, $"<b><color=#FFD700>{arg}: {num} / {questRequirement.Amount}</color></b>", 0, (Sprite)null); } } } if (SimpleQuestPro.Instance.IsWindowActive()) { QuestUI.UpdateUI(); } } QuestUI.UpdateHUD(); } }