Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DropinMultiplayer v4.3.0
BepInEx/plugins/DropInMultiplayer/DropInMultiplayer.dll
Decompiled 2 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DropInMultiplayer.Helpers; using HG.Reflection; using Microsoft.CodeAnalysis; using On.RoR2; using R2API.Utils; using RoR2; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: OptIn] [assembly: AssemblyTitle("DropInMultiplayer")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DropInMultiplayer")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("0321a436-2c1f-4f7b-8a99-becbbb8089d2")] [assembly: AssemblyFileVersion("4.3.0.0")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("4.3.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 DropInMultiplayer { public class DropInMultiplayerConfig { private const string DefaultWelcomeMessage = "Hello {username}! Join the game by typing '/join_as {survivor name}' in chat (or '/join_as random'). To get a list of availible survivors, type '/list_survivors' in chat"; public ConfigEntry<bool> AllowRespawn { get; } public ConfigEntry<bool> JoinAsRandomByDefault { get; } public ConfigEntry<bool> AllowJoinAsHiddenSurvivors { get; } public ConfigEntry<bool> AllowJoinAsAllBodies { get; } public ConfigEntry<bool> GiveHereticItems { get; } public ConfigEntry<bool> PreventCaptainScrapAbuse { get; } public ConfigEntry<bool> PreventOperatorDroneAbuse { get; } public ConfigEntry<bool> GiveCatchUpItems { get; } public ConfigEntry<bool> GiveRejoiningPlayersCatchUpItems { get; } public ConfigEntry<bool> GiveCatchUpVoidItems { get; } public ConfigEntry<bool> GiveCatchUpLunarItems { get; } public ConfigEntry<bool> SendWelcomeMessage { get; } public ConfigEntry<string> CustomWelcomeMessage { get; } public DropInMultiplayerConfig(ConfigFile config) { AllowRespawn = config.Bind<bool>("General", "AllowRespawn", true, "When enabled dead players who use the join as command will be immediately respawned"); JoinAsRandomByDefault = config.Bind<bool>("General", "JoinAsRandomByDefault", false, "When enabled newly joined players will be spawned as random survivor by default"); AllowJoinAsHiddenSurvivors = config.Bind<bool>("Survivors", "AllowJoinAsHiddenSurvivors", true, "When enabled allows players to join as hidden characters, e.g. heretic"); AllowJoinAsAllBodies = config.Bind<bool>("General", "AllowJoinAsAllBodies", false, "When enabled using the join as command will attempt to match with any body, e.g. join_as beetle, WARNING: Very Untested!"); GiveHereticItems = config.Bind<bool>("Survivors", "GiveHereticItems", true, "When enabled joining as Heretic will give all 4 Heretic items automatically."); PreventCaptainScrapAbuse = config.Bind<bool>("Survivors", "PreventCaptainScrapAbuse", true, "When enabled Captain will not receive replacement Microbots if it was scrapped or removed."); GiveCatchUpItems = config.Bind<bool>("Items", "GiveCatchUpItems", true, "When enabled players will be given catch up items when joining"); GiveRejoiningPlayersCatchUpItems = config.Bind<bool>("Items", "GiveRejoiningPlayersCatchUpItems", true, "When enabled players who leave and rejoin will be given catchup items, WARNING: Can be exploited by giving all items to one player then leaving and rejoining"); GiveCatchUpVoidItems = config.Bind<bool>("Items", "GiveCatchUpVoidItems", false, "When enabled void items will be dropped when players start (requires GiveCatchUpItems enabled)"); GiveCatchUpLunarItems = config.Bind<bool>("Items", "GiveCatchUpLunarItems", false, "When enabled lunar items will be dropped when players start (requires GiveCatchUpItems enabled)"); SendWelcomeMessage = config.Bind<bool>("Chat Messages", "SendWelcomeMessage", true, "Sends the welcome message when a new player joins."); CustomWelcomeMessage = config.Bind<string>("Chat Messages", "CustomWelcomeMessage", "Hello {username}! Join the game by typing '/join_as {survivor name}' in chat (or '/join_as random'). To get a list of availible survivors, type '/list_survivors' in chat", "Format of welcome message. {username} will be replaced with joining users name, and {survivorlist} will be replaced by list of availible survivors."); } } internal enum JoinAsResult { Success, DeadAndNotAllowRespawn } internal class ChatCommand { public string Name { get; set; } public string HelpText { get; set; } public Func<NetworkUser, string[], string> Handler { get; set; } internal ChatCommand(string name, string helpText, Func<NetworkUser, string[], string> handler) { Name = name; HelpText = helpText; Handler = handler; } } [BepInPlugin("com.niwith.DropInMultiplayer", "Drop In Multiplayer", "4.3.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class DropInMultiplayer : BaseUnityPlugin { [CompilerGenerated] private static class <>O { public static Action<Run> <0>__Run_onRunStartGlobal; public static hook_RunCmd <1>__Console_RunCmd; public static hook_SetupUserCharacterMaster <2>__Run_SetupUserCharacterMaster; public static NetworkUserGenericDelegate <3>__NetworkUser_onPostNetworkUserStart; } public const string PluginGUID = "com.niwith.DropInMultiplayer"; public const string PluginName = "Drop In Multiplayer"; public const string PluginVersion = "4.3.0"; private const string HelpHelpText = "Usage: help {command}\nDescription: Prints help text for command"; private const string JoinAsHelpText = "Usage: join_as {survivor} {player (optional)}\nDescription: Join in-progress run as the given survivor"; private const string ListSurvivorsHelpText = "Usage: list_survivors {player (optional)}\nDescription: Shows a list of all availible survivors for given player (or self)"; private const string ListBodiesHelpText = "Usage: list_bodies\nDescription: Shows a list of all bodies to be used with join_as command (if AllowJoinAsAllBodies is true)"; private const string CatchupHelpText = "Usage: catchup {player (optional)}\nDescription: Manually adds catch up items for the given player (or self)"; private const string GiveRandomItemsHelpText = "Usage: give_random_items {count} {lunarEnabled} {voidEnabled} {player (optional)}\nDescription: Adds random items for the given player (or self)"; private static readonly Random _rand = new Random(); private static readonly Dictionary<string, ChatCommand> _chatCommands = new List<ChatCommand> { new ChatCommand("HELP", "Usage: help {command}\nDescription: Prints help text for command", Help), new ChatCommand("JOIN", "Usage: join_as {survivor} {player (optional)}\nDescription: Join in-progress run as the given survivor", JoinAs), new ChatCommand("JOIN_AS", "Usage: join_as {survivor} {player (optional)}\nDescription: Join in-progress run as the given survivor", JoinAs), new ChatCommand("LIST_SURVIVORS", "Usage: list_survivors {player (optional)}\nDescription: Shows a list of all availible survivors for given player (or self)", ListSurvivors), new ChatCommand("LIST_BODIES", "Usage: list_bodies\nDescription: Shows a list of all bodies to be used with join_as command (if AllowJoinAsAllBodies is true)", ListBodies) }.ToDictionary((ChatCommand rec) => rec.Name); private static HashSet<Inventory> captainBlacklistInventories; public static DropInMultiplayerConfig DropInConfig { get; set; } public static DropInMultiplayer Instance { get; set; } internal static ManualLogSource Logger { get; set; } public void Awake() { Instance = this; Logger = ((BaseUnityPlugin)this).Logger; DropInConfig = new DropInMultiplayerConfig(((BaseUnityPlugin)this).Config); SetupEventHandlers(); ((MonoBehaviour)Instance).StartCoroutine(SurvivorNameResolver.PreloadLanguageStrings()); } private static void SetupEventHandlers() { //IL_0030: 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_003b: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown Run.onRunStartGlobal += Run_onRunStartGlobal; object obj = <>O.<1>__Console_RunCmd; if (obj == null) { hook_RunCmd val = Console_RunCmd; <>O.<1>__Console_RunCmd = val; obj = (object)val; } Console.RunCmd += (hook_RunCmd)obj; object obj2 = <>O.<2>__Run_SetupUserCharacterMaster; if (obj2 == null) { hook_SetupUserCharacterMaster val2 = Run_SetupUserCharacterMaster; <>O.<2>__Run_SetupUserCharacterMaster = val2; obj2 = (object)val2; } Run.SetupUserCharacterMaster += (hook_SetupUserCharacterMaster)obj2; object obj3 = <>O.<3>__NetworkUser_onPostNetworkUserStart; if (obj3 == null) { NetworkUserGenericDelegate val3 = NetworkUser_onPostNetworkUserStart; <>O.<3>__NetworkUser_onPostNetworkUserStart = val3; obj3 = (object)val3; } NetworkUser.onPostNetworkUserStart += (NetworkUserGenericDelegate)obj3; } private static void Run_onRunStartGlobal(Run run) { captainBlacklistInventories = new HashSet<Inventory>(); } private static void Run_SetupUserCharacterMaster(orig_SetupUserCharacterMaster orig, Run self, NetworkUser user) { try { orig.Invoke(self, user); } catch (Exception ex) { Debug.LogException(ex); Logger.LogError((object)ex); Logger.LogMessage((object)"SetupUserCharacterMaster threw an exception and was caught"); } } private static void Console_RunCmd(orig_RunCmd orig, Console self, CmdSender sender, string concommandName, List<string> userArgs) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) orig.Invoke(self, sender, concommandName, userArgs); if (!NetworkServer.active || (Object)(object)Run.instance == (Object)null || !concommandName.Equals("say", StringComparison.InvariantCultureIgnoreCase)) { return; } string text = userArgs.FirstOrDefault(); if (string.IsNullOrWhiteSpace(text) || !text.StartsWith("/")) { return; } string[] source = text.Split(new char[1] { ' ' }); string text2 = source.FirstOrDefault().Substring(1); string[] arg = source.Skip(1).ToArray(); if (!_chatCommands.TryGetValue(text2.ToUpperInvariant(), out var value)) { SendChatMessage("Unable to find command, try /help"); return; } string text3 = value.Handler(sender.networkUser, arg); if (!string.IsNullOrWhiteSpace(text3)) { SendChatMessage(text3); } } private static void NetworkUser_onPostNetworkUserStart(NetworkUser networkUser) { if (NetworkServer.active && (Object)(object)Run.instance != (Object)null) { bool flag = (Object)(object)networkUser.master != (Object)null; Logger.LogMessage((object)(networkUser.userName + " has joined " + (flag ? "as a previously connected player" : "as a new player"))); GreetNewPlayer(networkUser); if (DropInConfig.JoinAsRandomByDefault.Value && !flag) { Logger.LogMessage((object)"Spawning new player as random, since JoinAsRandomByDefault is true"); ((MonoBehaviour)Instance).StartCoroutine(SpawnPlayerAsRandomInternal(networkUser)); } if (DropInConfig.GiveCatchUpItems.Value && DropInConfig.GiveRejoiningPlayersCatchUpItems.Value && flag) { GiveCatchUpItems(networkUser); } } } private static JoinAsResult SpawnPlayerWithBody(NetworkUser player, BodyIndex newBodyIndex) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player.master == (Object)null) { Logger.LogMessage((object)$"Spawning new player {player.userName} with bodyIndex = {newBodyIndex}"); return SpawnNewPlayerWithBody(player, newBodyIndex); } Logger.LogMessage((object)$"Respawning existing player {player.userName} with bodyIndex = {newBodyIndex}"); return RespawnExistingPlayerWithBody(player, newBodyIndex); } private static JoinAsResult SpawnNewPlayerWithBody(NetworkUser player, BodyIndex newBodyIndex) { //IL_0001: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) player.CmdSetBodyPreference(newBodyIndex); Reflection.SetFieldValue<bool>((object)Run.instance, "allowNewParticipants", true); Run.instance.OnUserAdded(player); Reflection.SetFieldValue<bool>((object)Run.instance, "allowNewParticipants", false); Transform spawnTransformForPlayer = GetSpawnTransformForPlayer(player); player.master.SpawnBody(spawnTransformForPlayer.position, spawnTransformForPlayer.rotation); HandleBodyItems(player, null, BodyCatalog.GetBodyPrefab(newBodyIndex)); if (DropInConfig.GiveCatchUpItems.Value) { GiveCatchUpItems(player); } return JoinAsResult.Success; } private static JoinAsResult RespawnExistingPlayerWithBody(NetworkUser player, BodyIndex newBodyIndex) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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) GameObject bodyPrefab = player.master.bodyPrefab; player.CmdSetBodyPreference(newBodyIndex); JoinAsResult result = JoinAsResult.Success; if ((((Object)(object)player.GetCurrentBody() == (Object)null && player.master.lostBodyToDeath) | ((Object)(object)player.GetCurrentBody() != (Object)null && player.GetCurrentBody().isRemoteOp)) && !DropInConfig.AllowRespawn.Value) { Logger.LogMessage((object)$"Unable immediately to spawn {player.userName} with bodyIndex = {newBodyIndex} due to being player being dead and AllowRespawn being set to false"); result = JoinAsResult.DeadAndNotAllowRespawn; } else { player.master.originalBodyPrefab = player.master.bodyPrefab; Transform spawnTransformForPlayer = GetSpawnTransformForPlayer(player); player.master.Respawn(spawnTransformForPlayer.position, spawnTransformForPlayer.rotation, false); } HandleBodyItems(player, bodyPrefab, BodyCatalog.GetBodyPrefab(newBodyIndex)); return result; } private static void HandleBodyItems(NetworkUser player, GameObject oldBodyPrefab, GameObject newBodyPrefab) { string text = null; string text2 = null; try { Inventory inventory = player.master.inventory; text = ((oldBodyPrefab != null) ? ((Object)oldBodyPrefab).name : null); text2 = ((Object)newBodyPrefab).name; switch (text) { case "CaptainBody": if (inventory.GetItemCountPermanent(Items.CaptainDefenseMatrix) <= 0 && DropInConfig.PreventCaptainScrapAbuse.Value) { captainBlacklistInventories.Add(inventory); } if (!captainBlacklistInventories.Contains(inventory)) { inventory.RemoveItemPermanent(Items.CaptainDefenseMatrix, 1); } break; case "HereticBody": if (DropInConfig.GiveHereticItems.Value) { inventory.RemoveItemPermanent(Items.LunarPrimaryReplacement, 1); inventory.RemoveItemPermanent(Items.LunarSecondaryReplacement, 1); inventory.RemoveItemPermanent(Items.LunarSpecialReplacement, 1); inventory.RemoveItemPermanent(Items.LunarUtilityReplacement, 1); } break; case "DroneTechBody": Logger.LogMessage((object)"Removing drones from players swapping off Operator is work in progress"); break; } if (!(text2 == "CaptainBody")) { if (text2 == "HereticBody" && DropInConfig.GiveHereticItems.Value) { inventory.GiveItemPermanent(Items.LunarPrimaryReplacement, 1); inventory.GiveItemPermanent(Items.LunarSecondaryReplacement, 1); inventory.GiveItemPermanent(Items.LunarSpecialReplacement, 1); inventory.GiveItemPermanent(Items.LunarUtilityReplacement, 1); } } else if (!captainBlacklistInventories.Contains(inventory) || !DropInConfig.PreventCaptainScrapAbuse.Value) { inventory.GiveItemPermanent(Items.CaptainDefenseMatrix, 1); } } catch (Exception ex) { Debug.LogException(ex); Logger.LogError((object)ex); Logger.LogMessage((object)("Handling body items for transition from " + (text ?? "none") + " to " + (text2 ?? "none") + " resulted in an exception")); } } private static string Help(NetworkUser sender, string[] args) { if (args.Length > 1) { return "Help requires either 0 or 1 argument"; } if (args.Length == 1) { if (!_chatCommands.TryGetValue(args[0].ToUpperInvariant(), out var value)) { return "Unable to find command, try /help"; } return value.HelpText; } return "Availible Commands: " + string.Join(",", _chatCommands.Values.Select((ChatCommand command) => command.Name.ToLower())); } private static string JoinAs(NetworkUser sender, string[] args) { //IL_0040: 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_0056: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Invalid comparison between Unknown and I4 //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_00ab: Unknown result type (might be due to invalid IL or missing references) if (args.Length != 1 && args.Length != 2) { return "join as requires either 1 or 2 arguments"; } NetworkUser val = ((args.Length == 1) ? sender : GetNetUserFromString(args[1])); if ((Object)(object)val == (Object)null) { return "Unable to find player with given name"; } string text = args[0]; SurvivorDef availibleSurvivorForPlayerByName = GetAvailibleSurvivorForPlayerByName(val, text); BodyIndex val2 = (BodyIndex)(-1); string text2; if ((Object)(object)availibleSurvivorForPlayerByName != (Object)null) { val2 = BodyCatalog.FindBodyIndex(availibleSurvivorForPlayerByName.bodyPrefab); text2 = Language.GetString(availibleSurvivorForPlayerByName.displayNameToken); } else { if (!DropInConfig.AllowJoinAsAllBodies.Value) { return "Unable to find survivor with the name " + text + ". Try /list_survivors to see the available names"; } BodyIndex val3 = FindBodyIndexByName(text); if ((int)val3 == -1) { return "Unable to find survivor or body with given name"; } val2 = val3; text2 = BodyCatalog.GetBodyName(val3); } JoinAsResult joinAsResult; try { joinAsResult = SpawnPlayerWithBody(val, val2); } catch (Exception ex) { Debug.LogException(ex); Logger.LogError((object)ex); return "An exception occured spawning " + val.userName + " as " + text2; } return joinAsResult switch { JoinAsResult.Success => "Spawning " + val.userName + " as " + text2, JoinAsResult.DeadAndNotAllowRespawn => val.userName + " will be spawned as " + text2 + " next stage", _ => "Unknown join as result", }; } private static string ListSurvivors(NetworkUser sender, string[] args) { if (args.Length > 1) { return "list survivors requires 0 or 1 argument"; } NetworkUser val = ((args.Length == 0) ? sender : GetNetUserFromString(args[0])); if ((Object)(object)val == (Object)null) { return "Unable to find player with given name"; } return GetSurvivorChatListForPlayer(val); } private static string ListBodies(NetworkUser sender, string[] args) { if (args.Length != 0) { return "list bodies requires no arguments"; } return string.Join(", ", BodyCatalog.allBodyPrefabs.Select((GameObject prefab) => ((Object)prefab).name)); } private static string Transform(NetworkUser sender, string[] args) { if (args.Length > 2 || args.Length == 0) { return "transform requires 1 or 2 arguments"; } NetworkUser val = ((args.Length == 1) ? sender : GetNetUserFromString(args[1])); if ((Object)(object)val == (Object)null) { return "Unable to find player with given name"; } val.master.TransformBody(args[0]); return "Transformed " + sender.userName + " into " + args[0]; } private static string Catchup(NetworkUser sender, string[] args) { if (args.Length != 0 && args.Length != 1) { return "Catchup requires 0 or 1 argument"; } NetworkUser val = ((args.Length == 0) ? sender : GetNetUserFromString(args[0])); if ((Object)(object)val == (Object)null) { return "Unable to find player with given name"; } GiveCatchUpItems(val); return "Gave " + val.userName + " catch up items"; } private static string GiveRandomItems(NetworkUser sender, string[] args) { if (args.Length != 3 && args.Length != 4) { return "Give random items requires 3 or 4 arguments"; } NetworkUser val = ((args.Length == 3) ? sender : GetNetUserFromString(args[3])); if ((Object)(object)val == (Object)null) { return "Unable to find player with given name"; } object obj; if (val == null) { obj = null; } else { CharacterMaster master = val.master; obj = ((master != null) ? master.inventory : null); } if ((Object)obj == (Object)null) { return "Player has no inventory so cannot be given items"; } int num; bool lunarEnabled; bool voidEnabled; try { num = int.Parse(args[0]); lunarEnabled = bool.Parse(args[1]); voidEnabled = bool.Parse(args[2]); } catch { return "Unable to parse arguments"; } GiveRandomItems(val.master.inventory, num, lunarEnabled, voidEnabled); return $"Gave {val.userName} {num} random items"; } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CommandJoinAs(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Debug.Log((object)JoinAs(args.sender, args.userArgs.ToArray())); } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CommandShowSurvivors(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Debug.Log((object)ListSurvivors(args.sender, args.userArgs.ToArray())); } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CommandListBodies(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Debug.Log((object)ListBodies(args.sender, args.userArgs.ToArray())); } private static NetworkUser GetNetUserFromString(string playerString) { if (!string.IsNullOrWhiteSpace(playerString)) { if (int.TryParse(playerString, out var result)) { if (result < NetworkUser.readOnlyInstancesList.Count && result >= 0) { return NetworkUser.readOnlyInstancesList[result]; } return null; } foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { if (readOnlyInstances.userName.Replace(" ", "").Equals(playerString.Replace(" ", ""), StringComparison.InvariantCultureIgnoreCase)) { return readOnlyInstances; } } return null; } return null; } public static SurvivorDef[] GetAvailibleSurvivorsForPlayer(NetworkUser player) { return SurvivorCatalog.allSurvivorDefs.Where(SurvivorIsUnlockedAndAvailable).ToArray(); static bool SurvivorIsUnlockedAndAvailable(SurvivorDef survivorDef) { if (!DropInConfig.AllowJoinAsHiddenSurvivors.Value && survivorDef.hidden) { Logger.LogMessage((object)("Survivor " + survivorDef.cachedName + " is not availible because survivor is hidden and AllowJoinAsHiddenSurvivors is false")); return false; } return true; } } public static SurvivorDef GetAvailibleSurvivorForPlayerByName(NetworkUser player, string name) { SurvivorDef[] availibleSurvivorsForPlayer = GetAvailibleSurvivorsForPlayer(player); if (string.Equals(name, "random", StringComparison.InvariantCultureIgnoreCase)) { return availibleSurvivorsForPlayer[_rand.Next(availibleSurvivorsForPlayer.Length)]; } string normalizedName = SurvivorNameResolver.Normalize(name); return availibleSurvivorsForPlayer.Where(NameStringMatches).FirstOrDefault(); bool NameStringMatches(SurvivorDef survivorDef) { return SurvivorNameResolver.Matches(survivorDef, normalizedName); } } private static BodyIndex FindBodyIndexByName(string name) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) BodyIndex val = BodyCatalog.FindBodyIndexCaseInsensitive(name.EndsWith("Body", StringComparison.InvariantCultureIgnoreCase) ? name : (name + "Body")); if ((int)val != -1) { return val; } string text = SurvivorNameResolver.Normalize(name); if (text.EndsWith("body", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "body".Length); } if (text.Length != 0) { foreach (GameObject allBodyPrefab in BodyCatalog.allBodyPrefabs) { if (Object.op_Implicit((Object)(object)allBodyPrefab)) { string text2 = SurvivorNameResolver.Normalize(((Object)allBodyPrefab).name); if (text2.EndsWith("body", StringComparison.Ordinal)) { text2 = text2.Substring(0, text2.Length - "body".Length); } if (string.Equals(text2, text, StringComparison.Ordinal)) { return BodyCatalog.FindBodyIndex(allBodyPrefab); } } } return (BodyIndex)(-1); } return (BodyIndex)(-1); } private static void GiveCatchUpItems(NetworkUser player) { List<PickupIndex> list = new List<PickupIndex>(); list.AddRange(Run.instance.availableTier1DropList); list.AddRange(Run.instance.availableTier2DropList); list.AddRange(Run.instance.availableTier3DropList); list.AddRange(Run.instance.availableBossDropList); list.AddRange(Run.instance.availableVoidTier1DropList); list.AddRange(Run.instance.availableVoidTier2DropList); list.AddRange(Run.instance.availableVoidTier3DropList); list.AddRange(Run.instance.availableVoidBossDropList); list.AddRange(Run.instance.availableLunarItemDropList); Inventory[] source = (from netUser in NetworkUser.readOnlyInstancesList.Where(delegate(NetworkUser netUser) { if ((Object)(object)netUser != (Object)(object)player) { object obj; if (netUser == null) { obj = null; } else { CharacterMaster master = netUser.master; obj = ((master != null) ? master.inventory : null); } return (Object)obj != (Object)null; } return false; }) select netUser.master.inventory).ToArray(); ItemIndex[] countItemIndexes = list.Select((PickupIndex pickupIndex) => PickupCatalog.GetPickupDef(pickupIndex).itemIndex).ToArray(); int num = (int)((IEnumerable<Inventory>)source).Average((Func<Inventory, int>)CountInventoryItems); int num2 = num - CountInventoryItems(player.master.inventory); Logger.LogMessage((object)$"On average other players have {num} items, giving {player.userName} {num2} items to match"); GiveRandomItems(player.master.inventory, num2, DropInConfig.GiveCatchUpLunarItems.Value, DropInConfig.GiveCatchUpVoidItems.Value); int CountInventoryItems(Inventory inventory) { return countItemIndexes.Sum((ItemIndex itemIndex) => inventory.GetItemCountPermanent(itemIndex)); } } private static void GiveRandomItems(Inventory inventory, int count, bool lunarEnabled, bool voidEnabled) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) if (count <= 0) { return; } WeightedSelection<List<PickupIndex>> val = new WeightedSelection<List<PickupIndex>>(8); val.AddChoice(Run.instance.availableTier1DropList, 100f); val.AddChoice(Run.instance.availableTier2DropList, 60f); val.AddChoice(Run.instance.availableTier3DropList, 4f); if (lunarEnabled) { val.AddChoice(Run.instance.availableLunarItemDropList, 4f); } if (voidEnabled) { val.AddChoice(Run.instance.availableVoidTier1DropList, 4f); val.AddChoice(Run.instance.availableVoidTier2DropList, 2.3999999f); val.AddChoice(Run.instance.availableVoidTier3DropList, 0.16f); } for (int i = 0; i < count; i++) { try { List<PickupIndex> list = val.Evaluate(Random.value); PickupDef pickupDef = PickupCatalog.GetPickupDef(list.ElementAtOrDefault(Random.Range(0, list.Count))); ItemIndex val2 = (ItemIndex)((pickupDef == null) ? (-1) : ((int)pickupDef.itemIndex)); inventory.GiveItemPermanent(val2, 1); } catch (Exception ex) { Debug.LogException(ex); Logger.LogError((object)ex); Logger.LogMessage((object)"Exception occured giving player an item"); } } } private static Transform GetSpawnTransformForPlayer(NetworkUser player) { CharacterBody currentBody = player.GetCurrentBody(); Transform val = ((currentBody != null) ? ((Component)currentBody).transform : null); if ((Object)(object)val == (Object)null) { Logger.LogMessage((object)(player.userName + " does not have a current body, spawning on another player")); NetworkUser? obj = NetworkUser.readOnlyInstancesList.Where((NetworkUser user) => (Object)(object)user.GetCurrentBody() != (Object)null).FirstOrDefault(); val = ((obj != null) ? ((Component)obj.GetCurrentBody()).transform : null); } if ((Object)(object)val == (Object)null) { Logger.LogMessage((object)("Unable to find alive player for " + player.userName + " to spawn on, defaulting to map spawn")); val = Stage.instance.GetPlayerSpawnTransform(); } return val; } private static IEnumerator SpawnPlayerAsRandomInternal(NetworkUser player) { yield return (object)new WaitForSeconds(0.1f); SpawnPlayerWithBody(player, BodyCatalog.FindBodyIndex(GetAvailibleSurvivorForPlayerByName(player, "random").bodyPrefab)); } private static string GetSurvivorChatListForPlayer(NetworkUser player) { string[] value = (from survivor in GetAvailibleSurvivorsForPlayer(player) select survivor.cachedName + " (" + Language.GetString(survivor.displayNameToken) + ")").ToArray(); return string.Join(", ", value); } private static void GreetNewPlayer(NetworkUser player) { //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_0082: Expected O, but got Unknown if (DropInConfig.SendWelcomeMessage.Value) { string value = DropInConfig.CustomWelcomeMessage.Value; if (value.Length > 1000) { Logger.LogMessage((object)$"The custom welcome message has a length of {value.Length} which is longer than the limit of 1000 characters"); return; } string baseToken = value.ReplaceOnce("{username}", player.userName).ReplaceOnce("{survivorlist}", GetSurvivorChatListForPlayer(player)); Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage { baseToken = baseToken }); } } private static void SendChatMessage(string message) { ((MonoBehaviour)Instance).StartCoroutine(SendChatMessageInternal(message)); } private static IEnumerator SendChatMessageInternal(string message) { yield return (object)new WaitForSeconds(0.1f); Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage { baseToken = message }); } } } namespace DropInMultiplayer.Helpers { internal class BodyManager { private readonly Run _run; private readonly DropInMultiplayerConfig _config; private static Random _rand = new Random(); internal BodyManager(DropInMultiplayerConfig config, Run run) { _config = config; _run = run; } public SurvivorDef[] GetAvailibleSurvivorsForPlayer(NetworkUser player) { return SurvivorCatalog.allSurvivorDefs.Where(SurvivorIsUnlockedAndAvailable).ToArray(); bool SurvivorIsUnlockedAndAvailable(SurvivorDef survivorDef) { if (_config.AllowJoinAsHiddenSurvivors.Value || !survivorDef.hidden) { if (!survivorDef.CheckRequiredExpansionEnabled((NetworkUser)null)) { return false; } UnlockableDef unlockableDef = survivorDef.unlockableDef; if ((Object)(object)unlockableDef != (Object)null) { return _run.IsUnlockableUnlocked(unlockableDef); } return false; } return false; } } public SurvivorDef GetAvailibleSurvivorForPlayerByName(NetworkUser player, string name) { SurvivorDef[] availibleSurvivorsForPlayer = GetAvailibleSurvivorsForPlayer(player); if (string.Equals(name, "random", StringComparison.InvariantCultureIgnoreCase)) { return availibleSurvivorsForPlayer[_rand.Next(availibleSurvivorsForPlayer.Length)]; } return availibleSurvivorsForPlayer.Where(NameStringMatches).FirstOrDefault(); bool NameStringMatches(SurvivorDef survivorDef) { return SurvivorNameResolver.Matches(survivorDef, SurvivorNameResolver.Normalize(name)); } } } public static class HelperExtensions { public static void SetPrivateFieldValue(this object instance, string fieldName, object value) { instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(instance, value); } public static string ReplaceOnce(this string source, string replacetoken, string replacewith) { int num = source.IndexOf(replacetoken); if (num > -1) { return source.Substring(0, num) + replacewith + source.Substring(num + replacetoken.Length); } return source; } } internal static class SurvivorNameResolver { private static readonly Regex RichTextTagRegex = new Regex("<[^>]+>", RegexOptions.Compiled); private static readonly Dictionary<SurvivorDef, string[]> NameCache = new Dictionary<SurvivorDef, string[]>(); private static readonly Dictionary<string, string[]> ExtraAliases = new Dictionary<string, string[]> { { "engi", new string[1] { "engineer" } }, { "toolbot", new string[1] { "mult" } }, { "treebot", new string[1] { "rex" } }, { "voidsurvivor", new string[1] { "voidfiend" } }, { "dronetech", new string[1] { "operator" } }, { "enforcer2", new string[1] { "enforcer" } } }; internal static bool PreloadComplete { get; private set; } internal static string Normalize(string value) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } string text = RichTextTagRegex.Replace(value, string.Empty); string text2; try { text2 = text.Normalize(NormalizationForm.FormKC); } catch (ArgumentException) { text2 = text; } StringBuilder stringBuilder = new StringBuilder(text2.Length); string text3 = text2; foreach (char c in text3) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } internal static bool Matches(SurvivorDef survivorDef, string normalizedQuery) { if ((Object)(object)survivorDef == (Object)null || string.IsNullOrEmpty(normalizedQuery)) { return false; } return GetNames(survivorDef).Contains(normalizedQuery); } internal static IEnumerator PreloadLanguageStrings() { while (!Language.GetAllLanguages().Any()) { yield return null; } Language[] array = Language.GetAllLanguages().ToArray(); foreach (Language val in array) { if (val != null && !val.stringsLoaded) { try { val.LoadStrings(); } catch (Exception arg) { Debug.LogWarning((object)$"DropInMultiplayer: failed to preload language {val.name}: {arg}"); } yield return null; } } PreloadComplete = true; } private static string[] GetNames(SurvivorDef survivorDef) { if (NameCache.TryGetValue(survivorDef, out var value)) { return value; } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); AddName(hashSet, survivorDef.cachedName); GameObject bodyPrefab = survivorDef.bodyPrefab; if (Object.op_Implicit((Object)(object)bodyPrefab)) { AddName(hashSet, ((Object)bodyPrefab).name); if (((Object)bodyPrefab).name.EndsWith("Body", StringComparison.OrdinalIgnoreCase)) { AddName(hashSet, ((Object)bodyPrefab).name.Substring(0, ((Object)bodyPrefab).name.Length - "Body".Length)); } } string displayNameToken = survivorDef.displayNameToken; if (!string.IsNullOrEmpty(displayNameToken)) { AddName(hashSet, Language.GetString(displayNameToken)); AddName(hashSet, Language.GetString(displayNameToken, "en")); foreach (Language allLanguage in Language.GetAllLanguages()) { if (allLanguage != null && !string.IsNullOrEmpty(allLanguage.name)) { AddName(hashSet, Language.GetString(displayNameToken, allLanguage.name)); } } } if (ExtraAliases.TryGetValue(Normalize(survivorDef.cachedName), out var value2)) { string[] array = value2; foreach (string value3 in array) { AddName(hashSet, value3); } } string[] array2 = hashSet.ToArray(); if (PreloadComplete) { NameCache[survivorDef] = array2; } return array2; } private static void AddName(HashSet<string> names, string value) { string text = Normalize(value); if (text.Length > 0) { names.Add(text); } } } }