using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UltraAchievementsRevamped.Core.Achievements;
using UltraAchievementsRevamped.Core.UI;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("UltraAchievementsRevamped.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Core library for UltraAchievements")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+53de7905e782c38379c5254ecd06ea62b5c9c4ec")]
[assembly: AssemblyProduct("UltraAchievementsRevamped.Core")]
[assembly: AssemblyTitle("UltraAchievementsRevamped.Core")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 UltraAchievementsRevamped.Core
{
internal static class Assets
{
internal static AchievementPopUp AchievementPopUpPrefab;
internal static AchievementPanel AchievementPanelPrefab;
public static string AssetPath => Path.Combine(ModFolder, "Assets");
private static string ModFolder => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
private static string CatalogPath => Path.Combine(AssetPath, "catalog_core.json");
internal static void LoadAssets()
{
//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_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
Addressables.LoadContentCatalogAsync(CatalogPath, true, (string)null).WaitForCompletion();
AchievementPopUpPrefab = Addressables.LoadAssetAsync<GameObject>((object)"UltraAchievementsCore/Achievement Overlay.prefab").WaitForCompletion().GetComponent<AchievementPopUp>();
AchievementPanelPrefab = Addressables.LoadAssetAsync<GameObject>((object)"UltraAchievementsCore/Achievement Panel.prefab").WaitForCompletion().GetComponent<AchievementPanel>();
}
}
[BepInPlugin("protract.ultrakill.ultra_achievements_core", "UltraAchievementsRevamped.Core", "2.0.0")]
public class Plugin : BaseUnityPlugin
{
public static class PluginInfo
{
public const string Name = "UltraAchievementsRevamped.Core";
public const string Guid = "protract.ultrakill.ultra_achievements_core";
public const string Version = "2.0.0";
}
internal static ManualLogSource Logger;
private void Awake()
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
Logger = ((BaseUnityPlugin)this).Logger;
Logger.LogInfo((object)"UltraAchievementsRevamped.Core 2.0.0 has loaded!");
new Harmony("protract.ultrakill.ultra_achievements_core").PatchAll();
Assets.LoadAssets();
}
}
}
namespace UltraAchievementsRevamped.Core.UI
{
[HarmonyPatch]
public class AchievementPanel : MonoBehaviour
{
[SerializeField]
private GameObject modButtonTemplate;
[SerializeField]
private GameObject modPanelTemplate;
[SerializeField]
private GameObject achievementTemplate;
[SerializeField]
private ShopButton backButton;
[SerializeField]
private int itemsPerPage;
private readonly List<GameObject> modButtons = new List<GameObject>();
private readonly List<Button> pageButtons = new List<Button>();
private readonly List<GameObject> modPanels = new List<GameObject>();
private void Start()
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Expected O, but got Unknown
foreach (Transform item in ((Component)this).transform.Find("Left Panel/Buttons/Page Buttons"))
{
Button component = ((Component)item).GetComponent<Button>();
if ((Object)(object)component != (Object)null)
{
pageButtons.Add(component);
}
}
for (int i = 0; i < pageButtons.Count; i++)
{
int pageIndex = i;
((UnityEvent)pageButtons[i].onClick).AddListener((UnityAction)delegate
{
GoToPage(pageIndex);
});
}
foreach (var (modName, achievements) in AchievementManager.ModNameToAchInfo)
{
CreateModButton(modName, achievements);
}
GoToPage(0);
}
private void CreateModButton(string modName, List<AchievementInfo> achievements)
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
Transform val = ((Component)this).transform.Find("Left Panel/Buttons/Mod Buttons");
GameObject val2 = Object.Instantiate<GameObject>(modButtonTemplate, val);
val2.GetComponentInChildren<TMP_Text>().text = modName;
int panelIndex = modButtons.Count;
((UnityEvent)val2.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
{
SelectModPanel(panelIndex);
});
CreateModPanel(modName, achievements);
modButtons.Add(val2);
}
private void CreateModPanel(string modName, List<AchievementInfo> achievements)
{
GameObject val = Object.Instantiate<GameObject>(modPanelTemplate, modPanelTemplate.transform.parent);
((Component)val.transform.Find("Title")).GetComponent<TMP_Text>().text = modName;
val.SetActive(false);
Transform val2 = val.transform.Find("Achievement List/Viewport/Content");
foreach (AchievementInfo achievement in achievements)
{
if (!achievement.IsHidden || achievement.IsComplete)
{
GameObject val3 = Object.Instantiate<GameObject>(achievementTemplate, val2);
val3.SetActive(true);
((Component)val3.transform.Find("Name")).GetComponent<TMP_Text>().text = achievement.DisplayName;
((Component)val3.transform.Find("Description")).GetComponent<TMP_Text>().text = achievement.Description;
if (achievement.IsComplete)
{
((Component)val3.transform.Find("Icon")).GetComponent<Image>().sprite = achievement.Icon;
}
}
}
modPanels.Add(val);
}
private void SelectModPanel(int index)
{
for (int i = 0; i < modPanels.Count; i++)
{
modPanels[i].SetActive(i == index);
}
}
private void GoToPage(int pageIndex)
{
//IL_00a9: 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_00df: Unknown result type (might be due to invalid IL or missing references)
if (itemsPerPage <= 0)
{
Plugin.Logger.LogError((object)"itemsPerPage on AchievementPanel must be greater than zero");
return;
}
int num = pageIndex * itemsPerPage;
int num2 = num + itemsPerPage;
for (int i = 0; i < modButtons.Count; i++)
{
modButtons[i].SetActive(i >= num && i < num2);
}
int num3 = Mathf.CeilToInt((float)modButtons.Count / (float)itemsPerPage);
for (int j = 0; j < pageButtons.Count; j++)
{
if (j >= num3)
{
((Selectable)pageButtons[j]).interactable = false;
((Graphic)((Component)pageButtons[j]).GetComponent<Image>()).color = Color.white;
}
else if (j == pageIndex)
{
((Selectable)pageButtons[j]).interactable = true;
((Graphic)((Component)pageButtons[j]).GetComponent<Image>()).color = Color.red;
}
else
{
((Selectable)pageButtons[j]).interactable = true;
((Graphic)((Component)pageButtons[j]).GetComponent<Image>()).color = Color.white;
}
}
}
[HarmonyPatch(typeof(ShopZone), "Start")]
[HarmonyPostfix]
private static void TerminalSpawnPatch(ShopZone __instance)
{
if (!(((Object)__instance).name != "Shop"))
{
GameObject gameObject = ((Component)((Component)__instance).transform.Find("Canvas/Background/Main Panel")).gameObject;
AchievementPanel achievementPanel = Object.Instantiate<AchievementPanel>(Assets.AchievementPanelPrefab, gameObject.transform);
GameObject gameObject2 = ((Component)((Component)__instance).transform.Find("Canvas/Background/Icon")).gameObject;
((Selectable)gameObject2.AddComponent<Button>()).interactable = true;
((Graphic)gameObject2.GetComponent<Image>()).raycastTarget = true;
ShopButton val = gameObject2.AddComponent<ShopButton>();
val.toActivate = (GameObject[])(object)new GameObject[1] { ((Component)achievementPanel).gameObject };
val.toDeactivate = Array.Empty<GameObject>();
val.clickSound = achievementPanel.backButton.clickSound;
}
}
}
public class AchievementPopUp : MonoBehaviour
{
[CompilerGenerated]
private sealed class <WaitAndDestroy>d__9 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public AchievementPopUp <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <WaitAndDestroy>d__9(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Expected O, but got Unknown
int num = <>1__state;
AchievementPopUp achievementPopUp = <>4__this;
switch (num)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = (object)new WaitForSeconds(10f);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
achievementPopUp.hudOpenEffect.Reverse(30f);
<>2__current = (object)new WaitForSeconds(1f);
<>1__state = 2;
return true;
case 2:
<>1__state = -1;
Object.Destroy((Object)(object)((Component)achievementPopUp).gameObject);
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();
}
}
[SerializeField]
private TMP_Text titleText;
[SerializeField]
private TMP_Text descriptionText;
[SerializeField]
private Image achievementIcon;
[SerializeField]
private AudioClip achievementSound;
[SerializeField]
private HudOpenEffect hudOpenEffect;
private const float DestroyDelay = 10f;
private const float HUDReverseSpeed = 30f;
private const float HUDReverseTime = 1f;
private void Start()
{
NewMovement instance = MonoSingleton<NewMovement>.Instance;
if (instance != null)
{
AudioSource component = ((Component)instance).GetComponent<AudioSource>();
if (component != null)
{
component.PlayOneShot(achievementSound);
}
}
((MonoBehaviour)this).StartCoroutine(WaitAndDestroy());
}
[IteratorStateMachine(typeof(<WaitAndDestroy>d__9))]
private IEnumerator WaitAndDestroy()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <WaitAndDestroy>d__9(0)
{
<>4__this = this
};
}
internal static void CreateInstance(AchievementInfo achievementInfo, Transform parent)
{
AchievementPopUp achievementPopUp = Object.Instantiate<AchievementPopUp>(Assets.AchievementPopUpPrefab, parent);
achievementPopUp.titleText.text = achievementInfo.DisplayName;
achievementPopUp.descriptionText.text = achievementInfo.Description;
achievementPopUp.achievementIcon.sprite = achievementInfo.Icon;
}
}
}
namespace UltraAchievementsRevamped.Core.Achievements
{
public class AchievementInfo : ScriptableObject
{
[SerializeField]
private string id;
[SerializeField]
private string sourceMod;
[SerializeField]
private Sprite icon;
[SerializeField]
private string displayName;
[SerializeField]
[TextArea]
private string description;
[SerializeField]
private bool isHidden;
[NonSerialized]
internal bool IsComplete;
public string Id => id;
public string SourceMod => sourceMod;
public Sprite Icon => icon;
public string DisplayName => displayName;
public string Description => description;
public bool IsHidden => isHidden;
public static T Create<T>(string id, string sourceMod, Sprite icon, string displayName, string description, bool isHidden) where T : AchievementInfo
{
T val = ScriptableObject.CreateInstance<T>();
val.id = id;
val.sourceMod = sourceMod;
val.icon = icon;
val.displayName = displayName;
val.description = description;
val.isHidden = isHidden;
return val;
}
}
public static class AchievementManager
{
private const int SaveFormatVersion = 1;
private static Dictionary<string, (bool isComplete, int? progress)> _saveDataCache;
private static readonly Dictionary<string, AchievementInfo> IdToAchInfo = new Dictionary<string, AchievementInfo>();
private static string SavePath => Path.Combine(Application.persistentDataPath, "achievements.dat");
internal static Dictionary<string, List<AchievementInfo>> ModNameToAchInfo => (from info in IdToAchInfo.Values
group info by info.SourceMod).ToDictionary((IGrouping<string, AchievementInfo> grouping) => grouping.Key, (IGrouping<string, AchievementInfo> grouping) => grouping.ToList());
public static void RegisterAchievementInfos(IEnumerable<AchievementInfo> infos)
{
foreach (AchievementInfo info2 in infos)
{
if ((Object)(object)info2 == (Object)null)
{
Plugin.Logger.LogError((object)"Cannot register null achievement info");
continue;
}
if (IdToAchInfo.ContainsKey(info2.Id))
{
Plugin.Logger.LogError((object)("Achievement with id " + info2.Id + " has already been registered"));
continue;
}
if (info2 is ProgressiveAchievementInfo info)
{
RegisterProgressiveInfo(info);
}
else
{
RegisterInfo(info2);
}
Plugin.Logger.LogInfo((object)("Registered achievement with id " + info2.Id));
}
}
public static AchievementInfo GetAchievementInfo(string id)
{
if (!IdToAchInfo.TryGetValue(id, out var value))
{
Plugin.Logger.LogError((object)("Achievement " + id + " has not been registered"));
}
return value;
}
public static void MarkAchievementComplete(string id)
{
AchievementInfo achievementInfo = GetAchievementInfo(id);
if (!((Object)(object)achievementInfo == (Object)null) && !achievementInfo.IsComplete)
{
achievementInfo.IsComplete = true;
AchievementPopUp.CreateInstance(achievementInfo, null);
Plugin.Logger.LogInfo((object)("Marked achievement " + achievementInfo.Id + " as complete"));
SaveAchievementProgress();
}
}
public static void MarkAchievementComplete(AchievementInfo achievementInfo)
{
if ((Object)(object)achievementInfo == (Object)null)
{
Plugin.Logger.LogError((object)"Cannot mark null achievement info as complete");
}
else if (!achievementInfo.IsComplete)
{
achievementInfo.IsComplete = true;
AchievementPopUp.CreateInstance(achievementInfo, null);
Plugin.Logger.LogInfo((object)("Marked achievement " + achievementInfo.Id + " as complete"));
SaveAchievementProgress();
}
}
public static void AddProgressToAchievement(string id, int amount)
{
AchievementInfo achievementInfo = GetAchievementInfo(id);
if ((Object)(object)achievementInfo == (Object)null)
{
return;
}
if (achievementInfo is ProgressiveAchievementInfo progressiveAchievementInfo)
{
progressiveAchievementInfo.CurrentProgress += amount;
if (progressiveAchievementInfo.CurrentProgress >= progressiveAchievementInfo.MaxProgress)
{
MarkAchievementComplete(progressiveAchievementInfo);
}
else
{
SaveAchievementProgress();
}
}
else
{
Plugin.Logger.LogError((object)("Achievement " + id + " is not a progressive achievement"));
}
}
public static void AddProgressToAchievement(AchievementInfo achievementInfo, int amount)
{
if ((Object)(object)achievementInfo == (Object)null)
{
Plugin.Logger.LogError((object)"Cannot add progress to null progressive achievement info");
}
else if (achievementInfo is ProgressiveAchievementInfo progressiveAchievementInfo)
{
progressiveAchievementInfo.CurrentProgress += amount;
if (progressiveAchievementInfo.CurrentProgress >= progressiveAchievementInfo.MaxProgress)
{
MarkAchievementComplete(progressiveAchievementInfo);
}
else
{
SaveAchievementProgress();
}
}
else
{
Plugin.Logger.LogError((object)("Achievement " + achievementInfo.Id + " is not a progressive achievement"));
}
}
private static void RegisterInfo(AchievementInfo info)
{
if (_saveDataCache == null)
{
_saveDataCache = LoadAchievementProgress();
}
if (_saveDataCache.TryGetValue(info.Id, out (bool, int?) value))
{
(info.IsComplete, _) = value;
}
IdToAchInfo.Add(info.Id, info);
}
private static void RegisterProgressiveInfo(ProgressiveAchievementInfo info)
{
if (_saveDataCache == null)
{
_saveDataCache = LoadAchievementProgress();
}
if (_saveDataCache.TryGetValue(info.Id, out (bool, int?) value))
{
(info.IsComplete, _) = value;
if (value.Item2.HasValue)
{
info.CurrentProgress = value.Item2.Value;
}
}
IdToAchInfo.Add(info.Id, info);
}
private static void SaveAchievementProgress()
{
try
{
using BinaryWriter binaryWriter = new BinaryWriter(File.Open(SavePath, FileMode.Create));
binaryWriter.Write(1);
binaryWriter.Write(IdToAchInfo.Count);
foreach (var (value, achievementInfo2) in IdToAchInfo)
{
binaryWriter.Write(value);
binaryWriter.Write(achievementInfo2.IsComplete);
binaryWriter.Write(achievementInfo2 is ProgressiveAchievementInfo);
if (achievementInfo2 is ProgressiveAchievementInfo progressiveAchievementInfo)
{
binaryWriter.Write(progressiveAchievementInfo.CurrentProgress);
}
}
Plugin.Logger.LogInfo((object)$"Achievements saved at {Time.time}");
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)("Achievements could not be saved to " + SavePath + ": " + ex.Message));
}
}
private static Dictionary<string, (bool isComplete, int? progress)> LoadAchievementProgress()
{
Dictionary<string, (bool, int?)> dictionary = new Dictionary<string, (bool, int?)>();
if (!File.Exists(SavePath))
{
return dictionary;
}
try
{
using BinaryReader binaryReader = new BinaryReader(File.OpenRead(SavePath));
int num = binaryReader.ReadInt32();
if (num != 1)
{
Plugin.Logger.LogError((object)$"Achievements could not be loaded due to mismatched format versions: {num} vs {1}");
return dictionary;
}
int num2 = binaryReader.ReadInt32();
for (int i = 0; i < num2; i++)
{
string key = binaryReader.ReadString();
bool item = binaryReader.ReadBoolean();
int? item2 = (binaryReader.ReadBoolean() ? new int?(binaryReader.ReadInt32()) : null);
dictionary[key] = (item, item2);
}
return dictionary;
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)("Achievements could not be loaded from " + SavePath + ": " + ex.Message));
return dictionary;
}
}
}
public class ProgressiveAchievementInfo : AchievementInfo
{
[SerializeField]
private int maxProgress;
[NonSerialized]
internal int CurrentProgress;
public int MaxProgress => maxProgress;
public static ProgressiveAchievementInfo Create(string id, string sourceMod, Sprite icon, string displayName, string description, bool isHidden, int maxProgress)
{
ProgressiveAchievementInfo progressiveAchievementInfo = AchievementInfo.Create<ProgressiveAchievementInfo>(id, sourceMod, icon, displayName, description, isHidden);
progressiveAchievementInfo.maxProgress = maxProgress;
return progressiveAchievementInfo;
}
}
}