using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading.Tasks; using BBModMenu; using BB_Better_rich_presence; using BB_Better_rich_presence.RichPresence; using DiscordRPC; using HarmonyLib; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using Steamworks; using Steamworks.Data; using Steamworks.Ugc; using UnityEngine; using UnityEngine.UIElements; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "BB_Better-rich-presence", "1.1.0", "Xannix", null)] [assembly: MelonGame("Jan Malitschek", "BetonBrutal")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BB_Better_rich_presence")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BB_Better_rich_presence")] [assembly: AssemblyTitle("BB_Better_rich_presence")] [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] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BB_Better_rich_presence { public class Core : MelonMod { public static string category = "Rich Presence"; private MelonPreferences_Category melonCategory; private static MelonPreferences_Entry allowEditorData; private static MelonPreferences_Entry allowPlaytestData; public static bool isModMenuLoaded = false; public static bool isLoaded = false; public static MelonPreferences_Entry AllowEditorData => allowEditorData; public static MelonPreferences_Entry AllowPlaytestData => allowPlaytestData; public override void OnInitializeMelon() { melonCategory = MelonPreferences.CreateCategory("RichPresence"); allowEditorData = melonCategory.CreateEntry("allowEditorData", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); allowPlaytestData = melonCategory.CreateEntry("allowPlaytestData", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); ModMenuComponent.Start(); ((MelonBase)this).LoggerInstance.Msg("Initialized."); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (!isLoaded) { RichPresenceManager.Awake(); isLoaded = true; } } public override void OnFixedUpdate() { while (!isModMenuLoaded) { ModMenuComponent.Start(); } RichPresenceManager.Update(); } } public class ModMenuComponent { private static string category = "Rich Presence"; private static ModMenu _modMenu; private static VisualElement settings; public static void Start() { if (_modMenu != null) { return; } GameObject val = GameObject.Find("GameUI"); if ((Object)(object)val == (Object)null) { return; } GameUI component = val.GetComponent(); if (!((Object)(object)component == (Object)null)) { UIScreen? obj = (typeof(GameUI).GetField("screens", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(component) as List)?.FirstOrDefault((Func)((UIScreen screen) => screen is ModMenu)); _modMenu = (ModMenu)(object)((obj is ModMenu) ? obj : null); if (_modMenu == null) { MelonLogger.Msg("ModMenu not found"); return; } settings = _modMenu.AddSetting(category); InitializeSettings(); } } public static void InitializeSettings() { MelonLogger.Msg("Initializing BBBRP ModMenu..."); VisualElement val = _modMenu.CreateGroup("Default settings"); VisualElement val2 = _modMenu.CreateWrapper(); val2.Add((VisualElement)(object)_modMenu.CreateLabel("Allow mod to show info from map editor")); Toggle val3 = _modMenu.CreateToggle(category, "mapWrapper", Core.AllowEditorData.Value); INotifyValueChangedExtensions.RegisterValueChangedCallback((INotifyValueChanged)(object)val3, (EventCallback>)delegate(ChangeEvent b) { Core.AllowEditorData.Value = b.newValue; MelonPreferences.Save(); RichPresenceManager.UpdateRP(GameModeManager.Instance.ActiveGameMode); }); val2.Add((VisualElement)(object)val3); VisualElement val4 = _modMenu.CreateWrapper(); val4.Add((VisualElement)(object)_modMenu.CreateLabel("Allow mod to show info from local maps")); Toggle val5 = _modMenu.CreateToggle(category, "playtestWrapper", Core.AllowPlaytestData.Value); INotifyValueChangedExtensions.RegisterValueChangedCallback((INotifyValueChanged)(object)val5, (EventCallback>)delegate(ChangeEvent b) { Core.AllowPlaytestData.Value = b.newValue; MelonPreferences.Save(); RichPresenceManager.UpdateRP(GameModeManager.Instance.ActiveGameMode); }); val4.Add((VisualElement)(object)val5); val.Add(val2); val.Add(val4); settings.Add(val); Core.isModMenuLoaded = true; } } [HarmonyPatch(typeof(MapEditor), "LoadDownloadedMap")] public static class OnMapDownloaded { public static void Postfix(string mapItemID) { RichPresenceManager.mapId = mapItemID; } } [HarmonyPatch(typeof(PlayerStats), "CompleteRun")] [HarmonyPatch(typeof(PlayerStats), "CompleteCustomRun")] public static class OnRunCompleted { private static void Postfix() { RichPresenceManager.UpdateRP(GameModeManager.Instance.ActiveGameMode); } } } namespace BB_Better_rich_presence.RichPresence { public static class RichPresenceManager { public static string category = "Rich Presence"; public static string mapId; public static bool isCustomMap = false; private static readonly DiscordRpcClient client = new DiscordRpcClient("1412798038929575946"); private static float updateTimer = 0f; private static Timestamps sessionStart; private static int blocks = 0; private static string mapName = null; private static string imageUrl; private static bool allowEditor => Core.AllowEditorData.Value; private static bool allowPlaytest => Core.AllowPlaytestData.Value; public static void Awake() { if (!Core.isLoaded) { client.Initialize(); sessionStart = Timestamps.Now; MelonLogger.Msg("DRP client Initialized"); UpdateRP(GameModeManager.Instance.ActiveGameMode); GameModeManager.Instance.onGameModeChanged += UpdateRP; MapEditor.Instance.onMapLoaded += delegate { blocks = BuildingBlockContainer.Instance.buildingBlocksInScene.Count(); mapName = MapEditor.Instance.mapName; isCustomMap = true; }; MapEditor.Instance.onMapCleared += delegate { imageUrl = "bb_icon"; mapName = null; mapId = null; isCustomMap = false; }; } } public static void Update() { updateTimer += Time.deltaTime; if (updateTimer >= 10f) { try { updateTimer = 0f; UpdateRP(GameModeManager.Instance.ActiveGameMode); } catch (Exception ex) { MelonLogger.Msg((object)ex); } } } public static void UpdateRP(GameMode mode) { if (GameModeManager.Instance.PreviousGameMode is MenuGameMode && mode is MenuGameMode) { mapName = null; isCustomMap = false; } if (!(mode is CustomMapGameMode)) { if (!(mode is MapEditorGameMode)) { if (!(mode is MenuGameMode)) { if (!(mode is MainGameMode)) { } if (isCustomMap) { InCustomMap(); } else { InMainMode(); } } else { InMenu(); } } else { InEditor(); } } else { InCustomMap(); } } private static void InMainMode() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown PlayerStats instance = PlayerStats.Instance; string text = $"{instance.currentHeight}m (run #{instance.numRuns})" + (instance.IsPracticing ? " | Practicing" : ""); string text2 = $"Completed in {instance.currentTimeString} (run #{instance.numRuns})"; client.SetPresence(new RichPresence { Details = "Playing in " + GetMap(), State = (instance.runComplete ? text2 : text), Assets = new Assets { LargeImageKey = "bb_icon", SmallImageKey = (instance.runComplete ? "finish" : GetSmallIcon()) }, Timestamps = sessionStart }); } private static async void InCustomMap() { PlayerStats playerStats = PlayerStats.Instance; bool hideLocalMapData = mapId == null && !allowPlaytest; string defaultState = string.Format("{0}m {1}", hideLocalMapData ? "???" : ((object)playerStats.currentHeight), hideLocalMapData ? "" : $"(run #{playerStats.numRuns})") + (hideLocalMapData ? "" : (playerStats.IsPracticing ? " | Practicing" : "")); string completedState = "Completed in " + playerStats.currentTimeString + " " + (hideLocalMapData ? "" : $"(run #{playerStats.numRuns})"); imageUrl = await GetImageUrlAsync(); client.SetPresence(new RichPresence { Details = "Playing \"" + (hideLocalMapData ? "???" : mapName) + "\"", State = (playerStats.runComplete ? completedState : defaultState), Assets = new Assets { LargeImageKey = ((mapId == null) ? "custom_map" : imageUrl), SmallImageKey = (playerStats.runComplete ? "finish" : null) }, Timestamps = sessionStart }); } private static void InEditor() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown client.SetPresence(new RichPresence { Details = "Building " + (allowEditor ? ("\"" + mapName + "\"") : "something"), State = (allowEditor ? ((object)blocks) : "???")?.ToString() + " blocks", Assets = new Assets { LargeImageKey = "custom_map" }, Timestamps = sessionStart }); } private static void InMenu() { //IL_0026: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown bool flag = mapId == null && !allowPlaytest && GetMap() == "Unknown map"; client.SetPresence(new RichPresence { Details = "Playing " + (flag ? "???" : ((mapName == null) ? GetMap() : ("\"" + mapName + "\""))), State = "In menu", Assets = new Assets { LargeImageKey = ((!isCustomMap && mapName == null) ? "bb_icon" : ((mapId == null) ? "custom_map" : imageUrl)), SmallImageKey = ((mapName == null) ? GetSmallIcon() : "") }, Timestamps = sessionStart }); } private static string GetMap() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected I4, but got Unknown StatsMode currentStatsMode = PlayerStats.Instance.currentStatsMode; return (int)currentStatsMode switch { 0 => "BETON BRUTAL", 1 => "BETON BATH", 2 => "BETON B-DAY", _ => "Unknown map", }; } private static string GetSmallIcon() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected I4, but got Unknown StatsMode currentStatsMode = PlayerStats.Instance.currentStatsMode; return (int)currentStatsMode switch { 0 => "beton_brutal", 1 => "beton_bath", 2 => "beton_b-day", _ => "bb_icon", }; } private static async Task GetImageUrlAsync() { if (mapId == null || !isCustomMap) { return "bb_icon"; } Item? val = await SteamUGC.QueryFileAsync(PublishedFileId.op_Implicit(ulong.Parse(mapId))); if (!val.HasValue) { return "bb_icon"; } Item value = val.Value; mapName = ((Item)(ref value)).Title; value = val.Value; return ((Item)(ref value)).PreviewImageUrl; } public static void OnDisable() { client.Dispose(); } } }