using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using LabFusion.Entities;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.Player;
using LabFusion.SDK.Modules;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using bonelab_template;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("For R41CHU's Hood RP")]
[assembly: AssemblyDescription("For R41CHU's Hood RP")]
[assembly: AssemblyCompany("R41CHU's Company")]
[assembly: AssemblyProduct("R41CHU's Hood RP")]
[assembly: AssemblyCopyright("Developed by R41CHU")]
[assembly: AssemblyTrademark("R41CHU's Company")]
[assembly: AssemblyFileVersion("0.0.1")]
[assembly: MelonInfo(typeof(Main), "R41CHU's Hood RP", "0.0.1", "R41CHU", "Link")]
[assembly: MelonColor(255, 255, 255, 255)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("0.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace bonelab_template
{
internal class Main : MelonMod
{
internal const string Name = "R41CHU's Hood RP";
internal const string Description = "For R41CHU's Hood RP";
internal const string Author = "R41CHU";
internal const string Company = "R41CHU's Company";
internal const string Version = "0.0.1";
internal const string DownloadLink = "Link";
public override void OnEarlyInitializeMelon()
{
((MelonBase)this).OnEarlyInitializeMelon();
}
public override void OnInitializeMelon()
{
((MelonBase)this).OnInitializeMelon();
HoodRPNetwork.Register();
HoodRPMenu.Initialize();
}
public override void OnLateInitializeMelon()
{
((MelonBase)this).OnLateInitializeMelon();
}
public override void OnUpdate()
{
HoodRPMenu.Update();
((MelonBase)this).OnUpdate();
}
public override void OnFixedUpdate()
{
((MelonBase)this).OnFixedUpdate();
}
public override void OnLateUpdate()
{
((MelonBase)this).OnLateUpdate();
}
}
internal static class HoodRPMenu
{
internal sealed class ProfileData : INetSerializable
{
public ulong TargetPlatformId;
public string DisplayName = string.Empty;
public string[] Jobs = Array.Empty<string>();
public string[] Licenses = Array.Empty<string>();
public string[] Warrants = Array.Empty<string>();
public void Serialize(INetSerializer serializer)
{
serializer.SerializeValue(ref TargetPlatformId);
serializer.SerializeValue(ref DisplayName);
serializer.SerializeValue(ref Jobs);
serializer.SerializeValue(ref Licenses);
serializer.SerializeValue(ref Warrants);
}
public int? GetSize()
{
return null;
}
}
internal sealed class AnnouncementData : INetSerializable
{
public string Text = string.Empty;
public void Serialize(INetSerializer serializer)
{
serializer.SerializeValue(ref Text);
}
public int? GetSize()
{
return null;
}
}
private sealed class PlayerRecord
{
public ulong PlatformId { get; set; }
public string LastKnownName { get; set; } = string.Empty;
public HashSet<string> Licenses { get; set; } = new HashSet<string>(StringComparer.Ordinal);
public HashSet<string> Jobs { get; set; } = new HashSet<string>(StringComparer.Ordinal);
public List<string> Warrants { get; set; } = new List<string>();
}
internal const ulong OwnerSteamId = 76561199061832735uL;
private static readonly string[] LicenseNames = new string[6] { "Driving", "Gun License Tier 1", "Gun License Tier 2", "Gun License Tier 3", "Property", "Business" };
private static readonly string[] JobNames = new string[5] { "Police", "Store Clerk", "Delivery Driver", "Taxi Driver", "Illegal Supplier" };
private const string DiscordPhrase = "Join the discord : https://discord.gg/p4p2M79hd6";
private const string InstallPhrase = "Install \"LabRP\" and \"R41CHU's Hood RP\"";
private const string StorePhrase = "General Store OPEN";
private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions
{
WriteIndented = true
};
private static readonly List<PlayerRecord> Records = new List<PlayerRecord>();
private static readonly List<Page> AdminPages = new List<Page>();
private static Page _homePage;
private static Page _playersPage;
private static Page _personalJobsPage;
private static Page _personalLicensesPage;
private static Page _personalWarrantsPage;
private static bool _loaded;
private static bool _adminPagesVisible;
private static bool _lastHostState;
private static string _pendingWarrantReason = string.Empty;
private static string _pendingAnnouncement = string.Empty;
private static ProfileData _receivedProfile;
private static string _rosterSignature = string.Empty;
private static DateTime _nextRosterCheck;
private static bool IsOwnerAccount => PlayerIDManager.LocalPlatformID == 76561199061832735L;
private static bool IsFusionHost => NetworkLayerManager.Layer != null && NetworkLayerManager.Layer.IsHost;
private static string SavePath => Path.Combine(MelonEnvironment.UserDataDirectory, "HoodRP", "players.json");
public static void Initialize()
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: 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_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
if (!_loaded)
{
_loaded = true;
LoadRecords();
_homePage = Page.Root.CreatePage("Hood RP", Color.white, 0, true);
_personalJobsPage = _homePage.CreatePage("Jobs", Color.white, 0, true);
_personalLicensesPage = _homePage.CreatePage("Licenses", Color.white, 0, true);
_personalWarrantsPage = _homePage.CreatePage("Arrest Warrants", Color.white, 0, true);
_personalJobsPage.CreateFunction("Go ask owner for a job", Color.white, (Action)delegate
{
});
RefreshPersonalPages();
UpdateAdminVisibility();
}
}
public static void Update()
{
if (!_loaded)
{
return;
}
HoodRPNetwork.Register();
UpdateAdminVisibility();
if (_adminPagesVisible && _lastHostState != IsFusionHost)
{
_lastHostState = IsFusionHost;
RefreshPlayers();
}
if (CanAdminister() && DateTime.UtcNow >= _nextRosterCheck)
{
_nextRosterCheck = DateTime.UtcNow.AddSeconds(2.0);
string text = string.Join(",", from id in PlayerIDManager.PlayerIDs
where id != null
select id.PlatformID into id
orderby id
select id);
if (text != _rosterSignature)
{
_rosterSignature = text;
SyncAllPlayers();
}
}
}
private static void UpdateAdminVisibility()
{
bool flag = IsOwnerAccount && PlayerIDManager.HasPlayerID(76561199061832735uL);
if (flag != _adminPagesVisible)
{
if (flag)
{
CreateAdminPages();
}
else
{
RemoveAdminPages();
}
}
}
private static void CreateAdminPages()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
if (!_adminPagesVisible)
{
_playersPage = _homePage.CreatePage("Players (Admin)", Color.white, 0, true);
AdminPages.Add(_playersPage);
_adminPagesVisible = true;
_lastHostState = IsFusionHost;
RefreshPlayers();
}
}
private static void RemoveAdminPages()
{
if (_adminPagesVisible)
{
_homePage.RemovePages(AdminPages.ToArray());
AdminPages.Clear();
_playersPage = null;
_adminPagesVisible = false;
}
}
private static void RefreshPlayers()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
if (_playersPage == null)
{
return;
}
if (!CanAdminister())
{
_playersPage.RemoveAll();
_playersPage.CreateFunction("Host a Fusion lobby to manage records", Color.white, (Action)delegate
{
});
return;
}
Page[] array = AdminPages.Skip(1).ToArray();
foreach (Page val in array)
{
_playersPage.RemovePage(val);
}
if (AdminPages.Count > 1)
{
AdminPages.RemoveRange(1, AdminPages.Count - 1);
}
_playersPage.RemoveAll();
_playersPage.CreateFunction("Refresh Fusion players", Color.white, (Action)RefreshPlayers);
CreateAnnouncementPages();
foreach (PlayerID item in from id in PlayerIDManager.PlayerIDs
where id != null && id.PlatformID != 0
orderby id.PlatformID
select id)
{
string playerName = GetPlayerName(item);
PlayerRecord orCreateRecord = GetOrCreateRecord(item.PlatformID, playerName);
orCreateRecord.LastKnownName = playerName;
string text = item.PlatformID.ToString();
if (text.Length > 4)
{
text = text.Substring(text.Length - 4);
}
Page val2 = _playersPage.CreatePage(playerName + " (" + text + ")", Color.white, 0, true);
AdminPages.Add(val2);
CreatePlayerSubPages(val2, orCreateRecord);
}
SaveRecords();
SyncAllPlayers();
}
private static void CreateAnnouncementPages()
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
Page val = _playersPage.CreatePage("Server Announcement", Color.white, 0, true);
AdminPages.Add(val);
val.CreateString("Announcement text", Color.white, _pendingAnnouncement, (Action<string>)delegate(string value)
{
_pendingAnnouncement = value ?? string.Empty;
});
val.CreateFunction("Send to server", Color.white, (Action)SendAnnouncement);
Page val2 = _playersPage.CreatePage("Copy Setup Phrases", Color.white, 0, true);
AdminPages.Add(val2);
val2.CreateFunction("Copy Discord invite", Color.white, (Action)delegate
{
CopyPhrase("Join the discord : https://discord.gg/p4p2M79hd6");
});
val2.CreateFunction("Copy mod install message", Color.white, (Action)delegate
{
CopyPhrase("Install \"LabRP\" and \"R41CHU's Hood RP\"");
});
val2.CreateFunction("Copy store announcement", Color.white, (Action)delegate
{
CopyPhrase("General Store OPEN");
});
}
private static void CopyPhrase(string phrase)
{
try
{
GUIUtility.systemCopyBuffer = phrase;
SendNotification("Copied to clipboard", phrase);
}
catch (Exception ex)
{
MelonLogger.Warning("Could not copy Hood RP phrase: " + ex.Message);
}
}
private static void SendAnnouncement()
{
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
if (CanAdminister())
{
string text = new string((_pendingAnnouncement ?? string.Empty).Where((char character) => !char.IsControl(character) && character != '<' && character != '>').Take(240).ToArray()).Trim();
if (!string.IsNullOrWhiteSpace(text))
{
AnnouncementData announcementData = new AnnouncementData
{
Text = text
};
MessageRelay.RelayModule<HoodRPAnnouncementHandler, AnnouncementData>(announcementData, new MessageRoute((RelayType)3, (NetworkChannel)0));
ReceiveAnnouncement(text);
_pendingAnnouncement = string.Empty;
RefreshPlayers();
}
}
}
internal static void ReceiveAnnouncement(string text)
{
if (!string.IsNullOrWhiteSpace(text))
{
SendNotification("Server Announcement", text);
}
}
private static string GetPlayerName(PlayerID playerId)
{
NetworkPlayer val = default(NetworkPlayer);
if (!NetworkPlayerManager.TryGetPlayer(playerId.SmallID, ref val) || val == null || string.IsNullOrWhiteSpace(val.Username))
{
return $"Player {playerId.PlatformID}";
}
return val.Username;
}
private static void CreatePlayerSubPages(Page playerPage, PlayerRecord record)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
Page val = playerPage.CreatePage("Licenses", Color.white, 0, true);
string[] licenseNames = LicenseNames;
foreach (string license in licenseNames)
{
val.CreateBool(license, Color.white, record.Licenses.Contains(license), (Action<bool>)delegate(bool enabled)
{
ChangeAssignment(record, record.Licenses, license, enabled);
});
}
Page val2 = playerPage.CreatePage("Jobs", Color.white, 0, true);
string[] jobNames = JobNames;
foreach (string job in jobNames)
{
val2.CreateBool(job, Color.white, record.Jobs.Contains(job), (Action<bool>)delegate(bool enabled)
{
ChangeAssignment(record, record.Jobs, job, enabled);
});
}
Page val3 = playerPage.CreatePage("Warrants", Color.white, 0, true);
val3.CreateString("Warrant reason", Color.white, string.Empty, (Action<string>)delegate(string value)
{
_pendingWarrantReason = SanitizeWarrant(value);
});
val3.CreateFunction("Add warrant", Color.white, (Action)delegate
{
if (CanAdminister() && !string.IsNullOrWhiteSpace(_pendingWarrantReason))
{
string item = _pendingWarrantReason.Trim();
if (!record.Warrants.Contains(item))
{
record.Warrants.Add(item);
}
_pendingWarrantReason = string.Empty;
SaveRecords();
SyncPlayer(record);
RefreshPlayers();
}
});
string[] array = record.Warrants.ToArray();
foreach (string warrant in array)
{
val3.CreateFunction("Remove: " + warrant, Color.white, (Action)delegate
{
if (CanAdminister())
{
record.Warrants.Remove(warrant);
SaveRecords();
SyncPlayer(record);
RefreshPlayers();
}
});
}
}
private static void ChangeAssignment(PlayerRecord record, HashSet<string> set, string value, bool enabled)
{
if (CanAdminister() && (enabled ? set.Add(value) : set.Remove(value)))
{
SaveRecords();
SyncPlayer(record);
}
}
private static string SanitizeWarrant(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return string.Empty;
}
return new string(text.Where((char character) => !char.IsControl(character) && character != '<' && character != '>').Take(120).ToArray()).Trim();
}
private static bool CanAdminister()
{
return _adminPagesVisible && IsOwnerAccount && IsFusionHost;
}
private static PlayerRecord GetOrCreateRecord(ulong platformId, string playerName)
{
PlayerRecord playerRecord = Records.FirstOrDefault((PlayerRecord item) => item.PlatformId == platformId);
if (playerRecord != null)
{
return playerRecord;
}
playerRecord = new PlayerRecord
{
PlatformId = platformId,
LastKnownName = playerName
};
Records.Add(playerRecord);
return playerRecord;
}
private static void SyncAllPlayers()
{
if (CanAdminister())
{
PlayerRecord[] array = Records.ToArray();
foreach (PlayerRecord record in array)
{
SyncPlayer(record);
}
}
}
private static void SyncPlayer(PlayerRecord record)
{
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
if (!CanAdminister())
{
return;
}
PlayerID playerID = PlayerIDManager.GetPlayerID(record.PlatformId);
if (playerID != null && playerID.PlatformID != 0)
{
ProfileData profileData = new ProfileData
{
TargetPlatformId = record.PlatformId,
DisplayName = (record.LastKnownName ?? string.Empty),
Jobs = record.Jobs.ToArray(),
Licenses = record.Licenses.ToArray(),
Warrants = record.Warrants.ToArray()
};
MessageRelay.RelayModule<HoodRPProfileHandler, ProfileData>(profileData, new MessageRoute(playerID.SmallID, (NetworkChannel)0));
if (record.PlatformId == 76561199061832735L)
{
ReceiveProfile(profileData);
}
}
}
internal static void ReceiveProfile(ProfileData profile)
{
if (profile == null || profile.TargetPlatformId != PlayerIDManager.LocalPlatformID)
{
return;
}
ProfileData receivedProfile = _receivedProfile;
_receivedProfile = profile;
RefreshPersonalPages();
if (receivedProfile == null)
{
return;
}
foreach (string item in profile.Jobs.Except(receivedProfile.Jobs))
{
SendNotification("New job", item);
}
foreach (string item2 in profile.Licenses.Except(receivedProfile.Licenses))
{
SendNotification("New license", item2);
}
foreach (string item3 in profile.Warrants.Except(receivedProfile.Warrants))
{
SendNotification("Arrest warrant", item3);
}
}
private static void RefreshPersonalPages()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
if (_personalJobsPage != null)
{
_personalJobsPage.RemoveAll();
_personalJobsPage.CreateFunction("Go ask owner for a job", Color.white, (Action)delegate
{
});
string[] array = _receivedProfile?.Jobs ?? Array.Empty<string>();
foreach (string text in array)
{
_personalJobsPage.CreateFunction(text, Color.white, (Action)delegate
{
});
}
_personalLicensesPage.RemoveAll();
string[] array2 = _receivedProfile?.Licenses ?? Array.Empty<string>();
foreach (string text2 in array2)
{
_personalLicensesPage.CreateFunction(text2, Color.white, (Action)delegate
{
});
}
_personalWarrantsPage.RemoveAll();
string[] array3 = _receivedProfile?.Warrants ?? Array.Empty<string>();
if (array3.Length == 0)
{
_personalWarrantsPage.CreateFunction("No active warrants", Color.white, (Action)delegate
{
});
}
string[] array4 = array3;
foreach (string text3 in array4)
{
_personalWarrantsPage.CreateFunction(text3, Color.white, (Action)delegate
{
});
}
}
}
private static void SendNotification(string title, string message)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Expected O, but got Unknown
try
{
Notifier.Send(new Notification
{
Title = NotificationText.op_Implicit(title),
Message = NotificationText.op_Implicit(message),
ShowTitleOnPopup = true,
PopupLength = 5f,
Type = (NotificationType)0
});
}
catch (Exception ex)
{
MelonLogger.Warning("Could not show Hood RP notification: " + ex.Message);
}
}
private static void LoadRecords()
{
try
{
if (!File.Exists(SavePath))
{
return;
}
List<PlayerRecord> list = JsonSerializer.Deserialize<List<PlayerRecord>>(File.ReadAllText(SavePath), JsonOptions);
if (list != null)
{
Records.AddRange(list.Where((PlayerRecord record) => record != null && record.PlatformId != 0));
}
}
catch (Exception value)
{
MelonLogger.Error($"Could not load Hood RP player records: {value}");
}
}
private static void SaveRecords()
{
if (!IsOwnerAccount)
{
return;
}
try
{
string directoryName = Path.GetDirectoryName(SavePath);
Directory.CreateDirectory(directoryName);
string text = SavePath + ".tmp";
File.WriteAllText(text, JsonSerializer.Serialize(Records, JsonOptions));
File.Move(text, SavePath, overwrite: true);
}
catch (Exception value)
{
MelonLogger.Error($"Could not save Hood RP player records: {value}");
}
}
}
internal sealed class HoodRPModule : Module
{
public override string Name => "Hood RP";
public override string Author => "R41CHU";
public override Version Version => new Version(1, 0, 0);
public override ConsoleColor Color => ConsoleColor.DarkGreen;
protected override void OnModuleRegistered()
{
ModuleMessageManager.RegisterHandler<HoodRPProfileHandler>();
}
}
internal sealed class HoodRPProfileHandler : ModuleMessageHandler
{
protected override void OnHandleMessage(ReceivedMessage receivedMessage)
{
if (((ReceivedMessage)(ref receivedMessage)).PlatformID == 76561199061832735L && ((ReceivedMessage)(ref receivedMessage)).IsServerHandled)
{
ProfileDataBridge(((ReceivedMessage)(ref receivedMessage)).ReadData<HoodRPMenu.ProfileData>());
}
}
private static void ProfileDataBridge(HoodRPMenu.ProfileData profile)
{
HoodRPMenu.ReceiveProfile(profile);
}
}
internal sealed class HoodRPAnnouncementHandler : ModuleMessageHandler
{
protected override void OnHandleMessage(ReceivedMessage receivedMessage)
{
if (((ReceivedMessage)(ref receivedMessage)).PlatformID == 76561199061832735L && ((ReceivedMessage)(ref receivedMessage)).IsServerHandled)
{
HoodRPMenu.ReceiveAnnouncement(((ReceivedMessage)(ref receivedMessage)).ReadData<HoodRPMenu.AnnouncementData>()?.Text);
}
}
}
internal static class HoodRPNetwork
{
private static bool _registered;
public static void Register()
{
if (!_registered && MelonBase.FindMelon("LabFusion", "Lakatrazz") != null)
{
ModuleManager.RegisterModule<HoodRPModule>();
_registered = true;
}
}
}
}