Decompiled source of ScoreLab v1.0.1
PCVR/Mods/ScoreLab.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BoneLib; using BoneLib.BoneMenu; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Bonelab; using Il2CppSLZ.Marrow; using Il2CppSLZ.Marrow.AI; using Il2CppSLZ.Marrow.Interaction; using Il2CppSLZ.Marrow.PuppetMasta; using Il2CppSLZ.Marrow.Utilities; using Il2CppSLZ.Marrow.Warehouse; using Il2CppSLZ.VRMK; using Il2CppSystem; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using NEP.ScoreLab; using NEP.ScoreLab.Audio; using NEP.ScoreLab.Core; using NEP.ScoreLab.Data; using NEP.ScoreLab.HUD; using NEP.ScoreLab.Menu; using NEP.ScoreLab.Patches; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Main), "ScoreLab", "1.0.0", "Not Enough Photons", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("ScoreLab")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0140fb38dafe5a3ef9669f29b961df65def51cb4")] [assembly: AssemblyProduct("ScoreLab")] [assembly: AssemblyTitle("ScoreLab")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.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 NEP.ScoreLab { public static class BuildInfo { public const string Name = "ScoreLab"; public const string Author = "Not Enough Photons"; public const string Company = "Not Enough Photons"; public const string Version = "1.0.0"; public const string DownloadLink = "https://thunderstore.io/c/bonelab/p/NotEnoughPhotons/ScoreLab"; } public class Main : MelonMod { internal static Instance Logger; public override void OnLateInitializeMelon() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown Logger = new Instance("ScoreLab"); Settings.CreatePreferences(); Hooks.Initialize(); Hooks.Game.OnMarrowGameStarted = (Action)Delegate.Combine(Hooks.Game.OnMarrowGameStarted, new Action(OnMarrowGameStarted)); Hooks.Game.OnMarrowSceneLoaded = (Action<MarrowSceneInfo>)Delegate.Combine(Hooks.Game.OnMarrowSceneLoaded, new Action<MarrowSceneInfo>(OnMarrowSceneLoaded)); HUDLoader.Initialize(); SLMenu.Initialize(); } public void OnMarrowGameStarted() { ScoreTracker.Initialize(); ValueManager.Initialize(); AudioManager.Initialize(); ScoreDirector.Patches.InitPatches(); } public void OnMarrowSceneLoaded(MarrowSceneInfo sceneInfo) { HUDManager.Initialize(); ScoreTracker.ResetAll(); } public override void OnUpdate() { ScoreTracker.Update(); } public override void OnDeinitializeMelon() { HUDManager.Uninitialize(); AudioManager.Uninitialize(); Settings.Save(); } } } namespace NEP.ScoreLab.Patches { public static class Hooks { public static class Game { public static Action OnMarrowGameStarted; public static Action<MarrowSceneInfo> OnMarrowSceneLoaded; private static MarrowSceneInfo _lastScene; private static MarrowSceneInfo _currentScene; private static MarrowSceneInfo _nextScene; public static void Initialize() { MarrowGame.RegisterOnReadyAction(Action.op_Implicit((Action)delegate { OnMarrowGameStarted?.Invoke(); })); Hooking.OnLevelLoaded += OnSceneMarrowLoaded; } private static void OnSceneMarrowLoaded(LevelInfo info) { //IL_000a: 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) MarrowSceneInfo currentScene = default(MarrowSceneInfo); currentScene.Barcode = info.barcode; currentScene.LevelTitle = info.title; currentScene.MarrowScene = ((CrateReferenceT<LevelCrate>)(object)info.levelReference).Crate.MainScene; _currentScene = currentScene; _lastScene = _currentScene; OnMarrowSceneLoaded?.Invoke(_currentScene); } } public static void Initialize() { Game.Initialize(); } } } namespace NEP.ScoreLab.Menu { public static class SLMenu { private static Page _hudPage; public static void Initialize() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) Page obj = Page.Root.CreatePage("Not Enough Photons", Color.white, 0, true).CreatePage("ScoreLab", Color.white, 0, true); _hudPage = obj.CreatePage("HUDs", Color.white, 0, true); obj.CreateFloat("HUD Distance", Color.white, 1.125f, 0.025f, 0f, 2f, (Action<float>)delegate(float value) { Settings.DistanceToCamera = value; }); obj.CreateEnum("Show HUD", Color.white, (Enum)Settings.HUDShowMode, (Action<Enum>)delegate(Enum value) { Settings.SetHUDShowMode((HUDShowMode)(object)value); }); for (int i = 0; i < HUDLoader.LoadedHUDManifests.Count; i++) { int index = i; JSONHUDManifest manifest = HUDLoader.LoadedHUDManifests[index]; _hudPage.CreateFunction(manifest.Name, Color.white, (Action)delegate { HUDManager.LoadHUD(manifest.Name); }).Logo = manifest.Logo; } } public static void RefreshHUDPage() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) _hudPage.RemoveAll(); for (int i = 0; i < HUDLoader.LoadedHUDManifests.Count; i++) { int index = i; JSONHUDManifest manifest = HUDLoader.LoadedHUDManifests[index]; _hudPage.CreateFunction(manifest.Name, Color.white, (Action)delegate { HUDManager.LoadHUD(manifest.Name); }).Logo = manifest.Logo; } } } } namespace NEP.ScoreLab.HUD { public enum HUDShowMode { Always, UpdateOnly, Never } [RegisterTypeInIl2Cpp] public class Module : MonoBehaviour { public enum UIModuleType { Main, Descriptor } public UIModuleType ModuleType; private bool _reachedDecay; private bool _reachedPostDecay; public PackedValue PackedValue => _packedValue; public virtual PackedValue.PackedType PackedType => PackedValue.PackedType.Base; public virtual bool CanDecay => (Object)(object)((Component)this).transform.Find("-Persist") == (Object)null; public float DecayTime => _decayTime; public float PostDecayTime => _postDecayTime; protected TextMeshProUGUI _title { get; private set; } protected TextMeshProUGUI _value { get; private set; } protected Slider _timeBar { get; private set; } protected PackedValue _packedValue { get; private set; } protected bool _canDecay { get; private set; } protected bool _decayed { get; private set; } protected float _decayTime { get; private set; } protected float _postDecayTime { get; private set; } protected float _tDecay { get; private set; } protected float _tPostDecay { get; private set; } private string Path_Root => ((Object)this).name; protected virtual string Path_TitleText => "Title"; protected virtual string Path_ValueText => "Value"; protected virtual string Path_TimeBar => "TimeBar"; public Module(IntPtr ptr) : base(ptr) { } public virtual void OnModuleEnable() { API.UI.OnModuleEnabled?.Invoke(this); } public virtual void OnModuleDisable() { API.UI.OnModuleDisabled?.Invoke(this); } public virtual void OnUpdate() { } public void AssignPackedData(PackedValue packedValue) { if (packedValue != null) { _packedValue = packedValue; if (_packedValue.DecayTime != 0f) { SetDecayTime(_packedValue.DecayTime); } } } public void SetDecayTime(float decayTime) { _decayTime = decayTime; _tDecay = _decayTime; } public void SetPostDecayTime(float postDecayTime) { _postDecayTime = postDecayTime; _tPostDecay = _postDecayTime; } public bool IsDecaying() { return _reachedDecay; } public bool IsDecayed() { return _reachedPostDecay; } protected void SetText(TextMeshProUGUI text, string value) { if (!((Object)(object)text == (Object)null)) { ((TMP_Text)text).text = value; } } protected void SetText(TextMeshProUGUI text, int value) { if (!((Object)(object)text == (Object)null)) { SetText(text, value.ToString()); } } protected void SetText(TextMeshProUGUI text, float value) { if (!((Object)(object)text == (Object)null)) { SetText(text, value.ToString()); } } protected void SetBarValue(Slider timeBar, float value) { timeBar.value = value; } protected void SetMaxValueToBar(Slider timeBar, float value) { if (!((Object)(object)timeBar == (Object)null)) { timeBar.maxValue = value; } } protected void UpdateDecay() { if (!CanDecay) { return; } if (_tDecay < 0f) { if (!_reachedDecay) { API.UI.OnModuleDecayed?.Invoke(this); _reachedDecay = true; } _tPostDecay -= Time.deltaTime; if (_tPostDecay < 0f) { if (!_reachedPostDecay) { API.UI.OnModulePostDecayed?.Invoke(this); _reachedPostDecay = true; } _tDecay = _decayTime; _tPostDecay = _postDecayTime; _reachedDecay = false; _reachedPostDecay = false; ((Component)this).gameObject.SetActive(false); } } else { _tDecay -= Time.deltaTime; } } private void Start() { Transform val = ((Component)this).transform.Find(Path_TitleText); Transform val2 = ((Component)this).transform.Find(Path_ValueText); Transform val3 = ((Component)this).transform.Find(Path_TimeBar); _title = ((val != null) ? ((Component)val).GetComponent<TextMeshProUGUI>() : null); _value = ((val2 != null) ? ((Component)val2).GetComponent<TextMeshProUGUI>() : null); _timeBar = ((val3 != null) ? ((Component)val3).GetComponent<Slider>() : null); } private void OnEnable() { OnModuleEnable(); } private void OnDisable() { OnModuleEnable(); } private void Update() { OnUpdate(); } } [RegisterTypeInIl2Cpp] public class ModuleAnimator : MonoBehaviour { public Animator Animator; private Module _module; public ModuleAnimator(IntPtr ptr) : base(ptr) { } private void Awake() { _module = ((Component)this).GetComponent<Module>(); Animator = ((Component)this).GetComponent<Animator>(); } private void OnEnable() { API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueTierReached, (Action<PackedValue>)delegate { OnTierReached(); }); API.UI.OnModuleDecayed = (Action<Module>)Delegate.Combine(API.UI.OnModuleDecayed, new Action<Module>(OnModuleDecayed)); } private void OnDisable() { API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueTierReached, (Action<PackedValue>)delegate { OnTierReached(); }); API.UI.OnModuleDecayed = (Action<Module>)Delegate.Remove(API.UI.OnModuleDecayed, new Action<Module>(OnModuleDecayed)); } private void PlayAnimation(string name) { if (!((Object)(object)Animator == (Object)null)) { Animator.Play(name, -1, 0f); } } private void OnModuleEnabled(Module module) { if (!((Object)(object)_module != (Object)(object)module)) { if (_module.ModuleType == Module.UIModuleType.Descriptor) { PlayAnimation("descriptor_show"); } else { PlayAnimation("show"); } } } private void OnTierReached() { PlayAnimation("tier_reached"); } private void OnModuleDecayed(Module module) { if (!((Object)(object)_module != (Object)(object)module)) { if (_module.ModuleType == Module.UIModuleType.Descriptor) { PlayAnimation("descriptor_hide"); } else { PlayAnimation("hide"); } } } } [RegisterTypeInIl2Cpp] public class MultiplierModule : Module { private float _currentValue; private float _targetValue; private float _rate; private PackedMultiplier _packedMultiplier => (PackedMultiplier)base._packedValue; public MultiplierModule(IntPtr ptr) : base(ptr) { } private void Awake() { if (((Object)this).name == "MultiplierDescriptor" || ((Object)this).name == "Descriptor") { ModuleType = UIModuleType.Descriptor; } } public override void OnModuleEnable() { base.OnModuleEnable(); if (base._packedValue == null || _packedMultiplier == null) { return; } if (ModuleType == UIModuleType.Main) { SetText(base._value, ScoreTracker.Multiplier + "x"); } else if (ModuleType == UIModuleType.Descriptor) { SetText(base._title, _packedMultiplier.Name); SetText(base._value, _packedMultiplier.Multiplier + "x"); } if ((Object)(object)base._timeBar != (Object)null) { if (_packedMultiplier.Condition != string.Empty) { ((Component)base._timeBar).gameObject.SetActive(false); return; } ((Component)base._timeBar).gameObject.SetActive(true); SetMaxValueToBar(base._timeBar, _packedMultiplier.DecayTime); SetBarValue(base._timeBar, _packedMultiplier.DecayTime); } } public override void OnModuleDisable() { } public override void OnUpdate() { if (ModuleType == UIModuleType.Main) { SetTweenValue(ScoreTracker.Multiplier); _currentValue = Mathf.MoveTowards(_currentValue, _targetValue, _rate * Time.unscaledDeltaTime); if (Mathf.Approximately(_currentValue, _targetValue)) { _currentValue = _targetValue; } SetText(base._value, _currentValue.ToString("F2")); } if (_packedMultiplier != null) { if (_packedMultiplier.condition != null) { if (!_packedMultiplier.condition()) { UpdateDecay(); } } else { UpdateDecay(); } } else { UpdateDecay(); } if ((Object)(object)base._timeBar != (Object)null) { SetBarValue(base._timeBar, base._tDecay); } } private void SetTweenValue(float value) { _targetValue = value; _rate = Mathf.Abs(_targetValue - _currentValue) / 1f; } } [RegisterTypeInIl2Cpp] public class ScoreModule : Module { private float _targetValue; private float _currentValue; private float _rate = 4f; private PackedScore _packedScore => (PackedScore)base._packedValue; public ScoreModule(IntPtr ptr) : base(ptr) { } private void Awake() { if (((Object)this).name == "ScoreDescriptor" || ((Object)this).name == "Descriptor") { ModuleType = UIModuleType.Descriptor; } } public override void OnModuleEnable() { base.OnModuleEnable(); if (ModuleType == UIModuleType.Main) { SetText(base._value, ScoreTracker.Score); } if (base._packedValue != null && ModuleType == UIModuleType.Descriptor) { SetText(base._title, _packedScore.Name); SetText(base._value, $"+{Mathf.RoundToInt((float)_packedScore.Score * ScoreTracker.Multiplier)}"); } } public override void OnModuleDisable() { } public override void OnUpdate() { UpdateDecay(); if (ModuleType == UIModuleType.Main) { SetTweenValue(ScoreTracker.Score); _currentValue = Mathf.MoveTowards(_currentValue, _targetValue, _rate * Time.unscaledDeltaTime); if (Mathf.Approximately(_currentValue, _targetValue)) { _currentValue = _targetValue; } SetText(base._value, _currentValue.ToString("N0")); } } private void SetTweenValue(int value) { _targetValue = value; _rate = Mathf.Abs(_targetValue - _currentValue) / 1f; } } [RegisterTypeInIl2Cpp] public class HUD : MonoBehaviour { public Transform followTarget; public Module ScoreModule { get; set; } public Module MultiplierModule { get; set; } public Module HighScoreModule { get; set; } public HUD(IntPtr ptr) : base(ptr) { } private void Awake() { if ((Object)(object)((Component)this).transform.Find("MainScore") != (Object)null) { ScoreModule = ((Component)((Component)this).transform.Find("MainScore")).GetComponent<ScoreModule>(); } if (Object.op_Implicit((Object)(object)((Component)this).transform.Find("MainMultiplier"))) { MultiplierModule = ((Component)((Component)this).transform.Find("MainMultiplier")).GetComponent<MultiplierModule>(); } } private void OnEnable() { UpdateModule(null); UpdateModule(null); API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAdded, new Action<PackedValue>(UpdateModule)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueTierReached, new Action<PackedValue>(UpdateModule)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAccumulated, new Action<PackedValue>(UpdateModule)); API.Value.OnValueRemoved = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueRemoved, new Action<PackedValue>(UpdateModule)); } private void OnDisable() { API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAdded, new Action<PackedValue>(UpdateModule)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueTierReached, new Action<PackedValue>(UpdateModule)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAccumulated, new Action<PackedValue>(UpdateModule)); API.Value.OnValueRemoved = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueRemoved, new Action<PackedValue>(UpdateModule)); } private void Start() { if ((Object)(object)Player.GetPhysicsRig() != (Object)null) { followTarget = ((Rig)Player.ControllerRig).m_head; } } private void FixedUpdate() { //IL_0015: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)followTarget == (Object)null)) { Vector3 position = Vector3.Lerp(((Component)this).transform.position, followTarget.position + followTarget.forward * Settings.DistanceToCamera, Settings.MovementSmoothness * Time.unscaledDeltaTime); Quaternion rotation = Quaternion.LookRotation(followTarget.forward); ((Component)this).transform.position = position; ((Component)this).transform.rotation = rotation; } } public void SetParent(Transform parent) { ((Component)this).transform.SetParent(parent); } public void SetScoreModule(Module module) { ScoreModule = module; } public void SetMultiplierModule(Module module) { MultiplierModule = module; } public void UpdateModule(PackedValue data) { if (data is PackedScore) { ScoreModule.AssignPackedData(data); ScoreModule.OnModuleEnable(); } else if (data is PackedMultiplier) { MultiplierModule.AssignPackedData(data); MultiplierModule.OnModuleEnable(); } } } [RegisterTypeInIl2Cpp] public class DescriptorList : MonoBehaviour { public List<Module> ActiveModules; public int count = 6; public List<Module> Modules; public PackedValue.PackedType packedType { get; set; } public GameObject ModulePrefab { get; set; } public DescriptorList(IntPtr ptr) : base(ptr) { } private void Awake() { Modules = new List<Module>(); ActiveModules = new List<Module>(); for (int i = 0; i < ((Component)this).transform.childCount; i++) { Transform child = ((Component)this).transform.GetChild(i); Modules.Add(((Component)child).GetComponent<Module>()); } if (((Object)this).name == "ScoreDescriptors") { packedType = PackedValue.PackedType.Score; } else if (((Object)this).name == "MultiplierDescriptors") { packedType = PackedValue.PackedType.Multiplier; } } private void OnEnable() { API.UI.OnModulePostDecayed = (Action<Module>)Delegate.Combine(API.UI.OnModulePostDecayed, (Action<Module>)delegate(Module item) { ActiveModules.Remove(item); }); API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAdded, new Action<PackedValue>(SetModuleActive)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAccumulated, new Action<PackedValue>(SetModuleActive)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueTierReached, new Action<PackedValue>(SetModuleActive)); } private void OnDisable() { API.UI.OnModulePostDecayed = (Action<Module>)Delegate.Remove(API.UI.OnModulePostDecayed, (Action<Module>)delegate(Module item) { ActiveModules.Remove(item); }); API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAdded, new Action<PackedValue>(SetModuleActive)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAccumulated, new Action<PackedValue>(SetModuleActive)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueTierReached, new Action<PackedValue>(SetModuleActive)); } public void SetPackedType(int packedType) { this.packedType = (PackedValue.PackedType)packedType; } public void SetModuleActive(PackedValue value) { if (Modules == null || Modules.Count == 0 || value.PackedValueType != packedType) { return; } foreach (Module module in Modules) { if (!((Component)module).gameObject.activeInHierarchy) { module.AssignPackedData(value); module.SetDecayTime(value.DecayTime); module.SetPostDecayTime(0.5f); ((Component)module).gameObject.SetActive(true); ActiveModules.Add(module); break; } if (ActiveModules.Contains(module) && !module.IsDecaying() && module.PackedValue.eventType == value.eventType) { if (value.Stackable) { module.AssignPackedData(value); module.OnModuleEnable(); module.SetDecayTime(value.DecayTime); module.SetPostDecayTime(0.5f); break; } if (value.Tiers != null) { module.AssignPackedData(value); module.OnModuleEnable(); module.SetDecayTime(value.DecayTime); module.SetPostDecayTime(0.5f); break; } } } } public void PoolObjects() { if (!((Object)(object)ModulePrefab == (Object)null)) { for (int i = 0; i < count; i++) { Module component = Object.Instantiate<GameObject>(ModulePrefab, ((Component)this).transform).GetComponent<Module>(); component.ModuleType = Module.UIModuleType.Descriptor; Modules.Add(component); } } } } public static class HUDManager { private static GameObject _parentObject; public static List<HUD> LoadedHUDs { get; private set; } public static HUD ActiveHUD { get; private set; } public static HUD LastHUD { get; private set; } internal static void Initialize() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown _parentObject = new GameObject("[ScoreLab] - HUD Container"); LoadedHUDs = new List<HUD>(); Populate(); if (HUDLoader.LoadedHUDs.ContainsKey(Settings.SavedHUD)) { LoadHUD(Settings.SavedHUD); } else { LoadHUD("Coda"); } } internal static void Uninitialize() { } public static void Populate() { for (int i = 0; i < HUDLoader.LoadedHUDManifests.Count; i++) { JSONHUDManifest jSONHUDManifest = HUDLoader.LoadedHUDManifests[i]; GameObject obj = Object.Instantiate<GameObject>(HUDLoader.LoadedHUDs[jSONHUDManifest.Name]); ((Object)obj).name = jSONHUDManifest.Name; HUD component = obj.GetComponent<HUD>(); if (!((Object)(object)component == (Object)null)) { LoadedHUDs.Add(component); component.SetParent(_parentObject.transform); ((Component)component).gameObject.SetActive(false); } } } public static void HUDShowModeUpdated(HUDShowMode mode) { if (!((Object)(object)ActiveHUD == (Object)null)) { switch (mode) { case HUDShowMode.Always: ((Component)ActiveHUD).gameObject.SetActive(true); break; case HUDShowMode.Never: ((Component)ActiveHUD).gameObject.SetActive(false); break; } } } public static void LoadHUD(string name) { if ((Object)(object)ActiveHUD != (Object)null) { LastHUD = ActiveHUD; } UnloadHUD(); foreach (HUD loadedHUD in LoadedHUDs) { if (((Object)loadedHUD).name == name) { ActiveHUD = loadedHUD; break; } } if (!((Object)(object)ActiveHUD == (Object)null)) { Settings.SavedHUD = name; ValueManager.UsePackage(name); ((Component)ActiveHUD).gameObject.SetActive(true); ActiveHUD.SetParent(null); } } public static void UnloadHUD() { if ((Object)(object)ActiveHUD != (Object)null) { ActiveHUD.SetParent(_parentObject.transform); ((Component)ActiveHUD).gameObject.SetActive(false); ActiveHUD = null; } } public static void DestroyHUD() { if ((Object)(object)ActiveHUD != (Object)null) { Object.Destroy((Object)(object)ActiveHUD); ActiveHUD = null; } } public static void DestroyLoadedHUDs() { if (LoadedHUDs == null || LoadedHUDs.Count == 0) { return; } foreach (HUD loadedHUD in LoadedHUDs) { Object.Destroy((Object)(object)((Component)loadedHUD).gameObject); } LoadedHUDs.Clear(); } } } namespace NEP.ScoreLab.Data { public static class HUDLoader { public static Dictionary<string, AudioClip> HUDAudioBank; public static Dictionary<string, GameObject> LoadedHUDs; public static List<JSONHUDManifest> LoadedHUDManifests; private static List<AssetBundle> _assetBundles; private static List<Object> _persistentBundleObjects; public static void Initialize() { LoadedHUDs = new Dictionary<string, GameObject>(); HUDAudioBank = new Dictionary<string, AudioClip>(); LoadedHUDManifests = new List<JSONHUDManifest>(); _persistentBundleObjects = new List<Object>(); _assetBundles = new List<AssetBundle>(); LoadHUDs(); } public static void SpawnDefaultUI() { SpawnUI("Coda"); } public static void SpawnUI(string name) { foreach (JSONHUDManifest loadedHUDManifest in LoadedHUDManifests) { if (loadedHUDManifest.Name == name) { SpawnUI(LoadedHUDs[name]); } } } public static void SpawnUI(GameObject uiObject) { Object.Instantiate<GameObject>(uiObject); } public static void LoadHUDs() { foreach (string item2 in Directory.EnumerateDirectories(Path.Combine(MelonEnvironment.UserDataDirectory, "Not Enough Photons/ScoreLab"))) { IEnumerable<string> enumerable = Directory.EnumerateFiles(item2); string text = string.Empty; string text2 = string.Empty; foreach (string item3 in enumerable) { if (item3.EndsWith(".hud")) { text = item3; } if (item3.EndsWith(".hud_manifest")) { text2 = item3; } } if (text == string.Empty) { Main.Logger.Error("Missing .HUD file in " + item2 + "!"); continue; } if (text2 == string.Empty) { Main.Logger.Error("Missing HUD manifest file in " + item2 + "!"); continue; } JSONHUDManifest item = default(JSONHUDManifest); if (!item.FromJSON(text2)) { Main.Logger.Error("Failed to read HUD manifest data! Source: " + item2); continue; } AssetBundle val = AssetBundle.LoadFromFile(text); GameObject value = HelperMethods.LoadPersistentAsset<GameObject>(val, item.AssetName); Il2CppReferenceArray<Object> val2 = val.LoadAllAssets(); Texture2D val3 = HelperMethods.LoadPersistentAsset<Texture2D>(val, "Logo"); if ((Object)(object)val3 != (Object)null) { item.SetHUDLogo(val3); } _assetBundles.Add(val); LoadedHUDManifests.Add(item); LoadedHUDs.Add(item.Name, value); if (val2 == null || ((Il2CppArrayBase<Object>)(object)val2).Length == 0) { continue; } foreach (Object item4 in (Il2CppArrayBase<Object>)(object)val2) { AudioClip val4 = ((Il2CppObjectBase)item4).TryCast<AudioClip>(); if ((Object)(object)val4 != (Object)null) { ((Object)val4).hideFlags = (HideFlags)32; HUDAudioBank.Add(item4.name, val4); } } } } public static void ReloadHUDs() { if ((Object)(object)HUDManager.ActiveHUD != (Object)null) { HUDManager.DestroyHUD(); } HUDManager.DestroyLoadedHUDs(); HUDAudioBank.Clear(); LoadedHUDManifests.Clear(); LoadedHUDs.Clear(); foreach (AssetBundle assetBundle in _assetBundles) { assetBundle.Unload(true); } _assetBundles.Clear(); LoadHUDs(); SLMenu.RefreshHUDPage(); HUDManager.Populate(); HUDManager.LoadHUD(Settings.SavedHUD); } } public struct JSONAudioParams { public string[] sounds; public float volume; public float pitch; public bool FromJSON(JObject jObject) { if (jObject == null) { return false; } JToken obj = jObject["Clips"]; JArray val = (JArray)(object)((obj is JArray) ? obj : null); if (val != null) { sounds = new string[((JContainer)val).Count]; for (int i = 0; i < sounds.Length; i++) { sounds[i] = Extensions.Value<string>((IEnumerable<JToken>)val[i]); } } volume = Extensions.Value<float>((IEnumerable<JToken>)jObject["Volume"]); pitch = Extensions.Value<float>((IEnumerable<JToken>)jObject["Pitch"]); return true; } } public struct JSONHUDManifest { public string Name; public string Author; public string Description; public string[] Tags; public string AssetName; public Texture2D Logo; public bool FromJSON(string pathToJson) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown using (StreamReader streamReader = new StreamReader(pathToJson)) { JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { JToken obj = JToken.ReadFrom((JsonReader)(object)val); JObject val2 = (JObject)(object)((obj is JObject) ? obj : null); if (val2 == null) { return false; } Name = Extensions.Value<string>((IEnumerable<JToken>)val2["name"]); Author = Extensions.Value<string>((IEnumerable<JToken>)val2["author"]); AssetName = Extensions.Value<string>((IEnumerable<JToken>)val2["assetName"]); } finally { ((IDisposable)val)?.Dispose(); } } return true; } public void SetHUDLogo(Texture2D texture) { Logo = texture; } } public struct JSONMult { public string EventType; public string TierEventType; public float DecayTime; public bool Stackable; public JSONAudioParams EventAudio; public string Name; public float Multiplier; public string Condition; public int TierRequirement; public JSONMult[] Tiers; public bool FromJSON(string pathToJson) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown using (StreamReader streamReader = new StreamReader(pathToJson)) { JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { JToken obj = JToken.ReadFrom((JsonReader)(object)val); JObject val2 = (JObject)(object)((obj is JObject) ? obj : null); if (val2 == null) { return false; } ReadMultObject(val2); } finally { ((IDisposable)val)?.Dispose(); } } return true; } private void ReadMultObject(JObject obj) { EventType = Extensions.Value<string>((IEnumerable<JToken>)obj["EventType"]); DecayTime = Extensions.Value<float>((IEnumerable<JToken>)obj["DecayTime"]); Stackable = Extensions.Value<bool>((IEnumerable<JToken>)obj["Stackable"]); Condition = Extensions.Value<string>((IEnumerable<JToken>)obj["Condition"]); EventAudio.FromJSON(Extensions.Value<JObject>((IEnumerable<JToken>)obj["EventAudio"])); Name = Extensions.Value<string>((IEnumerable<JToken>)obj["Name"]); Multiplier = Extensions.Value<float>((IEnumerable<JToken>)obj["Multiplier"]); TierRequirement = Extensions.Value<int>((IEnumerable<JToken>)obj["TierRequirement"]); JToken obj2 = obj["Tiers"]; JArray val = ((obj2 != null) ? Extensions.Value<JArray>((IEnumerable<JToken>)obj2) : null); List<JSONMult> list = new List<JSONMult>(); if (val != null) { for (int i = 0; i < ((JContainer)val).Count; i++) { JSONMult item = default(JSONMult); JToken obj3 = val[i]; JObject obj4 = (JObject)(object)((obj3 is JObject) ? obj3 : null); item.ReadMultObject(obj4); list.Add(item); } Tiers = list.ToArray(); } } } public struct JSONScore { public string EventType; public string TierEventType; public float DecayTime; public bool Stackable; public JSONAudioParams EventAudio; public string Name; public int Score; public int TierRequirement; public JSONScore[] Tiers; public bool FromJSON(string pathToJson) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown using (StreamReader streamReader = new StreamReader(pathToJson)) { JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { JToken obj = JToken.ReadFrom((JsonReader)(object)val); JObject val2 = (JObject)(object)((obj is JObject) ? obj : null); if (val2 == null) { return false; } ReadScoreObject(val2); } finally { ((IDisposable)val)?.Dispose(); } } return true; } private void ReadScoreObject(JObject obj) { EventType = Extensions.Value<string>((IEnumerable<JToken>)obj["EventType"]); DecayTime = Extensions.Value<float>((IEnumerable<JToken>)obj["DecayTime"]); Stackable = Extensions.Value<bool>((IEnumerable<JToken>)obj["Stackable"]); EventAudio.FromJSON(Extensions.Value<JObject>((IEnumerable<JToken>)obj["EventAudio"])); Name = Extensions.Value<string>((IEnumerable<JToken>)obj["Name"]); Score = Extensions.Value<int>((IEnumerable<JToken>)obj["Score"]); TierRequirement = Extensions.Value<int>((IEnumerable<JToken>)obj["TierRequirement"]); JToken obj2 = obj["Tiers"]; JArray val = ((obj2 != null) ? Extensions.Value<JArray>((IEnumerable<JToken>)obj2) : null); List<JSONScore> list = new List<JSONScore>(); if (val != null) { for (int i = 0; i < ((JContainer)val).Count; i++) { JSONScore item = default(JSONScore); JToken obj3 = val[i]; JObject obj4 = (JObject)(object)((obj3 is JObject) ? obj3 : null); item.ReadScoreObject(obj4); list.Add(item); } Tiers = list.ToArray(); } } } public struct MarrowSceneInfo { public string LevelTitle; public string Barcode; public MarrowScene MarrowScene; } public static class EventType { public static class Score { public static readonly string Kill = "SCORE_KILL"; public static readonly string Headshot = "SCORE_HEADSHOT"; public static readonly string EnemyMidAirKill = "SCORE_MID_AIR"; public static readonly string GameWaveCompleted = "SCORE_WAVE_COMPLETED"; public static readonly string GameRoundCompleted = "SCORE_ROUND_COMPLETED"; public static readonly string Crabcest = "SCORE_CRABCEST"; public static readonly string Facehug = "SCORE_FACEHUG"; public static readonly string StealthKill = "SCORE_STEALTH_KILL"; } public static class Mult { public static readonly string Kill = "MULT_KILL"; public static readonly string MidAir = "MULT_MIDAIR"; public static readonly string Seated = "MULT_SEATED"; public static readonly string SecondWind = "MULT_SECONDWIND"; public static readonly string Ragolled = "MULT_RAGDOLLED"; public static readonly string SwappedAvatars = "MULT_SWAPPED_AVATARS"; public static readonly string SlowMo = "MULT_SLOWMO"; } public static readonly string None = "None"; } public class PackedAudioParams { public AudioClip[] Clips { get; private set; } public float Volume { get; private set; } public float Pitch { get; private set; } public PackedAudioParams() { Clips = null; Volume = 1f; Pitch = 1f; } public PackedAudioParams(JSONAudioParams audioParams) { Clips = (AudioClip[])(object)new AudioClip[audioParams.sounds.Length]; for (int i = 0; i < Clips.Length; i++) { Clips[i] = HUDLoader.HUDAudioBank[audioParams.sounds[i]]; } Volume = audioParams.volume; Pitch = audioParams.pitch; } } public class PackedHighScore : PackedValue { public int bestScore; public override PackedType PackedValueType => PackedType.HighScore; public PackedHighScore(string name, int bestScore) { this.bestScore = bestScore; } public override void OnValueCreated() { } public override void OnValueRemoved() { } } [Serializable] public class PackedMultiplier : PackedValue { public float Multiplier; public float AccumulatedMultiplier; public string Condition; private bool _timed; private bool _timeBegin; public override PackedType PackedValueType => PackedType.Multiplier; public float Elapsed => _tDecay; public Func<bool> condition { get; private set; } public PackedMultiplier() { } public PackedMultiplier(JSONMult mult, bool useTiers = false) { eventType = mult.EventType; DecayTime = mult.DecayTime; Stackable = mult.Stackable; Name = mult.Name; Multiplier = mult.Multiplier; Condition = mult.Condition; TierRequirement = mult.TierRequirement; EventAudio = new PackedAudioParams(mult.EventAudio); if (useTiers) { TierEventType = mult.TierEventType; } } public override void OnValueCreated() { if (DecayTime != 0f) { _timed = true; } condition = API.GameConditions.GetCondition(Condition); AccumulatedMultiplier = Multiplier; _tDecay = DecayTime; } public override void OnValueRemoved() { _timeBegin = false; ResetTier(); } public override void OnUpdate() { if (condition != null && !condition()) { ScoreTracker.Remove(this); } OnUpdateDecay(); } public override void OnUpdateDecay() { if (_timed) { if (!_timeBegin) { API.Multiplier.OnMultiplierTimeBegin?.Invoke(this); _timeBegin = true; } if (_tDecay <= 0f) { API.Multiplier.OnMultiplierTimeExpired?.Invoke(this); _tDecay = DecayTime; ScoreTracker.Remove(this); } _tDecay -= Time.deltaTime; } } } [Serializable] public class PackedScore : PackedValue { public int Score; public int AccumulatedScore; public override PackedType PackedValueType => PackedType.Score; public PackedScore() { } public PackedScore(JSONScore score, bool useTiers = false) { eventType = score.EventType; DecayTime = score.DecayTime; Stackable = score.Stackable; Name = score.Name; Score = score.Score; TierRequirement = score.TierRequirement; EventAudio = new PackedAudioParams(score.EventAudio); if (useTiers) { TierEventType = score.TierEventType; } else { AccumulatedScore = score.Score; } } public override void OnValueCreated() { _tDecay = DecayTime; AccumulatedScore = Score; } public override void OnValueRemoved() { ResetTier(); } public override void OnUpdate() { OnUpdateDecay(); } public override void OnUpdateDecay() { if (_tDecay <= 0f) { ScoreTracker.Remove(this); } _tDecay -= Time.deltaTime; } } [Serializable] public class PackedValue { public enum PackedType { Base, Score, Multiplier, HighScore, Misc } public string Name; public string eventType; public string TierEventType; public PackedAudioParams EventAudio; public bool Stackable; public float DecayTime; public float PostDecayTime; public PackedValue Parent; public PackedValue[] Tiers; public int TierRequirement; protected float _tDecay; private int _tierIndex; private int _tierRequirementIndex; public virtual PackedType PackedValueType => PackedType.Base; public PackedValue CurrentTier { get { if (Tiers == null || Tiers.Length == 0) { return this; } if (_tierIndex == Tiers.Length) { _tierIndex = Tiers.Length; return Tiers[_tierIndex]; } return Tiers[_tierIndex]; } } public PackedValue NextTier { get { if (_tierIndex + 1 >= Tiers.Length) { return Tiers[_tierIndex]; } return Tiers[_tierIndex + 1]; } } public int TierIndex => _tierIndex; public int TierRequirementIndex => _tierRequirementIndex; public virtual bool IsActive { get; } public virtual void OnValueCreated() { } public virtual void OnValueRemoved() { } public virtual void OnUpdate() { } public virtual void OnUpdateDecay() { } public void SetDecayTime(float decayTime) { _tDecay = decayTime; } public void ToNextTier() { _tierRequirementIndex++; if (_tierRequirementIndex >= TierRequirement) { _tierRequirementIndex = TierRequirement; API.Value.OnValueTierReached?.Invoke(CurrentTier); if (_tierIndex + 1 < Tiers.Length) { _tierIndex++; } } } protected void ResetTier() { _tierIndex = 0; } } public static class ValueManager { public static Dictionary<string, int> HighScoreTable; public static readonly string Path_Developer = Path.Combine(MelonEnvironment.UserDataDirectory, "Not Enough Photons"); public static readonly string Path_Mod = Path.Combine(Path_Developer, "ScoreLab"); private static readonly string File_HighScores = Path.Combine(Path_Mod, "high_score_table.json"); public static Dictionary<string, ValuePackage> Packages { get; private set; } public static ValuePackage ActivePackage { get; private set; } public static void Initialize() { HighScoreTable = new Dictionary<string, int>(); Packages = new Dictionary<string, ValuePackage>(); foreach (JSONHUDManifest loadedHUDManifest in HUDLoader.LoadedHUDManifests) { JSONScore[] scoresForHUD = GetScoresForHUD(loadedHUDManifest.Name); JSONMult[] multipliersForHUD = GetMultipliersForHUD(loadedHUDManifest.Name); PackedScore[] scores = CreateScoreObjects(scoresForHUD); PackedMultiplier[] multipliers = CreateMultiplierObjects(multipliersForHUD); Packages.Add(loadedHUDManifest.Name, new ValuePackage(scores, multipliers)); } UsePackage(Settings.SavedHUD); } public static string[] GetAllFiles(string path, string extensionFilter) { string[] files = Directory.GetFiles(path); List<string> list = new List<string>(); string[] array = files; foreach (string text in array) { if (text.EndsWith(extensionFilter)) { list.Add(text); } } return list.ToArray(); } public static void UsePackage(string name) { if (Packages.TryGetValue(name, out var value)) { ActivePackage = value; } } public static PackedValue Get(string eventType) { if (ActivePackage.Values == null) { return null; } if (ActivePackage.Values.TryGetValue(eventType, out var value)) { return value; } return null; } public static Dictionary<string, int> ReadHighScore() { return JsonConvert.DeserializeObject(File_HighScores) as Dictionary<string, int>; } public static void WriteHighScore() { string file_HighScores = File_HighScores; if (!File.Exists(file_HighScores)) { Main.Logger.Warning("High score file doesn't exist! Creating one."); File.Create(file_HighScores); } else { string contents = JsonConvert.SerializeObject((object)HighScoreTable); File.WriteAllText(file_HighScores, contents); } } public static void WriteBestScore(PackedHighScore highScore) { string name = highScore.Name; int bestScore = highScore.bestScore; HighScoreTable.Add(name, bestScore); } private static JSONScore[] GetScoresForHUD(string name) { string path = Path.Combine(Path_Mod, name + "/Data/Score"); if (!Directory.Exists(path)) { Main.Logger.Warning("HUD " + name + " doesn't have a score data folder!"); return null; } string[] allFiles = GetAllFiles(path, ".json"); List<JSONScore> list = new List<JSONScore>(); string[] array = allFiles; for (int i = 0; i < array.Length; i++) { JSONScore item = ReadScoreData(array[i]); list.Add(item); } return list.ToArray(); } private static JSONMult[] GetMultipliersForHUD(string name) { string path = Path.Combine(Path_Mod, name + "/Data/Multiplier"); if (!Directory.Exists(path)) { Main.Logger.Warning("HUD " + name + " doesn't have a multiplier data folder!"); return null; } string[] allFiles = GetAllFiles(path, ".json"); List<JSONMult> list = new List<JSONMult>(); string[] array = allFiles; for (int i = 0; i < array.Length; i++) { JSONMult item = ReadMultiplierData(array[i]); list.Add(item); } return list.ToArray(); } private static PackedScore[] CreateScoreObjects(JSONScore[] scores) { if (scores == null) { return null; } List<PackedScore> list = new List<PackedScore>(); for (int i = 0; i < scores.Length; i++) { JSONScore score = scores[i]; PackedScore packedScore = new PackedScore(score); if (score.Tiers != null && score.Tiers.Length != 0) { List<PackedScore> list2 = new List<PackedScore>(); JSONScore[] tiers = score.Tiers; for (int j = 0; j < tiers.Length; j++) { PackedScore packedScore2 = new PackedScore(tiers[j], useTiers: true); packedScore2.eventType = packedScore.eventType; list2.Add(packedScore2); } PackedValue[] tiers2 = list2.ToArray(); packedScore.Tiers = tiers2; } list.Add(packedScore); } return list.ToArray(); } private static PackedMultiplier[] CreateMultiplierObjects(JSONMult[] multipliers) { if (multipliers == null) { return null; } List<PackedMultiplier> list = new List<PackedMultiplier>(); for (int i = 0; i < multipliers.Length; i++) { JSONMult mult = multipliers[i]; PackedMultiplier packedMultiplier = new PackedMultiplier(mult); if (mult.Tiers != null && mult.Tiers.Length != 0) { List<PackedMultiplier> list2 = new List<PackedMultiplier>(); JSONMult[] tiers = mult.Tiers; for (int j = 0; j < tiers.Length; j++) { PackedMultiplier packedMultiplier2 = new PackedMultiplier(tiers[j], useTiers: true); packedMultiplier2.eventType = packedMultiplier.eventType; list2.Add(packedMultiplier2); } PackedValue[] tiers2 = list2.ToArray(); packedMultiplier.Tiers = tiers2; } list.Add(packedMultiplier); } return list.ToArray(); } private static JSONScore ReadScoreData(string file) { JSONScore result = default(JSONScore); result.FromJSON(file); return result; } private static JSONMult ReadMultiplierData(string file) { JSONMult result = default(JSONMult); result.FromJSON(file); return result; } } public struct ValuePackage { public Dictionary<string, PackedValue> Values; public ValuePackage(PackedScore[] scores, PackedMultiplier[] multipliers) { Values = new Dictionary<string, PackedValue>(); if (scores != null) { foreach (PackedScore packedScore in scores) { Values.Add(packedScore.eventType, packedScore); } } if (multipliers != null) { foreach (PackedMultiplier packedMultiplier in multipliers) { Values.Add(packedMultiplier.eventType, packedMultiplier); } } } } } namespace NEP.ScoreLab.Core { public static class API { public static class Value { public static Action<PackedValue> OnValueAdded; public static Action<PackedValue> OnValueAccumulated; public static Action<PackedValue> OnValueTierReached; public static Action<PackedValue> OnValueRemoved; } public static class Score { public static Action<int> OnScoreUpdated; public static Action<int> OnScoreDifferenceUpdated; public static Action<int> OnLastScoreUpdated; } public static class Multiplier { public static Action<PackedMultiplier> OnMultiplierTimeBegin; public static Action<PackedMultiplier> OnMultiplierTimeExpired; } public static class HighScore { public static Action<PackedHighScore> OnHighScoreReached; public static Action<PackedHighScore> OnHighScoreUpdated; public static Action<PackedHighScore> OnHighScoreLoaded; public static Action<PackedHighScore> OnHighScoreSaved; } public static class GameConditions { private static Dictionary<string, Func<bool>> _conditionTable = new Dictionary<string, Func<bool>> { { "IsPlayerMoving", () => ScoreDirector.IsPlayerMoving }, { "IsPlayerSeated", () => ScoreDirector.IsPlayerSeated }, { "IsPlayerInAir", () => ScoreDirector.IsPlayerInAir }, { "IsPlayerRagdolled", () => ScoreDirector.IsPlayerRagdolled }, { "IsSlowMoEnabled", () => ScoreDirector.IsSlowMoEnabled } }; public static Func<bool> GetCondition(string cond) { if (string.IsNullOrEmpty(cond)) { Debug.LogWarning(Object.op_Implicit(cond + " doesn't exist in the condition table.")); return null; } if (!_conditionTable.ContainsKey(cond)) { Debug.LogWarning(Object.op_Implicit(cond + " doesn't exist in the condition table.")); return null; } return _conditionTable[cond]; } } public static class UI { public static Action<NEP.ScoreLab.HUD.Module> OnModuleEnabled; public static Action<NEP.ScoreLab.HUD.Module> OnModuleDisabled; public static Action<NEP.ScoreLab.HUD.Module> OnModuleDecayed; public static Action<NEP.ScoreLab.HUD.Module> OnModulePostDecayed; } } public static class ScoreDirector { public static class Patches { [HarmonyPatch(typeof(Projectile), "Awake")] public static class ProjectilePatch { public static void Postfix(Projectile __instance) { Action<Collider, Vector3, Vector3> action = OnProjectileCollision; ((UnityEvent<Collider, Vector3, Vector3>)(object)__instance.onCollision).AddListener(UnityAction<Collider, Vector3, Vector3>.op_Implicit(action)); } private static void OnProjectileCollision(Collider collider, Vector3 world, Vector3 normal) { MarrowBody val = MarrowBody.Cache.Get(((Component)collider).gameObject); if (!((Object)(object)val == (Object)null)) { TriggerRefProxy component = ((Component)val).GetComponent<TriggerRefProxy>(); if (!((Object)(object)component == (Object)null) && !component.aiManager.isDead && (Object)(object)((Component)component.targetHead).gameObject == (Object)(object)((Component)val).gameObject) { ScoreTracker.Add(EventType.Score.Headshot); } } } } [HarmonyPatch(typeof(RigManager), "SwitchAvatar")] public static class RigManagerSwapAvatarPatch { public static void Postfix(Avatar newAvatar) { _playerRecentlySwappedAvatars = true; } } [HarmonyPatch(typeof(BehaviourCrablet))] [HarmonyPatch("AttachToFace")] public static class CrabletAttachToFacePatch { public static void Postfix(Rigidbody face, TriggerRefProxy trp, bool preAttach = false, bool isPlayer = true) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if (!isPlayer) { if ((int)trp.npcType == 32) { ScoreTracker.Add(EventType.Score.Crabcest); } else { ScoreTracker.Add(EventType.Score.Facehug); } } } } [HarmonyPatch(typeof(Seat))] [HarmonyPatch("Register")] public static class RegisterSeatPatch { public static void Postfix(RigManager rM) { IsPlayerSeated = true; ScoreTracker.Add(EventType.Mult.Seated); } } [HarmonyPatch(typeof(Seat))] [HarmonyPatch("DeRegister")] public static class DeRegisterSeatPatch { public static void Postfix() { IsPlayerSeated = false; } } [HarmonyPatch(typeof(Player_Health))] [HarmonyPatch("LifeSavingDamgeDealt")] public static class SecondWindPatch { public static void Postfix() { ScoreTracker.Add(EventType.Mult.SecondWind); } } [HarmonyPatch(typeof(Arena_GameController))] [HarmonyPatch("StartNextWave")] public static class StartNextWavePatch { public static void Postfix(Arena_GameController __instance) { ScoreTracker.Add(EventType.Score.GameWaveCompleted); } } [HarmonyPatch(typeof(Arena_GameController))] [HarmonyPatch("EndOfRound")] public static class StartNextRoundPatch { public static void Postfix(Arena_GameController __instance) { ScoreTracker.Add(EventType.Score.GameRoundCompleted); } } [HarmonyPatch(typeof(PhysicsRig))] [HarmonyPatch("OnUpdate")] public static class PhysRigPatch { private static bool _midAirTargetBool; private static float _tMidAirDelay = 0.5f; private static float _tAirTime; private static bool _ragdolledTargetBool; private static float _tRagdollDelay = 0.5f; private static float _tRagdollTime; public static void Postfix(PhysicsRig __instance) { IsPlayerInAir = !__instance.physG.isGrounded; if (IsPlayerInAir) { if (!_midAirTargetBool) { _tAirTime += Time.deltaTime; if (_tAirTime > _tMidAirDelay) { ScoreTracker.Add(EventType.Mult.MidAir); _midAirTargetBool = true; } } } else { _tAirTime = 0f; _midAirTargetBool = false; } if (IsPlayerRagdolled) { if (!_ragdolledTargetBool) { _ragdolledTargetBool = true; } } else { _ragdolledTargetBool = false; } if (_playerRecentlySwappedAvatars) { ScoreTracker.Add(EventType.Mult.SwappedAvatars); _playerRecentlySwappedAvatars = false; } } } [HarmonyPatch(typeof(PhysicsRig))] [HarmonyPatch("RagdollRig")] public static class PhysRigRagdollPatch { public static void Postfix(PhysicsRig __instance) { IsPlayerRagdolled = true; } } [HarmonyPatch(typeof(PhysicsRig))] [HarmonyPatch("UnRagdollRig")] public static class PhysRigUnRagdollPatch { public static void Postfix(PhysicsRig __instance) { IsPlayerRagdolled = false; } } [HarmonyPatch(typeof(TimeManager), "OnPostTimeUpdate")] public static class TimeManagerUpdatePatch { private static bool _slowmoSwitch; public static void Postfix() { } } [HarmonyPatch(typeof(TimeManager), "INCREASE_TIMESCALE")] public static class TimeManagerIncreaseTimePatch { public static void Postfix() { } } [HarmonyPatch(typeof(TimeManager), "DECREASE_TIMESCALE")] public static class TimeManagerDecreaseTimePatch { public static void Postfix() { } } public static void InitPatches() { Hooking.OnNPCKillStart += OnAIDeath; } public static void OnAIDeath(BehaviourBaseNav behaviour) { ScoreTracker.Add(ValueManager.Get(EventType.Score.Kill)); ScoreTracker.Add(ValueManager.Get(EventType.Mult.Kill)); if (!behaviour.sensors.isGrounded) { ScoreTracker.Add(EventType.Score.EnemyMidAirKill); } if ((Object)(object)behaviour.sensors.target == (Object)null) { ScoreTracker.Add(EventType.Score.StealthKill); } } } public static readonly string PlayerName = ""; public static bool IsPlayerMoving = false; public static bool IsPlayerInAir = false; public static bool IsPlayerSeated = false; public static bool IsPlayerRagdolled = false; public static bool IsSlowMoEnabled = false; private static bool _playerRecentlySwappedAvatars = false; } public static class ScoreTracker { private static int _score = 0; private static int _lastScore = 0; private static float _multiplier = 1f; private static float _baseMultiplier = 1f; public static List<PackedValue> ActiveValues { get; private set; } public static int Score => _score; public static int LastScore => _lastScore; public static float Multiplier => _multiplier; public static void Initialize() { ActiveValues = new List<PackedValue>(); } public static void Update() { if (ActiveValues != null) { for (int i = 0; i < ActiveValues.Count; i++) { ActiveValues[i].OnUpdate(); } } } public static void Add(string eventType) { Add(Create(eventType)); } public static void Add(PackedValue value) { if (value != null) { if (value.PackedValueType == PackedValue.PackedType.Score) { SetPackedScore((PackedScore)value); } else if (value.PackedValueType == PackedValue.PackedType.Multiplier) { SetPackedMultiplier((PackedMultiplier)value); } } } public static void Remove(PackedValue value) { if (value.PackedValueType == PackedValue.PackedType.Score) { ActiveValues.Remove(value); value.OnValueRemoved(); API.Value.OnValueRemoved?.Invoke(value); } else if (value.PackedValueType == PackedValue.PackedType.Multiplier) { ActiveValues.Remove(value); RemoveMultiplier((value as PackedMultiplier).AccumulatedMultiplier); value.OnValueRemoved(); API.Value.OnValueRemoved?.Invoke(value); } } public static void AddScore(int score) { _lastScore = _score; _score += Mathf.RoundToInt((float)score * _multiplier); } public static void AddMultiplier(float multiplier) { _multiplier += multiplier; } public static void SetMultiplier(float multiplier) { _multiplier = multiplier; } public static void ResetScore() { _score = 0; _lastScore = 0; } public static void ResetMultiplier() { _multiplier = 1f; } public static void ResetAll() { ResetScore(); ResetMultiplier(); ResetHighScore(); ActiveValues.Clear(); } public static void ResetHighScore() { } public static void RemoveMultiplier(float multiplier) { if (_multiplier < _baseMultiplier) { _multiplier = _baseMultiplier; } _multiplier -= multiplier; } public static bool CheckDuplicate(PackedValue value) { foreach (PackedValue activeValue in ActiveValues) { if (activeValue.eventType == value.eventType) { return true; } } return false; } private static void SetPackedScore(PackedScore score) { if (score != null) { if (!CheckDuplicate(score)) { InitializeValue(score); AddScore(score.Score); ActiveValues.Add(score); API.Value.OnValueAdded?.Invoke(score); } else if (score.Tiers != null) { PackedScore clone = GetClone<PackedScore>(score); PackedScore packedScore = (PackedScore)clone.CurrentTier; clone.ToNextTier(); clone.TierRequirement = packedScore.TierRequirement; clone.SetDecayTime(packedScore.DecayTime); AddScore(packedScore.Score); } else if (score.Stackable) { PackedScore clone2 = GetClone<PackedScore>(score); AddScore(score.Score); clone2.SetDecayTime(clone2.DecayTime); clone2.AccumulatedScore += clone2.Score; API.Value.OnValueAccumulated?.Invoke(clone2); } else { PackedScore packedScore2 = CopyFromScore(score); InitializeValue(packedScore2); AddScore(packedScore2.Score); ActiveValues.Add(packedScore2); API.Value.OnValueAdded?.Invoke(packedScore2); } } } private static void SetPackedMultiplier(PackedMultiplier multiplier) { if (multiplier != null) { if (!CheckDuplicate(multiplier)) { InitializeValue(multiplier); AddMultiplier(multiplier.Multiplier); ActiveValues.Add(multiplier); API.Value.OnValueAdded?.Invoke(multiplier); } else if (multiplier.Tiers != null) { PackedMultiplier clone = GetClone<PackedMultiplier>(multiplier); PackedMultiplier packedMultiplier = (PackedMultiplier)clone.CurrentTier; clone.ToNextTier(); clone.TierRequirement = packedMultiplier.TierRequirement; clone.SetDecayTime(packedMultiplier.DecayTime); AddMultiplier(packedMultiplier.Multiplier); multiplier.AccumulatedMultiplier += packedMultiplier.Multiplier; API.Value.OnValueTierReached?.Invoke(packedMultiplier); } else if (multiplier.Stackable) { PackedMultiplier clone2 = GetClone<PackedMultiplier>(multiplier); AddMultiplier(multiplier.Multiplier); clone2.SetDecayTime(clone2.DecayTime); clone2.AccumulatedMultiplier += clone2.Multiplier; API.Value.OnValueAccumulated?.Invoke(clone2); } else { PackedMultiplier packedMultiplier2 = CopyFromMult(multiplier); InitializeValue(packedMultiplier2); AddMultiplier(multiplier.Multiplier); ActiveValues.Add(packedMultiplier2); API.Value.OnValueAdded?.Invoke(packedMultiplier2); } } } private static PackedScore CopyFromScore(PackedScore original) { return new PackedScore { eventType = original.eventType, Name = original.Name, Score = original.Score, EventAudio = original.EventAudio, DecayTime = original.DecayTime }; } private static PackedMultiplier CopyFromMult(PackedMultiplier original) { return new PackedMultiplier { eventType = original.eventType, Name = original.Name, Multiplier = original.Multiplier, EventAudio = original.EventAudio, DecayTime = original.DecayTime, Condition = original.Condition }; } private static PackedValue Create(string eventType) { PackedValue packedValue = ValueManager.Get(eventType); if (packedValue == null) { return null; } if (packedValue.PackedValueType == PackedValue.PackedType.Score) { PackedScore packedScore = (PackedScore)packedValue; return new PackedScore { eventType = packedScore.eventType, Stackable = packedScore.Stackable, DecayTime = packedScore.DecayTime, Name = packedScore.Name, Score = packedScore.Score, EventAudio = packedScore.EventAudio, TierRequirement = packedScore.TierRequirement, Tiers = packedScore.Tiers }; } if (packedValue.PackedValueType == PackedValue.PackedType.Multiplier) { PackedMultiplier packedMultiplier = (PackedMultiplier)packedValue; return new PackedMultiplier { eventType = packedMultiplier.eventType, Stackable = packedMultiplier.Stackable, DecayTime = packedMultiplier.DecayTime, Name = packedMultiplier.Name, Multiplier = packedMultiplier.Multiplier, Condition = packedMultiplier.Condition, EventAudio = packedMultiplier.EventAudio, TierRequirement = packedMultiplier.TierRequirement, Tiers = packedMultiplier.Tiers }; } return null; } private static void InitializeValue(PackedValue value) { value.OnValueCreated(); value.SetDecayTime(value.DecayTime); } private static T GetClone<T>(PackedValue value) where T : PackedValue { return (T)ActiveValues.Find((PackedValue match) => match.eventType == value.eventType); } } public static class Settings { public static float DistanceToCamera; public static float MovementSmoothness; public static bool UseAnnouncer; public static string SavedHUD; public static HUDShowMode HUDShowMode; private static MelonPreferences_Category m_scorelabCategory; private static MelonPreferences_Entry<float> m_eDistanceToCamera; private static MelonPreferences_Entry<float> m_eMovementSmoothness; private static MelonPreferences_Entry<bool> m_eUseAnnouncer; private static MelonPreferences_Entry<string> m_eSavedHUD; private static MelonPreferences_Entry<int> m_eHudShowMode; public static void CreatePreferences() { m_scorelabCategory = MelonPreferences.CreateCategory("ScoreLab"); m_eDistanceToCamera = m_scorelabCategory.CreateEntry<float>("DistanceToCamera", 1.125f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); m_eMovementSmoothness = m_scorelabCategory.CreateEntry<float>("MovementSmoothness", 16f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); m_eUseAnnouncer = m_scorelabCategory.CreateEntry<bool>("UseAnnouncer", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); m_eSavedHUD = m_scorelabCategory.CreateEntry<string>("SavedHUD", "Coda", (string)null, (string)null, false, false, (ValueValidator)null, (string)null); m_eHudShowMode = m_scorelabCategory.CreateEntry<int>("HUDShowMode", 0, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); DistanceToCamera = m_eDistanceToCamera.Value; MovementSmoothness = m_eMovementSmoothness.Value; UseAnnouncer = m_eUseAnnouncer.Value; SavedHUD = m_eSavedHUD.Value; HUDShowMode = (HUDShowMode)m_eHudShowMode.Value; } public static void Save(bool log = false) { m_eDistanceToCamera.Value = DistanceToCamera; m_eMovementSmoothness.Value = MovementSmoothness; m_eUseAnnouncer.Value = UseAnnouncer; m_eSavedHUD.Value = SavedHUD; m_scorelabCategory.SaveToFile(log); } public static void SetDistanceToCamera(float distance) { m_eDistanceToCamera.Value = distance; } public static void SetMovementSmoothness(float movementSmoothness) { m_eMovementSmoothness.Value = movementSmoothness; } public static void SetUseAnnouncer(bool useAnnouncer) { m_eUseAnnouncer.Value = useAnnouncer; } public static void SetHUDShowMode(HUDShowMode mode) { m_eHudShowMode.Value = (int)mode; HUDManager.HUDShowModeUpdated(mode); } } } namespace NEP.ScoreLab.Audio { public static class AudioManager { public static void Initialize() { API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAdded, new Action<PackedValue>(OnValueReceived)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueTierReached, new Action<PackedValue>(OnValueReceived)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAccumulated, new Action<PackedValue>(OnValueReceived)); } public static void Uninitialize() { API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAdded, new Action<PackedValue>(OnValueReceived)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueTierReached, new Action<PackedValue>(OnValueReceived)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAccumulated, new Action<PackedValue>(OnValueReceived)); } private static void OnValueReceived(PackedValue value) { if (Settings.UseAnnouncer && value.EventAudio != null && value.EventAudio.Clips != null && value.EventAudio.Clips.Length != 0) { AudioClip val = null; if (value.EventAudio.Clips.Length == 1) { val = value.EventAudio.Clips[0]; } else { int num = Random.Range(0, value.EventAudio.Clips.Length); val = value.EventAudio.Clips[num]; } Play(val, value.EventAudio.Volume, value.EventAudio.Pitch); } } public static void Play(AudioClip clip, float volume = 1f, float pitch = 1f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Audio.PlayAtPoint(clip, Vector3.zero, Audio.InHead, volume, pitch, 0f); } } }
Quest/Mods/ScoreLab.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BoneLib; using BoneLib.BoneMenu; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Bonelab; using Il2CppSLZ.Marrow; using Il2CppSLZ.Marrow.AI; using Il2CppSLZ.Marrow.Interaction; using Il2CppSLZ.Marrow.PuppetMasta; using Il2CppSLZ.Marrow.Utilities; using Il2CppSLZ.Marrow.Warehouse; using Il2CppSLZ.VRMK; using Il2CppSystem; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using NEP.ScoreLab; using NEP.ScoreLab.Audio; using NEP.ScoreLab.Core; using NEP.ScoreLab.Data; using NEP.ScoreLab.HUD; using NEP.ScoreLab.Menu; using NEP.ScoreLab.Patches; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Main), "ScoreLab", "1.0.0", "Not Enough Photons", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("ScoreLab")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0140fb38dafe5a3ef9669f29b961df65def51cb4")] [assembly: AssemblyProduct("ScoreLab")] [assembly: AssemblyTitle("ScoreLab")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.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 NEP.ScoreLab { public static class BuildInfo { public const string Name = "ScoreLab"; public const string Author = "Not Enough Photons"; public const string Company = "Not Enough Photons"; public const string Version = "1.0.0"; public const string DownloadLink = "https://thunderstore.io/c/bonelab/p/NotEnoughPhotons/ScoreLab"; } public class Main : MelonMod { internal static Instance Logger; public override void OnLateInitializeMelon() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown Logger = new Instance("ScoreLab"); Settings.CreatePreferences(); Hooks.Initialize(); Hooks.Game.OnMarrowGameStarted = (Action)Delegate.Combine(Hooks.Game.OnMarrowGameStarted, new Action(OnMarrowGameStarted)); Hooks.Game.OnMarrowSceneLoaded = (Action<MarrowSceneInfo>)Delegate.Combine(Hooks.Game.OnMarrowSceneLoaded, new Action<MarrowSceneInfo>(OnMarrowSceneLoaded)); HUDLoader.Initialize(); SLMenu.Initialize(); } public void OnMarrowGameStarted() { ScoreTracker.Initialize(); ValueManager.Initialize(); AudioManager.Initialize(); ScoreDirector.Patches.InitPatches(); } public void OnMarrowSceneLoaded(MarrowSceneInfo sceneInfo) { HUDManager.Initialize(); ScoreTracker.ResetAll(); } public override void OnUpdate() { ScoreTracker.Update(); } public override void OnDeinitializeMelon() { HUDManager.Uninitialize(); AudioManager.Uninitialize(); Settings.Save(); } } } namespace NEP.ScoreLab.Patches { public static class Hooks { public static class Game { public static Action OnMarrowGameStarted; public static Action<MarrowSceneInfo> OnMarrowSceneLoaded; private static MarrowSceneInfo _lastScene; private static MarrowSceneInfo _currentScene; private static MarrowSceneInfo _nextScene; public static void Initialize() { MarrowGame.RegisterOnReadyAction(Action.op_Implicit((Action)delegate { OnMarrowGameStarted?.Invoke(); })); Hooking.OnLevelLoaded += OnSceneMarrowLoaded; } private static void OnSceneMarrowLoaded(LevelInfo info) { //IL_000a: 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) MarrowSceneInfo currentScene = default(MarrowSceneInfo); currentScene.Barcode = info.barcode; currentScene.LevelTitle = info.title; currentScene.MarrowScene = ((CrateReferenceT<LevelCrate>)(object)info.levelReference).Crate.MainScene; _currentScene = currentScene; _lastScene = _currentScene; OnMarrowSceneLoaded?.Invoke(_currentScene); } } public static void Initialize() { Game.Initialize(); } } } namespace NEP.ScoreLab.Menu { public static class SLMenu { private static Page _hudPage; public static void Initialize() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) Page obj = Page.Root.CreatePage("Not Enough Photons", Color.white, 0, true).CreatePage("ScoreLab", Color.white, 0, true); _hudPage = obj.CreatePage("HUDs", Color.white, 0, true); obj.CreateFloat("HUD Distance", Color.white, 1.125f, 0.025f, 0f, 2f, (Action<float>)delegate(float value) { Settings.DistanceToCamera = value; }); obj.CreateEnum("Show HUD", Color.white, (Enum)Settings.HUDShowMode, (Action<Enum>)delegate(Enum value) { Settings.SetHUDShowMode((HUDShowMode)(object)value); }); for (int i = 0; i < HUDLoader.LoadedHUDManifests.Count; i++) { int index = i; JSONHUDManifest manifest = HUDLoader.LoadedHUDManifests[index]; _hudPage.CreateFunction(manifest.Name, Color.white, (Action)delegate { HUDManager.LoadHUD(manifest.Name); }).Logo = manifest.Logo; } } public static void RefreshHUDPage() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) _hudPage.RemoveAll(); for (int i = 0; i < HUDLoader.LoadedHUDManifests.Count; i++) { int index = i; JSONHUDManifest manifest = HUDLoader.LoadedHUDManifests[index]; _hudPage.CreateFunction(manifest.Name, Color.white, (Action)delegate { HUDManager.LoadHUD(manifest.Name); }).Logo = manifest.Logo; } } } } namespace NEP.ScoreLab.HUD { public enum HUDShowMode { Always, UpdateOnly, Never } [RegisterTypeInIl2Cpp] public class Module : MonoBehaviour { public enum UIModuleType { Main, Descriptor } public UIModuleType ModuleType; private bool _reachedDecay; private bool _reachedPostDecay; public PackedValue PackedValue => _packedValue; public virtual PackedValue.PackedType PackedType => PackedValue.PackedType.Base; public virtual bool CanDecay => (Object)(object)((Component)this).transform.Find("-Persist") == (Object)null; public float DecayTime => _decayTime; public float PostDecayTime => _postDecayTime; protected TextMeshProUGUI _title { get; private set; } protected TextMeshProUGUI _value { get; private set; } protected Slider _timeBar { get; private set; } protected PackedValue _packedValue { get; private set; } protected bool _canDecay { get; private set; } protected bool _decayed { get; private set; } protected float _decayTime { get; private set; } protected float _postDecayTime { get; private set; } protected float _tDecay { get; private set; } protected float _tPostDecay { get; private set; } private string Path_Root => ((Object)this).name; protected virtual string Path_TitleText => "Title"; protected virtual string Path_ValueText => "Value"; protected virtual string Path_TimeBar => "TimeBar"; public Module(IntPtr ptr) : base(ptr) { } public virtual void OnModuleEnable() { API.UI.OnModuleEnabled?.Invoke(this); } public virtual void OnModuleDisable() { API.UI.OnModuleDisabled?.Invoke(this); } public virtual void OnUpdate() { } public void AssignPackedData(PackedValue packedValue) { if (packedValue != null) { _packedValue = packedValue; if (_packedValue.DecayTime != 0f) { SetDecayTime(_packedValue.DecayTime); } } } public void SetDecayTime(float decayTime) { _decayTime = decayTime; _tDecay = _decayTime; } public void SetPostDecayTime(float postDecayTime) { _postDecayTime = postDecayTime; _tPostDecay = _postDecayTime; } public bool IsDecaying() { return _reachedDecay; } public bool IsDecayed() { return _reachedPostDecay; } protected void SetText(TextMeshProUGUI text, string value) { if (!((Object)(object)text == (Object)null)) { ((TMP_Text)text).text = value; } } protected void SetText(TextMeshProUGUI text, int value) { if (!((Object)(object)text == (Object)null)) { SetText(text, value.ToString()); } } protected void SetText(TextMeshProUGUI text, float value) { if (!((Object)(object)text == (Object)null)) { SetText(text, value.ToString()); } } protected void SetBarValue(Slider timeBar, float value) { timeBar.value = value; } protected void SetMaxValueToBar(Slider timeBar, float value) { if (!((Object)(object)timeBar == (Object)null)) { timeBar.maxValue = value; } } protected void UpdateDecay() { if (!CanDecay) { return; } if (_tDecay < 0f) { if (!_reachedDecay) { API.UI.OnModuleDecayed?.Invoke(this); _reachedDecay = true; } _tPostDecay -= Time.deltaTime; if (_tPostDecay < 0f) { if (!_reachedPostDecay) { API.UI.OnModulePostDecayed?.Invoke(this); _reachedPostDecay = true; } _tDecay = _decayTime; _tPostDecay = _postDecayTime; _reachedDecay = false; _reachedPostDecay = false; ((Component)this).gameObject.SetActive(false); } } else { _tDecay -= Time.deltaTime; } } private void Start() { Transform val = ((Component)this).transform.Find(Path_TitleText); Transform val2 = ((Component)this).transform.Find(Path_ValueText); Transform val3 = ((Component)this).transform.Find(Path_TimeBar); _title = ((val != null) ? ((Component)val).GetComponent<TextMeshProUGUI>() : null); _value = ((val2 != null) ? ((Component)val2).GetComponent<TextMeshProUGUI>() : null); _timeBar = ((val3 != null) ? ((Component)val3).GetComponent<Slider>() : null); } private void OnEnable() { OnModuleEnable(); } private void OnDisable() { OnModuleEnable(); } private void Update() { OnUpdate(); } } [RegisterTypeInIl2Cpp] public class ModuleAnimator : MonoBehaviour { public Animator Animator; private Module _module; public ModuleAnimator(IntPtr ptr) : base(ptr) { } private void Awake() { _module = ((Component)this).GetComponent<Module>(); Animator = ((Component)this).GetComponent<Animator>(); } private void OnEnable() { API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueTierReached, (Action<PackedValue>)delegate { OnTierReached(); }); API.UI.OnModuleDecayed = (Action<Module>)Delegate.Combine(API.UI.OnModuleDecayed, new Action<Module>(OnModuleDecayed)); } private void OnDisable() { API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueTierReached, (Action<PackedValue>)delegate { OnTierReached(); }); API.UI.OnModuleDecayed = (Action<Module>)Delegate.Remove(API.UI.OnModuleDecayed, new Action<Module>(OnModuleDecayed)); } private void PlayAnimation(string name) { if (!((Object)(object)Animator == (Object)null)) { Animator.Play(name, -1, 0f); } } private void OnModuleEnabled(Module module) { if (!((Object)(object)_module != (Object)(object)module)) { if (_module.ModuleType == Module.UIModuleType.Descriptor) { PlayAnimation("descriptor_show"); } else { PlayAnimation("show"); } } } private void OnTierReached() { PlayAnimation("tier_reached"); } private void OnModuleDecayed(Module module) { if (!((Object)(object)_module != (Object)(object)module)) { if (_module.ModuleType == Module.UIModuleType.Descriptor) { PlayAnimation("descriptor_hide"); } else { PlayAnimation("hide"); } } } } [RegisterTypeInIl2Cpp] public class MultiplierModule : Module { private float _currentValue; private float _targetValue; private float _rate; private PackedMultiplier _packedMultiplier => (PackedMultiplier)base._packedValue; public MultiplierModule(IntPtr ptr) : base(ptr) { } private void Awake() { if (((Object)this).name == "MultiplierDescriptor" || ((Object)this).name == "Descriptor") { ModuleType = UIModuleType.Descriptor; } } public override void OnModuleEnable() { base.OnModuleEnable(); if (base._packedValue == null || _packedMultiplier == null) { return; } if (ModuleType == UIModuleType.Main) { SetText(base._value, ScoreTracker.Multiplier + "x"); } else if (ModuleType == UIModuleType.Descriptor) { SetText(base._title, _packedMultiplier.Name); SetText(base._value, _packedMultiplier.Multiplier + "x"); } if ((Object)(object)base._timeBar != (Object)null) { if (_packedMultiplier.Condition != string.Empty) { ((Component)base._timeBar).gameObject.SetActive(false); return; } ((Component)base._timeBar).gameObject.SetActive(true); SetMaxValueToBar(base._timeBar, _packedMultiplier.DecayTime); SetBarValue(base._timeBar, _packedMultiplier.DecayTime); } } public override void OnModuleDisable() { } public override void OnUpdate() { if (ModuleType == UIModuleType.Main) { SetTweenValue(ScoreTracker.Multiplier); _currentValue = Mathf.MoveTowards(_currentValue, _targetValue, _rate * Time.unscaledDeltaTime); if (Mathf.Approximately(_currentValue, _targetValue)) { _currentValue = _targetValue; } SetText(base._value, _currentValue.ToString("F2")); } if (_packedMultiplier != null) { if (_packedMultiplier.condition != null) { if (!_packedMultiplier.condition()) { UpdateDecay(); } } else { UpdateDecay(); } } else { UpdateDecay(); } if ((Object)(object)base._timeBar != (Object)null) { SetBarValue(base._timeBar, base._tDecay); } } private void SetTweenValue(float value) { _targetValue = value; _rate = Mathf.Abs(_targetValue - _currentValue) / 1f; } } [RegisterTypeInIl2Cpp] public class ScoreModule : Module { private float _targetValue; private float _currentValue; private float _rate = 4f; private PackedScore _packedScore => (PackedScore)base._packedValue; public ScoreModule(IntPtr ptr) : base(ptr) { } private void Awake() { if (((Object)this).name == "ScoreDescriptor" || ((Object)this).name == "Descriptor") { ModuleType = UIModuleType.Descriptor; } } public override void OnModuleEnable() { base.OnModuleEnable(); if (ModuleType == UIModuleType.Main) { SetText(base._value, ScoreTracker.Score); } if (base._packedValue != null && ModuleType == UIModuleType.Descriptor) { SetText(base._title, _packedScore.Name); SetText(base._value, $"+{Mathf.RoundToInt((float)_packedScore.Score * ScoreTracker.Multiplier)}"); } } public override void OnModuleDisable() { } public override void OnUpdate() { UpdateDecay(); if (ModuleType == UIModuleType.Main) { SetTweenValue(ScoreTracker.Score); _currentValue = Mathf.MoveTowards(_currentValue, _targetValue, _rate * Time.unscaledDeltaTime); if (Mathf.Approximately(_currentValue, _targetValue)) { _currentValue = _targetValue; } SetText(base._value, _currentValue.ToString("N0")); } } private void SetTweenValue(int value) { _targetValue = value; _rate = Mathf.Abs(_targetValue - _currentValue) / 1f; } } [RegisterTypeInIl2Cpp] public class HUD : MonoBehaviour { public Transform followTarget; public Module ScoreModule { get; set; } public Module MultiplierModule { get; set; } public Module HighScoreModule { get; set; } public HUD(IntPtr ptr) : base(ptr) { } private void Awake() { if ((Object)(object)((Component)this).transform.Find("MainScore") != (Object)null) { ScoreModule = ((Component)((Component)this).transform.Find("MainScore")).GetComponent<ScoreModule>(); } if (Object.op_Implicit((Object)(object)((Component)this).transform.Find("MainMultiplier"))) { MultiplierModule = ((Component)((Component)this).transform.Find("MainMultiplier")).GetComponent<MultiplierModule>(); } } private void OnEnable() { UpdateModule(null); UpdateModule(null); API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAdded, new Action<PackedValue>(UpdateModule)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueTierReached, new Action<PackedValue>(UpdateModule)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAccumulated, new Action<PackedValue>(UpdateModule)); API.Value.OnValueRemoved = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueRemoved, new Action<PackedValue>(UpdateModule)); } private void OnDisable() { API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAdded, new Action<PackedValue>(UpdateModule)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueTierReached, new Action<PackedValue>(UpdateModule)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAccumulated, new Action<PackedValue>(UpdateModule)); API.Value.OnValueRemoved = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueRemoved, new Action<PackedValue>(UpdateModule)); } private void Start() { if ((Object)(object)Player.GetPhysicsRig() != (Object)null) { followTarget = ((Rig)Player.ControllerRig).m_head; } } private void FixedUpdate() { //IL_0015: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)followTarget == (Object)null)) { Vector3 position = Vector3.Lerp(((Component)this).transform.position, followTarget.position + followTarget.forward * Settings.DistanceToCamera, Settings.MovementSmoothness * Time.unscaledDeltaTime); Quaternion rotation = Quaternion.LookRotation(followTarget.forward); ((Component)this).transform.position = position; ((Component)this).transform.rotation = rotation; } } public void SetParent(Transform parent) { ((Component)this).transform.SetParent(parent); } public void SetScoreModule(Module module) { ScoreModule = module; } public void SetMultiplierModule(Module module) { MultiplierModule = module; } public void UpdateModule(PackedValue data) { if (data is PackedScore) { ScoreModule.AssignPackedData(data); ScoreModule.OnModuleEnable(); } else if (data is PackedMultiplier) { MultiplierModule.AssignPackedData(data); MultiplierModule.OnModuleEnable(); } } } [RegisterTypeInIl2Cpp] public class DescriptorList : MonoBehaviour { public List<Module> ActiveModules; public int count = 6; public List<Module> Modules; public PackedValue.PackedType packedType { get; set; } public GameObject ModulePrefab { get; set; } public DescriptorList(IntPtr ptr) : base(ptr) { } private void Awake() { Modules = new List<Module>(); ActiveModules = new List<Module>(); for (int i = 0; i < ((Component)this).transform.childCount; i++) { Transform child = ((Component)this).transform.GetChild(i); Modules.Add(((Component)child).GetComponent<Module>()); } if (((Object)this).name == "ScoreDescriptors") { packedType = PackedValue.PackedType.Score; } else if (((Object)this).name == "MultiplierDescriptors") { packedType = PackedValue.PackedType.Multiplier; } } private void OnEnable() { API.UI.OnModulePostDecayed = (Action<Module>)Delegate.Combine(API.UI.OnModulePostDecayed, (Action<Module>)delegate(Module item) { ActiveModules.Remove(item); }); API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAdded, new Action<PackedValue>(SetModuleActive)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAccumulated, new Action<PackedValue>(SetModuleActive)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueTierReached, new Action<PackedValue>(SetModuleActive)); } private void OnDisable() { API.UI.OnModulePostDecayed = (Action<Module>)Delegate.Remove(API.UI.OnModulePostDecayed, (Action<Module>)delegate(Module item) { ActiveModules.Remove(item); }); API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAdded, new Action<PackedValue>(SetModuleActive)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAccumulated, new Action<PackedValue>(SetModuleActive)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueTierReached, new Action<PackedValue>(SetModuleActive)); } public void SetPackedType(int packedType) { this.packedType = (PackedValue.PackedType)packedType; } public void SetModuleActive(PackedValue value) { if (Modules == null || Modules.Count == 0 || value.PackedValueType != packedType) { return; } foreach (Module module in Modules) { if (!((Component)module).gameObject.activeInHierarchy) { module.AssignPackedData(value); module.SetDecayTime(value.DecayTime); module.SetPostDecayTime(0.5f); ((Component)module).gameObject.SetActive(true); ActiveModules.Add(module); break; } if (ActiveModules.Contains(module) && !module.IsDecaying() && module.PackedValue.eventType == value.eventType) { if (value.Stackable) { module.AssignPackedData(value); module.OnModuleEnable(); module.SetDecayTime(value.DecayTime); module.SetPostDecayTime(0.5f); break; } if (value.Tiers != null) { module.AssignPackedData(value); module.OnModuleEnable(); module.SetDecayTime(value.DecayTime); module.SetPostDecayTime(0.5f); break; } } } } public void PoolObjects() { if (!((Object)(object)ModulePrefab == (Object)null)) { for (int i = 0; i < count; i++) { Module component = Object.Instantiate<GameObject>(ModulePrefab, ((Component)this).transform).GetComponent<Module>(); component.ModuleType = Module.UIModuleType.Descriptor; Modules.Add(component); } } } } public static class HUDManager { private static GameObject _parentObject; public static List<HUD> LoadedHUDs { get; private set; } public static HUD ActiveHUD { get; private set; } public static HUD LastHUD { get; private set; } internal static void Initialize() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown _parentObject = new GameObject("[ScoreLab] - HUD Container"); LoadedHUDs = new List<HUD>(); Populate(); if (HUDLoader.LoadedHUDs.ContainsKey(Settings.SavedHUD)) { LoadHUD(Settings.SavedHUD); } else { LoadHUD("Coda"); } } internal static void Uninitialize() { } public static void Populate() { for (int i = 0; i < HUDLoader.LoadedHUDManifests.Count; i++) { JSONHUDManifest jSONHUDManifest = HUDLoader.LoadedHUDManifests[i]; GameObject obj = Object.Instantiate<GameObject>(HUDLoader.LoadedHUDs[jSONHUDManifest.Name]); ((Object)obj).name = jSONHUDManifest.Name; HUD component = obj.GetComponent<HUD>(); if (!((Object)(object)component == (Object)null)) { LoadedHUDs.Add(component); component.SetParent(_parentObject.transform); ((Component)component).gameObject.SetActive(false); } } } public static void HUDShowModeUpdated(HUDShowMode mode) { if (!((Object)(object)ActiveHUD == (Object)null)) { switch (mode) { case HUDShowMode.Always: ((Component)ActiveHUD).gameObject.SetActive(true); break; case HUDShowMode.Never: ((Component)ActiveHUD).gameObject.SetActive(false); break; } } } public static void LoadHUD(string name) { if ((Object)(object)ActiveHUD != (Object)null) { LastHUD = ActiveHUD; } UnloadHUD(); foreach (HUD loadedHUD in LoadedHUDs) { if (((Object)loadedHUD).name == name) { ActiveHUD = loadedHUD; break; } } if (!((Object)(object)ActiveHUD == (Object)null)) { Settings.SavedHUD = name; ValueManager.UsePackage(name); ((Component)ActiveHUD).gameObject.SetActive(true); ActiveHUD.SetParent(null); } } public static void UnloadHUD() { if ((Object)(object)ActiveHUD != (Object)null) { ActiveHUD.SetParent(_parentObject.transform); ((Component)ActiveHUD).gameObject.SetActive(false); ActiveHUD = null; } } public static void DestroyHUD() { if ((Object)(object)ActiveHUD != (Object)null) { Object.Destroy((Object)(object)ActiveHUD); ActiveHUD = null; } } public static void DestroyLoadedHUDs() { if (LoadedHUDs == null || LoadedHUDs.Count == 0) { return; } foreach (HUD loadedHUD in LoadedHUDs) { Object.Destroy((Object)(object)((Component)loadedHUD).gameObject); } LoadedHUDs.Clear(); } } } namespace NEP.ScoreLab.Data { public static class HUDLoader { public static Dictionary<string, AudioClip> HUDAudioBank; public static Dictionary<string, GameObject> LoadedHUDs; public static List<JSONHUDManifest> LoadedHUDManifests; private static List<AssetBundle> _assetBundles; private static List<Object> _persistentBundleObjects; public static void Initialize() { LoadedHUDs = new Dictionary<string, GameObject>(); HUDAudioBank = new Dictionary<string, AudioClip>(); LoadedHUDManifests = new List<JSONHUDManifest>(); _persistentBundleObjects = new List<Object>(); _assetBundles = new List<AssetBundle>(); LoadHUDs(); } public static void SpawnDefaultUI() { SpawnUI("Coda"); } public static void SpawnUI(string name) { foreach (JSONHUDManifest loadedHUDManifest in LoadedHUDManifests) { if (loadedHUDManifest.Name == name) { SpawnUI(LoadedHUDs[name]); } } } public static void SpawnUI(GameObject uiObject) { Object.Instantiate<GameObject>(uiObject); } public static void LoadHUDs() { foreach (string item2 in Directory.EnumerateDirectories(Path.Combine(MelonEnvironment.UserDataDirectory, "Not Enough Photons/ScoreLab"))) { IEnumerable<string> enumerable = Directory.EnumerateFiles(item2); string text = string.Empty; string text2 = string.Empty; foreach (string item3 in enumerable) { if (item3.EndsWith(".hud")) { text = item3; } if (item3.EndsWith(".hud_manifest")) { text2 = item3; } } if (text == string.Empty) { Main.Logger.Error("Missing .HUD file in " + item2 + "!"); continue; } if (text2 == string.Empty) { Main.Logger.Error("Missing HUD manifest file in " + item2 + "!"); continue; } JSONHUDManifest item = default(JSONHUDManifest); if (!item.FromJSON(text2)) { Main.Logger.Error("Failed to read HUD manifest data! Source: " + item2); continue; } AssetBundle val = AssetBundle.LoadFromFile(text); GameObject value = HelperMethods.LoadPersistentAsset<GameObject>(val, item.AssetName); Il2CppReferenceArray<Object> val2 = val.LoadAllAssets(); Texture2D val3 = HelperMethods.LoadPersistentAsset<Texture2D>(val, "Logo"); if ((Object)(object)val3 != (Object)null) { item.SetHUDLogo(val3); } _assetBundles.Add(val); LoadedHUDManifests.Add(item); LoadedHUDs.Add(item.Name, value); if (val2 == null || ((Il2CppArrayBase<Object>)(object)val2).Length == 0) { continue; } foreach (Object item4 in (Il2CppArrayBase<Object>)(object)val2) { AudioClip val4 = ((Il2CppObjectBase)item4).TryCast<AudioClip>(); if ((Object)(object)val4 != (Object)null) { ((Object)val4).hideFlags = (HideFlags)32; HUDAudioBank.Add(item4.name, val4); } } } } public static void ReloadHUDs() { if ((Object)(object)HUDManager.ActiveHUD != (Object)null) { HUDManager.DestroyHUD(); } HUDManager.DestroyLoadedHUDs(); HUDAudioBank.Clear(); LoadedHUDManifests.Clear(); LoadedHUDs.Clear(); foreach (AssetBundle assetBundle in _assetBundles) { assetBundle.Unload(true); } _assetBundles.Clear(); LoadHUDs(); SLMenu.RefreshHUDPage(); HUDManager.Populate(); HUDManager.LoadHUD(Settings.SavedHUD); } } public struct JSONAudioParams { public string[] sounds; public float volume; public float pitch; public bool FromJSON(JObject jObject) { if (jObject == null) { return false; } JToken obj = jObject["Clips"]; JArray val = (JArray)(object)((obj is JArray) ? obj : null); if (val != null) { sounds = new string[((JContainer)val).Count]; for (int i = 0; i < sounds.Length; i++) { sounds[i] = Extensions.Value<string>((IEnumerable<JToken>)val[i]); } } volume = Extensions.Value<float>((IEnumerable<JToken>)jObject["Volume"]); pitch = Extensions.Value<float>((IEnumerable<JToken>)jObject["Pitch"]); return true; } } public struct JSONHUDManifest { public string Name; public string Author; public string Description; public string[] Tags; public string AssetName; public Texture2D Logo; public bool FromJSON(string pathToJson) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown using (StreamReader streamReader = new StreamReader(pathToJson)) { JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { JToken obj = JToken.ReadFrom((JsonReader)(object)val); JObject val2 = (JObject)(object)((obj is JObject) ? obj : null); if (val2 == null) { return false; } Name = Extensions.Value<string>((IEnumerable<JToken>)val2["name"]); Author = Extensions.Value<string>((IEnumerable<JToken>)val2["author"]); AssetName = Extensions.Value<string>((IEnumerable<JToken>)val2["assetName"]); } finally { ((IDisposable)val)?.Dispose(); } } return true; } public void SetHUDLogo(Texture2D texture) { Logo = texture; } } public struct JSONMult { public string EventType; public string TierEventType; public float DecayTime; public bool Stackable; public JSONAudioParams EventAudio; public string Name; public float Multiplier; public string Condition; public int TierRequirement; public JSONMult[] Tiers; public bool FromJSON(string pathToJson) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown using (StreamReader streamReader = new StreamReader(pathToJson)) { JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { JToken obj = JToken.ReadFrom((JsonReader)(object)val); JObject val2 = (JObject)(object)((obj is JObject) ? obj : null); if (val2 == null) { return false; } ReadMultObject(val2); } finally { ((IDisposable)val)?.Dispose(); } } return true; } private void ReadMultObject(JObject obj) { EventType = Extensions.Value<string>((IEnumerable<JToken>)obj["EventType"]); DecayTime = Extensions.Value<float>((IEnumerable<JToken>)obj["DecayTime"]); Stackable = Extensions.Value<bool>((IEnumerable<JToken>)obj["Stackable"]); Condition = Extensions.Value<string>((IEnumerable<JToken>)obj["Condition"]); EventAudio.FromJSON(Extensions.Value<JObject>((IEnumerable<JToken>)obj["EventAudio"])); Name = Extensions.Value<string>((IEnumerable<JToken>)obj["Name"]); Multiplier = Extensions.Value<float>((IEnumerable<JToken>)obj["Multiplier"]); TierRequirement = Extensions.Value<int>((IEnumerable<JToken>)obj["TierRequirement"]); JToken obj2 = obj["Tiers"]; JArray val = ((obj2 != null) ? Extensions.Value<JArray>((IEnumerable<JToken>)obj2) : null); List<JSONMult> list = new List<JSONMult>(); if (val != null) { for (int i = 0; i < ((JContainer)val).Count; i++) { JSONMult item = default(JSONMult); JToken obj3 = val[i]; JObject obj4 = (JObject)(object)((obj3 is JObject) ? obj3 : null); item.ReadMultObject(obj4); list.Add(item); } Tiers = list.ToArray(); } } } public struct JSONScore { public string EventType; public string TierEventType; public float DecayTime; public bool Stackable; public JSONAudioParams EventAudio; public string Name; public int Score; public int TierRequirement; public JSONScore[] Tiers; public bool FromJSON(string pathToJson) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown using (StreamReader streamReader = new StreamReader(pathToJson)) { JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { JToken obj = JToken.ReadFrom((JsonReader)(object)val); JObject val2 = (JObject)(object)((obj is JObject) ? obj : null); if (val2 == null) { return false; } ReadScoreObject(val2); } finally { ((IDisposable)val)?.Dispose(); } } return true; } private void ReadScoreObject(JObject obj) { EventType = Extensions.Value<string>((IEnumerable<JToken>)obj["EventType"]); DecayTime = Extensions.Value<float>((IEnumerable<JToken>)obj["DecayTime"]); Stackable = Extensions.Value<bool>((IEnumerable<JToken>)obj["Stackable"]); EventAudio.FromJSON(Extensions.Value<JObject>((IEnumerable<JToken>)obj["EventAudio"])); Name = Extensions.Value<string>((IEnumerable<JToken>)obj["Name"]); Score = Extensions.Value<int>((IEnumerable<JToken>)obj["Score"]); TierRequirement = Extensions.Value<int>((IEnumerable<JToken>)obj["TierRequirement"]); JToken obj2 = obj["Tiers"]; JArray val = ((obj2 != null) ? Extensions.Value<JArray>((IEnumerable<JToken>)obj2) : null); List<JSONScore> list = new List<JSONScore>(); if (val != null) { for (int i = 0; i < ((JContainer)val).Count; i++) { JSONScore item = default(JSONScore); JToken obj3 = val[i]; JObject obj4 = (JObject)(object)((obj3 is JObject) ? obj3 : null); item.ReadScoreObject(obj4); list.Add(item); } Tiers = list.ToArray(); } } } public struct MarrowSceneInfo { public string LevelTitle; public string Barcode; public MarrowScene MarrowScene; } public static class EventType { public static class Score { public static readonly string Kill = "SCORE_KILL"; public static readonly string Headshot = "SCORE_HEADSHOT"; public static readonly string EnemyMidAirKill = "SCORE_MID_AIR"; public static readonly string GameWaveCompleted = "SCORE_WAVE_COMPLETED"; public static readonly string GameRoundCompleted = "SCORE_ROUND_COMPLETED"; public static readonly string Crabcest = "SCORE_CRABCEST"; public static readonly string Facehug = "SCORE_FACEHUG"; public static readonly string StealthKill = "SCORE_STEALTH_KILL"; } public static class Mult { public static readonly string Kill = "MULT_KILL"; public static readonly string MidAir = "MULT_MIDAIR"; public static readonly string Seated = "MULT_SEATED"; public static readonly string SecondWind = "MULT_SECONDWIND"; public static readonly string Ragolled = "MULT_RAGDOLLED"; public static readonly string SwappedAvatars = "MULT_SWAPPED_AVATARS"; public static readonly string SlowMo = "MULT_SLOWMO"; } public static readonly string None = "None"; } public class PackedAudioParams { public AudioClip[] Clips { get; private set; } public float Volume { get; private set; } public float Pitch { get; private set; } public PackedAudioParams() { Clips = null; Volume = 1f; Pitch = 1f; } public PackedAudioParams(JSONAudioParams audioParams) { Clips = (AudioClip[])(object)new AudioClip[audioParams.sounds.Length]; for (int i = 0; i < Clips.Length; i++) { Clips[i] = HUDLoader.HUDAudioBank[audioParams.sounds[i]]; } Volume = audioParams.volume; Pitch = audioParams.pitch; } } public class PackedHighScore : PackedValue { public int bestScore; public override PackedType PackedValueType => PackedType.HighScore; public PackedHighScore(string name, int bestScore) { this.bestScore = bestScore; } public override void OnValueCreated() { } public override void OnValueRemoved() { } } [Serializable] public class PackedMultiplier : PackedValue { public float Multiplier; public float AccumulatedMultiplier; public string Condition; private bool _timed; private bool _timeBegin; public override PackedType PackedValueType => PackedType.Multiplier; public float Elapsed => _tDecay; public Func<bool> condition { get; private set; } public PackedMultiplier() { } public PackedMultiplier(JSONMult mult, bool useTiers = false) { eventType = mult.EventType; DecayTime = mult.DecayTime; Stackable = mult.Stackable; Name = mult.Name; Multiplier = mult.Multiplier; Condition = mult.Condition; TierRequirement = mult.TierRequirement; EventAudio = new PackedAudioParams(mult.EventAudio); if (useTiers) { TierEventType = mult.TierEventType; } } public override void OnValueCreated() { if (DecayTime != 0f) { _timed = true; } condition = API.GameConditions.GetCondition(Condition); AccumulatedMultiplier = Multiplier; _tDecay = DecayTime; } public override void OnValueRemoved() { _timeBegin = false; ResetTier(); } public override void OnUpdate() { if (condition != null && !condition()) { ScoreTracker.Remove(this); } OnUpdateDecay(); } public override void OnUpdateDecay() { if (_timed) { if (!_timeBegin) { API.Multiplier.OnMultiplierTimeBegin?.Invoke(this); _timeBegin = true; } if (_tDecay <= 0f) { API.Multiplier.OnMultiplierTimeExpired?.Invoke(this); _tDecay = DecayTime; ScoreTracker.Remove(this); } _tDecay -= Time.deltaTime; } } } [Serializable] public class PackedScore : PackedValue { public int Score; public int AccumulatedScore; public override PackedType PackedValueType => PackedType.Score; public PackedScore() { } public PackedScore(JSONScore score, bool useTiers = false) { eventType = score.EventType; DecayTime = score.DecayTime; Stackable = score.Stackable; Name = score.Name; Score = score.Score; TierRequirement = score.TierRequirement; EventAudio = new PackedAudioParams(score.EventAudio); if (useTiers) { TierEventType = score.TierEventType; } else { AccumulatedScore = score.Score; } } public override void OnValueCreated() { _tDecay = DecayTime; AccumulatedScore = Score; } public override void OnValueRemoved() { ResetTier(); } public override void OnUpdate() { OnUpdateDecay(); } public override void OnUpdateDecay() { if (_tDecay <= 0f) { ScoreTracker.Remove(this); } _tDecay -= Time.deltaTime; } } [Serializable] public class PackedValue { public enum PackedType { Base, Score, Multiplier, HighScore, Misc } public string Name; public string eventType; public string TierEventType; public PackedAudioParams EventAudio; public bool Stackable; public float DecayTime; public float PostDecayTime; public PackedValue Parent; public PackedValue[] Tiers; public int TierRequirement; protected float _tDecay; private int _tierIndex; private int _tierRequirementIndex; public virtual PackedType PackedValueType => PackedType.Base; public PackedValue CurrentTier { get { if (Tiers == null || Tiers.Length == 0) { return this; } if (_tierIndex == Tiers.Length) { _tierIndex = Tiers.Length; return Tiers[_tierIndex]; } return Tiers[_tierIndex]; } } public PackedValue NextTier { get { if (_tierIndex + 1 >= Tiers.Length) { return Tiers[_tierIndex]; } return Tiers[_tierIndex + 1]; } } public int TierIndex => _tierIndex; public int TierRequirementIndex => _tierRequirementIndex; public virtual bool IsActive { get; } public virtual void OnValueCreated() { } public virtual void OnValueRemoved() { } public virtual void OnUpdate() { } public virtual void OnUpdateDecay() { } public void SetDecayTime(float decayTime) { _tDecay = decayTime; } public void ToNextTier() { _tierRequirementIndex++; if (_tierRequirementIndex >= TierRequirement) { _tierRequirementIndex = TierRequirement; API.Value.OnValueTierReached?.Invoke(CurrentTier); if (_tierIndex + 1 < Tiers.Length) { _tierIndex++; } } } protected void ResetTier() { _tierIndex = 0; } } public static class ValueManager { public static Dictionary<string, int> HighScoreTable; public static readonly string Path_Developer = Path.Combine(MelonEnvironment.UserDataDirectory, "Not Enough Photons"); public static readonly string Path_Mod = Path.Combine(Path_Developer, "ScoreLab"); private static readonly string File_HighScores = Path.Combine(Path_Mod, "high_score_table.json"); public static Dictionary<string, ValuePackage> Packages { get; private set; } public static ValuePackage ActivePackage { get; private set; } public static void Initialize() { HighScoreTable = new Dictionary<string, int>(); Packages = new Dictionary<string, ValuePackage>(); foreach (JSONHUDManifest loadedHUDManifest in HUDLoader.LoadedHUDManifests) { JSONScore[] scoresForHUD = GetScoresForHUD(loadedHUDManifest.Name); JSONMult[] multipliersForHUD = GetMultipliersForHUD(loadedHUDManifest.Name); PackedScore[] scores = CreateScoreObjects(scoresForHUD); PackedMultiplier[] multipliers = CreateMultiplierObjects(multipliersForHUD); Packages.Add(loadedHUDManifest.Name, new ValuePackage(scores, multipliers)); } UsePackage(Settings.SavedHUD); } public static string[] GetAllFiles(string path, string extensionFilter) { string[] files = Directory.GetFiles(path); List<string> list = new List<string>(); string[] array = files; foreach (string text in array) { if (text.EndsWith(extensionFilter)) { list.Add(text); } } return list.ToArray(); } public static void UsePackage(string name) { if (Packages.TryGetValue(name, out var value)) { ActivePackage = value; } } public static PackedValue Get(string eventType) { if (ActivePackage.Values == null) { return null; } if (ActivePackage.Values.TryGetValue(eventType, out var value)) { return value; } return null; } public static Dictionary<string, int> ReadHighScore() { return JsonConvert.DeserializeObject(File_HighScores) as Dictionary<string, int>; } public static void WriteHighScore() { string file_HighScores = File_HighScores; if (!File.Exists(file_HighScores)) { Main.Logger.Warning("High score file doesn't exist! Creating one."); File.Create(file_HighScores); } else { string contents = JsonConvert.SerializeObject((object)HighScoreTable); File.WriteAllText(file_HighScores, contents); } } public static void WriteBestScore(PackedHighScore highScore) { string name = highScore.Name; int bestScore = highScore.bestScore; HighScoreTable.Add(name, bestScore); } private static JSONScore[] GetScoresForHUD(string name) { string path = Path.Combine(Path_Mod, name + "/Data/Score"); if (!Directory.Exists(path)) { Main.Logger.Warning("HUD " + name + " doesn't have a score data folder!"); return null; } string[] allFiles = GetAllFiles(path, ".json"); List<JSONScore> list = new List<JSONScore>(); string[] array = allFiles; for (int i = 0; i < array.Length; i++) { JSONScore item = ReadScoreData(array[i]); list.Add(item); } return list.ToArray(); } private static JSONMult[] GetMultipliersForHUD(string name) { string path = Path.Combine(Path_Mod, name + "/Data/Multiplier"); if (!Directory.Exists(path)) { Main.Logger.Warning("HUD " + name + " doesn't have a multiplier data folder!"); return null; } string[] allFiles = GetAllFiles(path, ".json"); List<JSONMult> list = new List<JSONMult>(); string[] array = allFiles; for (int i = 0; i < array.Length; i++) { JSONMult item = ReadMultiplierData(array[i]); list.Add(item); } return list.ToArray(); } private static PackedScore[] CreateScoreObjects(JSONScore[] scores) { if (scores == null) { return null; } List<PackedScore> list = new List<PackedScore>(); for (int i = 0; i < scores.Length; i++) { JSONScore score = scores[i]; PackedScore packedScore = new PackedScore(score); if (score.Tiers != null && score.Tiers.Length != 0) { List<PackedScore> list2 = new List<PackedScore>(); JSONScore[] tiers = score.Tiers; for (int j = 0; j < tiers.Length; j++) { PackedScore packedScore2 = new PackedScore(tiers[j], useTiers: true); packedScore2.eventType = packedScore.eventType; list2.Add(packedScore2); } PackedValue[] tiers2 = list2.ToArray(); packedScore.Tiers = tiers2; } list.Add(packedScore); } return list.ToArray(); } private static PackedMultiplier[] CreateMultiplierObjects(JSONMult[] multipliers) { if (multipliers == null) { return null; } List<PackedMultiplier> list = new List<PackedMultiplier>(); for (int i = 0; i < multipliers.Length; i++) { JSONMult mult = multipliers[i]; PackedMultiplier packedMultiplier = new PackedMultiplier(mult); if (mult.Tiers != null && mult.Tiers.Length != 0) { List<PackedMultiplier> list2 = new List<PackedMultiplier>(); JSONMult[] tiers = mult.Tiers; for (int j = 0; j < tiers.Length; j++) { PackedMultiplier packedMultiplier2 = new PackedMultiplier(tiers[j], useTiers: true); packedMultiplier2.eventType = packedMultiplier.eventType; list2.Add(packedMultiplier2); } PackedValue[] tiers2 = list2.ToArray(); packedMultiplier.Tiers = tiers2; } list.Add(packedMultiplier); } return list.ToArray(); } private static JSONScore ReadScoreData(string file) { JSONScore result = default(JSONScore); result.FromJSON(file); return result; } private static JSONMult ReadMultiplierData(string file) { JSONMult result = default(JSONMult); result.FromJSON(file); return result; } } public struct ValuePackage { public Dictionary<string, PackedValue> Values; public ValuePackage(PackedScore[] scores, PackedMultiplier[] multipliers) { Values = new Dictionary<string, PackedValue>(); if (scores != null) { foreach (PackedScore packedScore in scores) { Values.Add(packedScore.eventType, packedScore); } } if (multipliers != null) { foreach (PackedMultiplier packedMultiplier in multipliers) { Values.Add(packedMultiplier.eventType, packedMultiplier); } } } } } namespace NEP.ScoreLab.Core { public static class API { public static class Value { public static Action<PackedValue> OnValueAdded; public static Action<PackedValue> OnValueAccumulated; public static Action<PackedValue> OnValueTierReached; public static Action<PackedValue> OnValueRemoved; } public static class Score { public static Action<int> OnScoreUpdated; public static Action<int> OnScoreDifferenceUpdated; public static Action<int> OnLastScoreUpdated; } public static class Multiplier { public static Action<PackedMultiplier> OnMultiplierTimeBegin; public static Action<PackedMultiplier> OnMultiplierTimeExpired; } public static class HighScore { public static Action<PackedHighScore> OnHighScoreReached; public static Action<PackedHighScore> OnHighScoreUpdated; public static Action<PackedHighScore> OnHighScoreLoaded; public static Action<PackedHighScore> OnHighScoreSaved; } public static class GameConditions { private static Dictionary<string, Func<bool>> _conditionTable = new Dictionary<string, Func<bool>> { { "IsPlayerMoving", () => ScoreDirector.IsPlayerMoving }, { "IsPlayerSeated", () => ScoreDirector.IsPlayerSeated }, { "IsPlayerInAir", () => ScoreDirector.IsPlayerInAir }, { "IsPlayerRagdolled", () => ScoreDirector.IsPlayerRagdolled }, { "IsSlowMoEnabled", () => ScoreDirector.IsSlowMoEnabled } }; public static Func<bool> GetCondition(string cond) { if (string.IsNullOrEmpty(cond)) { Debug.LogWarning(Object.op_Implicit(cond + " doesn't exist in the condition table.")); return null; } if (!_conditionTable.ContainsKey(cond)) { Debug.LogWarning(Object.op_Implicit(cond + " doesn't exist in the condition table.")); return null; } return _conditionTable[cond]; } } public static class UI { public static Action<NEP.ScoreLab.HUD.Module> OnModuleEnabled; public static Action<NEP.ScoreLab.HUD.Module> OnModuleDisabled; public static Action<NEP.ScoreLab.HUD.Module> OnModuleDecayed; public static Action<NEP.ScoreLab.HUD.Module> OnModulePostDecayed; } } public static class ScoreDirector { public static class Patches { [HarmonyPatch(typeof(Projectile), "Awake")] public static class ProjectilePatch { public static void Postfix(Projectile __instance) { Action<Collider, Vector3, Vector3> action = OnProjectileCollision; ((UnityEvent<Collider, Vector3, Vector3>)(object)__instance.onCollision).AddListener(UnityAction<Collider, Vector3, Vector3>.op_Implicit(action)); } private static void OnProjectileCollision(Collider collider, Vector3 world, Vector3 normal) { MarrowBody val = MarrowBody.Cache.Get(((Component)collider).gameObject); if (!((Object)(object)val == (Object)null)) { TriggerRefProxy component = ((Component)val).GetComponent<TriggerRefProxy>(); if (!((Object)(object)component == (Object)null) && !component.aiManager.isDead && (Object)(object)((Component)component.targetHead).gameObject == (Object)(object)((Component)val).gameObject) { ScoreTracker.Add(EventType.Score.Headshot); } } } } [HarmonyPatch(typeof(RigManager), "SwitchAvatar")] public static class RigManagerSwapAvatarPatch { public static void Postfix(Avatar newAvatar) { _playerRecentlySwappedAvatars = true; } } [HarmonyPatch(typeof(BehaviourCrablet))] [HarmonyPatch("AttachToFace")] public static class CrabletAttachToFacePatch { public static void Postfix(Rigidbody face, TriggerRefProxy trp, bool preAttach = false, bool isPlayer = true) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if (!isPlayer) { if ((int)trp.npcType == 32) { ScoreTracker.Add(EventType.Score.Crabcest); } else { ScoreTracker.Add(EventType.Score.Facehug); } } } } [HarmonyPatch(typeof(Seat))] [HarmonyPatch("Register")] public static class RegisterSeatPatch { public static void Postfix(RigManager rM) { IsPlayerSeated = true; ScoreTracker.Add(EventType.Mult.Seated); } } [HarmonyPatch(typeof(Seat))] [HarmonyPatch("DeRegister")] public static class DeRegisterSeatPatch { public static void Postfix() { IsPlayerSeated = false; } } [HarmonyPatch(typeof(Player_Health))] [HarmonyPatch("LifeSavingDamgeDealt")] public static class SecondWindPatch { public static void Postfix() { ScoreTracker.Add(EventType.Mult.SecondWind); } } [HarmonyPatch(typeof(Arena_GameController))] [HarmonyPatch("StartNextWave")] public static class StartNextWavePatch { public static void Postfix(Arena_GameController __instance) { ScoreTracker.Add(EventType.Score.GameWaveCompleted); } } [HarmonyPatch(typeof(Arena_GameController))] [HarmonyPatch("EndOfRound")] public static class StartNextRoundPatch { public static void Postfix(Arena_GameController __instance) { ScoreTracker.Add(EventType.Score.GameRoundCompleted); } } [HarmonyPatch(typeof(PhysicsRig))] [HarmonyPatch("OnUpdate")] public static class PhysRigPatch { private static bool _midAirTargetBool; private static float _tMidAirDelay = 0.5f; private static float _tAirTime; private static bool _ragdolledTargetBool; private static float _tRagdollDelay = 0.5f; private static float _tRagdollTime; public static void Postfix(PhysicsRig __instance) { IsPlayerInAir = !__instance.physG.isGrounded; if (IsPlayerInAir) { if (!_midAirTargetBool) { _tAirTime += Time.deltaTime; if (_tAirTime > _tMidAirDelay) { ScoreTracker.Add(EventType.Mult.MidAir); _midAirTargetBool = true; } } } else { _tAirTime = 0f; _midAirTargetBool = false; } if (IsPlayerRagdolled) { if (!_ragdolledTargetBool) { _ragdolledTargetBool = true; } } else { _ragdolledTargetBool = false; } if (_playerRecentlySwappedAvatars) { ScoreTracker.Add(EventType.Mult.SwappedAvatars); _playerRecentlySwappedAvatars = false; } } } [HarmonyPatch(typeof(PhysicsRig))] [HarmonyPatch("RagdollRig")] public static class PhysRigRagdollPatch { public static void Postfix(PhysicsRig __instance) { IsPlayerRagdolled = true; } } [HarmonyPatch(typeof(PhysicsRig))] [HarmonyPatch("UnRagdollRig")] public static class PhysRigUnRagdollPatch { public static void Postfix(PhysicsRig __instance) { IsPlayerRagdolled = false; } } [HarmonyPatch(typeof(TimeManager), "OnPostTimeUpdate")] public static class TimeManagerUpdatePatch { private static bool _slowmoSwitch; public static void Postfix() { } } [HarmonyPatch(typeof(TimeManager), "INCREASE_TIMESCALE")] public static class TimeManagerIncreaseTimePatch { public static void Postfix() { } } [HarmonyPatch(typeof(TimeManager), "DECREASE_TIMESCALE")] public static class TimeManagerDecreaseTimePatch { public static void Postfix() { } } public static void InitPatches() { Hooking.OnNPCKillStart += OnAIDeath; } public static void OnAIDeath(BehaviourBaseNav behaviour) { ScoreTracker.Add(ValueManager.Get(EventType.Score.Kill)); ScoreTracker.Add(ValueManager.Get(EventType.Mult.Kill)); if (!behaviour.sensors.isGrounded) { ScoreTracker.Add(EventType.Score.EnemyMidAirKill); } if ((Object)(object)behaviour.sensors.target == (Object)null) { ScoreTracker.Add(EventType.Score.StealthKill); } } } public static readonly string PlayerName = ""; public static bool IsPlayerMoving = false; public static bool IsPlayerInAir = false; public static bool IsPlayerSeated = false; public static bool IsPlayerRagdolled = false; public static bool IsSlowMoEnabled = false; private static bool _playerRecentlySwappedAvatars = false; } public static class ScoreTracker { private static int _score = 0; private static int _lastScore = 0; private static float _multiplier = 1f; private static float _baseMultiplier = 1f; public static List<PackedValue> ActiveValues { get; private set; } public static int Score => _score; public static int LastScore => _lastScore; public static float Multiplier => _multiplier; public static void Initialize() { ActiveValues = new List<PackedValue>(); } public static void Update() { if (ActiveValues != null) { for (int i = 0; i < ActiveValues.Count; i++) { ActiveValues[i].OnUpdate(); } } } public static void Add(string eventType) { Add(Create(eventType)); } public static void Add(PackedValue value) { if (value != null) { if (value.PackedValueType == PackedValue.PackedType.Score) { SetPackedScore((PackedScore)value); } else if (value.PackedValueType == PackedValue.PackedType.Multiplier) { SetPackedMultiplier((PackedMultiplier)value); } } } public static void Remove(PackedValue value) { if (value.PackedValueType == PackedValue.PackedType.Score) { ActiveValues.Remove(value); value.OnValueRemoved(); API.Value.OnValueRemoved?.Invoke(value); } else if (value.PackedValueType == PackedValue.PackedType.Multiplier) { ActiveValues.Remove(value); RemoveMultiplier((value as PackedMultiplier).AccumulatedMultiplier); value.OnValueRemoved(); API.Value.OnValueRemoved?.Invoke(value); } } public static void AddScore(int score) { _lastScore = _score; _score += Mathf.RoundToInt((float)score * _multiplier); } public static void AddMultiplier(float multiplier) { _multiplier += multiplier; } public static void SetMultiplier(float multiplier) { _multiplier = multiplier; } public static void ResetScore() { _score = 0; _lastScore = 0; } public static void ResetMultiplier() { _multiplier = 1f; } public static void ResetAll() { ResetScore(); ResetMultiplier(); ResetHighScore(); ActiveValues.Clear(); } public static void ResetHighScore() { } public static void RemoveMultiplier(float multiplier) { if (_multiplier < _baseMultiplier) { _multiplier = _baseMultiplier; } _multiplier -= multiplier; } public static bool CheckDuplicate(PackedValue value) { foreach (PackedValue activeValue in ActiveValues) { if (activeValue.eventType == value.eventType) { return true; } } return false; } private static void SetPackedScore(PackedScore score) { if (score != null) { if (!CheckDuplicate(score)) { InitializeValue(score); AddScore(score.Score); ActiveValues.Add(score); API.Value.OnValueAdded?.Invoke(score); } else if (score.Tiers != null) { PackedScore clone = GetClone<PackedScore>(score); PackedScore packedScore = (PackedScore)clone.CurrentTier; clone.ToNextTier(); clone.TierRequirement = packedScore.TierRequirement; clone.SetDecayTime(packedScore.DecayTime); AddScore(packedScore.Score); } else if (score.Stackable) { PackedScore clone2 = GetClone<PackedScore>(score); AddScore(score.Score); clone2.SetDecayTime(clone2.DecayTime); clone2.AccumulatedScore += clone2.Score; API.Value.OnValueAccumulated?.Invoke(clone2); } else { PackedScore packedScore2 = CopyFromScore(score); InitializeValue(packedScore2); AddScore(packedScore2.Score); ActiveValues.Add(packedScore2); API.Value.OnValueAdded?.Invoke(packedScore2); } } } private static void SetPackedMultiplier(PackedMultiplier multiplier) { if (multiplier != null) { if (!CheckDuplicate(multiplier)) { InitializeValue(multiplier); AddMultiplier(multiplier.Multiplier); ActiveValues.Add(multiplier); API.Value.OnValueAdded?.Invoke(multiplier); } else if (multiplier.Tiers != null) { PackedMultiplier clone = GetClone<PackedMultiplier>(multiplier); PackedMultiplier packedMultiplier = (PackedMultiplier)clone.CurrentTier; clone.ToNextTier(); clone.TierRequirement = packedMultiplier.TierRequirement; clone.SetDecayTime(packedMultiplier.DecayTime); AddMultiplier(packedMultiplier.Multiplier); multiplier.AccumulatedMultiplier += packedMultiplier.Multiplier; API.Value.OnValueTierReached?.Invoke(packedMultiplier); } else if (multiplier.Stackable) { PackedMultiplier clone2 = GetClone<PackedMultiplier>(multiplier); AddMultiplier(multiplier.Multiplier); clone2.SetDecayTime(clone2.DecayTime); clone2.AccumulatedMultiplier += clone2.Multiplier; API.Value.OnValueAccumulated?.Invoke(clone2); } else { PackedMultiplier packedMultiplier2 = CopyFromMult(multiplier); InitializeValue(packedMultiplier2); AddMultiplier(multiplier.Multiplier); ActiveValues.Add(packedMultiplier2); API.Value.OnValueAdded?.Invoke(packedMultiplier2); } } } private static PackedScore CopyFromScore(PackedScore original) { return new PackedScore { eventType = original.eventType, Name = original.Name, Score = original.Score, EventAudio = original.EventAudio, DecayTime = original.DecayTime }; } private static PackedMultiplier CopyFromMult(PackedMultiplier original) { return new PackedMultiplier { eventType = original.eventType, Name = original.Name, Multiplier = original.Multiplier, EventAudio = original.EventAudio, DecayTime = original.DecayTime, Condition = original.Condition }; } private static PackedValue Create(string eventType) { PackedValue packedValue = ValueManager.Get(eventType); if (packedValue == null) { return null; } if (packedValue.PackedValueType == PackedValue.PackedType.Score) { PackedScore packedScore = (PackedScore)packedValue; return new PackedScore { eventType = packedScore.eventType, Stackable = packedScore.Stackable, DecayTime = packedScore.DecayTime, Name = packedScore.Name, Score = packedScore.Score, EventAudio = packedScore.EventAudio, TierRequirement = packedScore.TierRequirement, Tiers = packedScore.Tiers }; } if (packedValue.PackedValueType == PackedValue.PackedType.Multiplier) { PackedMultiplier packedMultiplier = (PackedMultiplier)packedValue; return new PackedMultiplier { eventType = packedMultiplier.eventType, Stackable = packedMultiplier.Stackable, DecayTime = packedMultiplier.DecayTime, Name = packedMultiplier.Name, Multiplier = packedMultiplier.Multiplier, Condition = packedMultiplier.Condition, EventAudio = packedMultiplier.EventAudio, TierRequirement = packedMultiplier.TierRequirement, Tiers = packedMultiplier.Tiers }; } return null; } private static void InitializeValue(PackedValue value) { value.OnValueCreated(); value.SetDecayTime(value.DecayTime); } private static T GetClone<T>(PackedValue value) where T : PackedValue { return (T)ActiveValues.Find((PackedValue match) => match.eventType == value.eventType); } } public static class Settings { public static float DistanceToCamera; public static float MovementSmoothness; public static bool UseAnnouncer; public static string SavedHUD; public static HUDShowMode HUDShowMode; private static MelonPreferences_Category m_scorelabCategory; private static MelonPreferences_Entry<float> m_eDistanceToCamera; private static MelonPreferences_Entry<float> m_eMovementSmoothness; private static MelonPreferences_Entry<bool> m_eUseAnnouncer; private static MelonPreferences_Entry<string> m_eSavedHUD; private static MelonPreferences_Entry<int> m_eHudShowMode; public static void CreatePreferences() { m_scorelabCategory = MelonPreferences.CreateCategory("ScoreLab"); m_eDistanceToCamera = m_scorelabCategory.CreateEntry<float>("DistanceToCamera", 1.125f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); m_eMovementSmoothness = m_scorelabCategory.CreateEntry<float>("MovementSmoothness", 16f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); m_eUseAnnouncer = m_scorelabCategory.CreateEntry<bool>("UseAnnouncer", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); m_eSavedHUD = m_scorelabCategory.CreateEntry<string>("SavedHUD", "Coda", (string)null, (string)null, false, false, (ValueValidator)null, (string)null); m_eHudShowMode = m_scorelabCategory.CreateEntry<int>("HUDShowMode", 0, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); DistanceToCamera = m_eDistanceToCamera.Value; MovementSmoothness = m_eMovementSmoothness.Value; UseAnnouncer = m_eUseAnnouncer.Value; SavedHUD = m_eSavedHUD.Value; HUDShowMode = (HUDShowMode)m_eHudShowMode.Value; } public static void Save(bool log = false) { m_eDistanceToCamera.Value = DistanceToCamera; m_eMovementSmoothness.Value = MovementSmoothness; m_eUseAnnouncer.Value = UseAnnouncer; m_eSavedHUD.Value = SavedHUD; m_scorelabCategory.SaveToFile(log); } public static void SetDistanceToCamera(float distance) { m_eDistanceToCamera.Value = distance; } public static void SetMovementSmoothness(float movementSmoothness) { m_eMovementSmoothness.Value = movementSmoothness; } public static void SetUseAnnouncer(bool useAnnouncer) { m_eUseAnnouncer.Value = useAnnouncer; } public static void SetHUDShowMode(HUDShowMode mode) { m_eHudShowMode.Value = (int)mode; HUDManager.HUDShowModeUpdated(mode); } } } namespace NEP.ScoreLab.Audio { public static class AudioManager { public static void Initialize() { API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAdded, new Action<PackedValue>(OnValueReceived)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueTierReached, new Action<PackedValue>(OnValueReceived)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Combine(API.Value.OnValueAccumulated, new Action<PackedValue>(OnValueReceived)); } public static void Uninitialize() { API.Value.OnValueAdded = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAdded, new Action<PackedValue>(OnValueReceived)); API.Value.OnValueTierReached = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueTierReached, new Action<PackedValue>(OnValueReceived)); API.Value.OnValueAccumulated = (Action<PackedValue>)Delegate.Remove(API.Value.OnValueAccumulated, new Action<PackedValue>(OnValueReceived)); } private static void OnValueReceived(PackedValue value) { if (Settings.UseAnnouncer && value.EventAudio != null && value.EventAudio.Clips != null && value.EventAudio.Clips.Length != 0) { AudioClip val = null; if (value.EventAudio.Clips.Length == 1) { val = value.EventAudio.Clips[0]; } else { int num = Random.Range(0, value.EventAudio.Clips.Length); val = value.EventAudio.Clips[num]; } Play(val, value.EventAudio.Volume, value.EventAudio.Pitch); } } public static void Play(AudioClip clip, float volume = 1f, float pitch = 1f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Audio.PlayAtPoint(clip, Vector3.zero, Audio.InHead, volume, pitch, 0f); } } }